Подтвердить что ты не робот

Как обычная клавиатура iOS от Google, Gboard, программно отклоняет самое ближайшее приложение?

Пользовательское приложение iOS от Google, Gboard, имеет интересную функцию, которая не может быть выполнена с использованием общедоступных API-интерфейсов в SDK для iOS ( с IOS 10). Я хотел бы точно знать, как Google выполняет задачу по программному возврату одного приложения в стек переключения приложений в Gboard.

Пользовательские клавиатуры iOS имеют два основных компонента: контейнерное приложение и расширение для клавиатуры. Расширение приложения для клавиатуры запускается в отдельном процессе ОС, который запускается всякий раз, когда пользователь находится в любом приложении на своем телефоне, которое требует ввода текста.

Это приблизительные шаги, которые можно выполнить, используя Gboard, чтобы увидеть эффект программного возврата в предыдущее приложение:

  • Пользователь запускает приложение Apple Messages на своем iPhone и отбирает текстовое поле, чтобы начать ввод текста.
  • Открывается расширение клавиатуры Gboard, и пользователи видят специальную клавиатуру Gboard (пока они все еще находятся в приложении Apple Messages).
  • Пользователь вводит ключ микрофона внутри расширения клавиатуры Gboard для ввода текста в речь.
  • Gboard использует настраиваемую схему URL для запуска приложения-контейнера Gboard. Клавиатура Gboard и приложение Apple отправляются на один уровень в стек приложения, а приложение контейнера Gboard теперь является самым передним приложением в стеке приложений. Приложение контейнера Gboard использует микрофон для прослушивания речи пользователя и переводит его в текст, который он помещает на экран.
  • Пользователь нажимает кнопку "Готово", когда их удовлетворяет ввод текста, который они видят на экране.
  • Здесь происходит волшебство... при отключении экрана ввода текста приложение-контейнер Gboard также автоматически отбрасывается. Приложение контейнера Gboard уходит и заменяется приложением Apple Messages (иногда процесс расширения клавиатуры Gboard все еще жив, иногда он перезагружается, а иногда его нужно перезапустить вручную, нажав внутри текстового поля.). Как Google выполняет это?
  • Наконец, пользователь видит текст, который был просто переведен автоматически вставлен в поле ввода текста. Предположительно Google выполняет это посредством обмена данными между приложением контейнера Gboard и расширением клавиатуры.

Я бы предположил, что Google использует частные API-интерфейсы, исследуя иерархию представлений строки состояния, используя Objective-C интроспекцию времени выполнения и как-то синтезируя события крана или вызывая открытый объект/действие. Я изучил это очень мало и смог найти интересные подклассы UIView внутри строки состояния, например UIStatusBarBreadcrumbItemView, который содержит массив UISystemNavigationAction s. Я продолжаю изучать эти классы в надежде, что смогу найти способ репликации взаимодействия с пользователем.

Я понимаю, что использование частных API-интерфейсов - это хороший способ, чтобы ваше приложение отклонялось из App Store - это не проблема, о которой я бы хотел ответить в ответ. Я смотрю в первую очередь на конкретные ответы о том, как именно Google выполняет задачу по программному возврату одного приложения в стек переключения приложений в Gboard.

4b9b3361

Ответ 1

Ваша догадка правильная - Gboard использует частный API для этого.

... хотя и не путем изучения иерархии представлений или вставки событий.

Когда действие "голос-текст" выполняется, мы можем проверить syslog из Xcode или Console, который вызывает метод -[AVAudioSession setActive:withOptions:error:]. Поэтому я обратил свое внимание на приложение Gboard и искал трассировку стека, связанную с этим.

Поднимая стек вызовов, мы можем найти метод -[GKBVoiceRecognitionViewController navigateBackToPreviousApp] и...

введите описание изображения здесь

... _systemNavigationAction? Да, определенно частный API.

Так как class_getInstanceVariable является общедоступным API, а "_systemNavigationAction" является строковым литералом, автоматическая проверка не может заметить использование частного API, и, по мнению экспертов, люди не видят ничего плохого в "прыжке назад" предыдущее приложение "поведение. Или, вероятно, потому, что они Google, а вы не...


Фактический код, который выполняет действие "вернуться к предыдущему приложению", выглядит следующим образом:

@import UIKit;
@import ObjectiveC.runtime;

@interface UISystemNavigationAction : NSObject
@property(nonatomic, readonly, nonnull) NSArray<NSNumber*>* destinations;
-(BOOL)sendResponseForDestination:(NSUInteger)destination;
@end

inline BOOL jumpBackToPreviousApp() {
    Ivar sysNavIvar = class_getInstanceVariable(UIApplication.class, "_systemNavigationAction");
    UIApplication* app = UIApplication.sharedApplication;
    UISystemNavigationAction* action = object_getIvar(app, sysNavIvar);
    if (!action) {
        return NO;
    }
    NSUInteger destination = action.destinations.firstObject.unsignedIntegerValue;
    return [action sendResponseForDestination:destination];
}

В частности, метод -sendResponseForDestination: выполняет фактическое действие "вернуться".

(Так как API недокументирован, Gboard фактически использует API неправильно. Они использовали неправильную подпись -(void)sendResponseForDestination:(id)destination. Но бывает, что все числа, отличные от 1, будут работать одинаково, поэтому разработчикам Google повезло времени)