Інтеграція Siri або «Ось що мені вдалося знайти в вашому додатку»



На WWDC 2016 Apple представила світу SiriKit — API для роботи з голосовим помічником.

Якщо ви не дивилися WWDC сесію про SiriKit і чекаєте, що зможете використовувати Siri в будь-якому додатку, то вам варто знати, що на даний момент підтримується всього декілька типів сервісів:

1) Аудіо і відео виклики,
2) Повідомлення,
2) Платежі,
3) Пошук фото,
4) Тренування,
5) Поїздки (бронювання).

Також, як свідчить документація, існують можливість взаємодії з автомобілем за допомогою CarPlay (INSetClimateSettingsInCarIntent, INSetSeatTemperatureInCarIntent, etc.).

Таким чином, Siri можна дати команду "<подзвони того, відправ повідомлення, пошукай фото, etc.> через <назву вашої програми>".
Все влаштовано таким чином, що взаємодіяти безпосередньо з нейромережею не доведеться — SDK надає прості протоколи і набір легковагих класів для передачі інформації в методах. Розробнику залишається тільки реалізувати ці протоколи.

Для ледачих в кінці статті посилання на демо-додаток (відправляємо з допомогою Siri повідомлення своїм друзям з ВК).

Наріжний камінь SiriKit — Intent (android-розробники, привіт!). Об'єкт класу INIntent (або його спадкоємців) — це вхідні дані, які генерує Siri. Сам INIntent не містить в собі нічого крім ідентифікатора. Роль контексту делегована його сабклассам. Конкретний сабкласс залежить від типу програми. Наприклад, для програми з тренуваннями INStartWorkoutIntent містить інформацію про цілі — скільки часу потрібно провести за тим чи іншим вправою, де відбувається тренування і так далі. Для фото сервісу можна використовувати интент INSearchForPhotosIntent, в якому міститься геотеги (CLPlacemark), дата створення фото, список людей на фото і т. д.

Для обробки вхідного интента розробнику знадобиться створювати об'єкти класу INIntentResolutionResult (або його сабклассов).

Існує три стадії обробки вхідної інформації:

  • уточнення (resolve),
  • підтвердження (confirm),
  • виконання дії (handle).
На кожній з цих стадій ми отримуємо интент і повинні повертати відповідний INIntentResolutionResult.

Наприклад, якщо ми розробляємо програму-меседжер, то на стадії уточнення ми однозначно визначаємо користувачів, яким ми відправляємо повідомлення (resolveRecipientsForSendMessage), вміст повідомлення (resolveContentForSendMessage). На стадії підтвердження ми перевіряємо (confirmSendMessage), що все готово для надсилання (наприклад, авторизований користувач). І нарешті, на стадії виконання (handleSendMessage), ми відправляємо повідомлення обраним адресатам.

На будь-якому етапі є два варіанти розвитку сценарію: позитивний і негативний. Вибір шляху делегований розробнику: Siri надає оброблені дані у вигляді об'єкта интента, а який результат повернути системі вирішує програміст.

Intents Extension
Щоб ваш додаток підтримувало роботу з Siri знадобиться додати в InfoPlist ключ NSSiriUsageDescription з текстом, поясняющим кінцевому користувачеві, навіщо вашому додатком доступ до Siri (за аналогією з NSLocationUsageDescription для геолокації).



І запросити permission:

[INPreferences requestSiriAuthorization:^(INSiriAuthorizationStatus status) {
}];

Після цього потрібно додати в проект таргет з типом IntentsExtension.



Після додавання таргету, зверніть увагу на його структуру. Вхідна точка для интентов — об'єкт класу INExtension. Всередині екземпляра класу в методі (handlerForIntent) вибирається якийсь об'єкт буде обробляти вхідний интент. У InfoPlist таргету прописуються назва класу-спадкоємця INExtension і підтримувані типи интентов. Також можна вказати, які з типів интентов будуть недоступні на заблокованому екрані.



Для обробки конкретного типу интента потрібно реалізувати спеціалізований протокол у вашому класі (наприклад, INSendMessageIntentHandling). Протокол містить у собі методи, необхідні для проходження вищеописаних етапів (resolve, confirm, handle).

Розглянемо реалізацію класу обробника для интента надсилання повідомлення.

Як було описано вище, на першому етапі (уточнення) потрібно однозначно визначити користувачів і вміст повідомлення. Якщо говорити про вміст повідомлення, то в більшості випадків достатньо знати, що воно не порожнє. Але з адресатами не все так просто. У интенте ми можемо отримати список користувачів, яких розпізнала Siri. Це масив об'єктів класу INPerson. Для кожного адресата необхідно знайти відповідність до списку поточних адресатів.

Існує три варіанти розвитку подій:

  • відповідності немає — негативний сценарій;
  • одне відповідність — однозначність підтверджена;
  • більше одного відповідності — потрібно надати користувачеві можливість вибрати правильний контакт зі списку (INPersonResolutionResult -> disambiguationWithPeopleToDisambiguate).
Примітка — після вибору користувача в разі disambiguation, повторно буде виконаний метод resolveRecipientsForSendMessage. При перевірці збігу користувачів потрібно враховувати, що метод може бути викликаний кілька разів.

На етапі підтвердження ми перевіряємо необхідні умови для можливості відправки повідомлення. І нарешті, в методі handleSendMessage (фінальна стадія) надсилання повідомлення. На кожному з етапів є позитивний і негативний сценарій роботи.

Siri не завжди розуміє, що ми хочемо сказати. Щоб їй допомогти, можна використовувати Vocabulary — словник термінів. Вони бувають двох видів: статичні і динамічні. У першому випадку ми надаємо спеціальний AppIntentVocabulary.plist, в якому записані загальні терміни. Динамічний словник заповнюється спеціалізованими термінами для поточного користувача:

[[INVocabulary sharedVocabulary] setVocabularyStrings:[usersNames copy] ofType:INVocabularyStringTypeContactName];

За словник відповідає не Intent Extension, а основне додаток. Тобто свої додаткові терміни потрібно вказати до запуску розширення Siri.

Intents UI Extension
Крім логіки обробки даних, SiriKit надає можливість змінити інтерфейс відображення даних. Для цього існує Intents UI Extension. За аналогією з Intents Extension, InfoPlist UI-таргета містить у собі список підтримуваних интентов, а також назва storyboard-файлу.



Примітка — для будь-якого интента у UI-розширення буде створений один і той же контролер (entry point в storyboard). Для делегування логіки відображення рекомендується використовувати дочірні контролери (child view controllers). Базовий контролер повинен підтримувати протокол INUIHostedViewControlling, в якому визначений метод конфігурування інтерфейсу — configureWithInteraction. Розглянемо параметри цього методу.

  • interaction (INInteraction) містить интент і статус його обробки. По класу переданого интента ми можемо инстанцировать відповідний контролер;
  • context (INUIHostedViewContext) дозволяє визначити, чи використовуєте Siri безпосередньо, або ж задіюються Maps;
  • completion (блок завершення), в який потрібно передати розмір (CGSize) відображається контролера (фрагменту). Розмір обмежений мінімумом (hostedViewMinimumAllowedSize) і максимумом (hostedViewMaximumAllowedSize), значення яких визначені системою в категорії NSExtensionContext (INUIHostedViewControlling).
Крім основного протоколу INUIHostedViewControlling, існує додатковий протокол INUIHostedViewSiriProviding, який дозволяє контролювати відображення стандартних інтерфейсів Siri для повідомлень (displaysMessage) і карт (displaysMap). У вимогах Apple щодо створення інтерфейсів для Siri є заборона на показ у фрагментах реклами. Якщо ви плануєте використовувати анімацію, то рекомендується виконувати її у viewDidAppear.

Для передачі даних між основним додатком і экстеншенами як і раніше потрібно використовувати Application groups (приклад в демо).

Скріншоти




Посилання
SiriKit Programming Guide
Демо-додаток
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.