[iOS 10] Встраиваем поддержку Siri в свое iOS приложение
Apple показала на WWDC 2016 новые iOS 10 и macOS Sierra, и я не упустил возможность сразу же обновить свои устройста.
Одно из ключевых обновлений — появление SiriKit для разработчиков, теперь у нас с вами есть возможность использовать Siri в собственных приложениях. И мы сегодня сделаем наше первое приложение с поддержкой Siri (исходники проекта в конце статьи)
(!) Уважаемые читатели «Хабрахабра», все ошибки и правки по данной статье присылайте, пожалуйста, в личные сообщения.
Мои впечатления от iOS 10 и macOS
В новой macOS появилась Siri — это сразу бросается в глаза, с новыми функциями. Наконец-то заработал обмен ссылками между iOS и macOS — как только открываешь страницу на iPhone/iPad — сразу появляется на mac значек Safari, открывающий эту страницу (Раньше эта функция работала через раз). Ну и конечно очень круто — что копируя текст на iOS — его можно вставить на macOS. С картинками и фото тоже самое — один клик на iPhone, и фото уже на ноутбуке, больше не нужно мэйлить фото самому себе. По умолчанию включается на macOS телеметрия, которую я сразу отключил (скрин). Из минусов iOS 10 — действительно тормозная, иногда (не всегда) на iPhone 5S и iPad Air подтормаживает скролл, но в целом, интерфейс выглядит более стильно, контрастнее, изменения UI незначительные, но в целом «более стильно и минималистично» :) В плане UI дизайна так же стоит отметить обновленные формочки для IN-APP уведомлений.
Apple предлагает несколько сценариев для использования Siri сторонними разработчиками:
- Аудио и видео звонки
- Работа с сообщениями и контактами
- Совершение платежей с помощью Siri
- Поиск фотографий
- Тренировки
- Работа с картами (Вызов такси)
В данной статье я покажу, как создавать StoryBoard интерфейс для Siri и вызывать наши функции с помощью голосового помощника.
Для начала скачиваем и устанавливаем Xcode 8 и создаем новое приложение с одним ViewController и называем его, например «DemoApp».
Для добавления голосовой поддержки нам придется добавить новое расширение, для этого выбираем в левой панели файлового менеджера верхнюю строчку (файл проекта) и выбираем в меню Editor → Add target…
Назовем наше расширение «DemoAppSiriIntent», так же не забываем проверить наличие галочки напротив «Include UI Extension»
Так же для работы Siri нам необходимо добавить в проект библиотеку CoreLocation.framework
У нас в проекте появились новые файлы
- IntentHandler.m — файл с CallBack функциями, которые возвращает Siri
- IntentViewController.m — файл для работы с StoryBoard интерфейсом, который расположен рядом, в файле MainInterface.storyboard
Для начала мы научим наше приложение запускать «Фитнес активность» (Workout), для этого в файле IntentHandler.m должны быть объявленны следущие Delegates:
@interface IntentHandler ()
@end
Для обозначения методов взаимодействия с Siri Apple использует слово «Intent», теперь, зажимая клавишу CMD, кликаем на «INStartWorkoutIntentHandling» и смотрим, какие функции использует данный deligate.
Обязательный для включения в проект метод:
- handleStartWorkout
Дополнительные методы, которые можно не включать в проект:
- confirmStartWorkout
- resolveWorkoutNameForStartWorkout
- resolveGoalValueForStartWorkout
- resolveWorkoutGoalUnitTypeForStartWorkout
- resolveWorkoutLocationTypeForStartWorkout
- resolveIsOpenEndedForStartWorkout
Медод «confirmStartWorkout» вызывает по порядку следущие Callback функции, которые уже автоматически созданы в нашем файле «IntentHandler.m»:
- resolveWorkoutNameForStartWorkout
- resolveGoalValueForStartWorkout
- DemoAppSiriIntent
- resolveWorkoutLocationTypeForStartWorkout
- resolveIsOpenEndedForStartWorkout
- confirmStartWorkout
- handleStartWorkout
Рядом с файлом «IntentHandler.m» мы видим plist с настройками нашего «Intent» расширения, «Info.plist».
Проверяем, что в ветке »NSExtension → NSExtensionAttributes → IntentsSupported» перечислены все наши Intents для работы с Siri Workout:
- Item 0: INStartWorkoutIntent
- Item 1: INPauseWorkoutIntent
- Item 2: INResumeWorkoutIntent
- Item 3: INCancelWorkoutIntent
- Item 4: INEndWorkoutIntent
Если мы продублируем данные «Intents» в ветку »NSExtension → NSExtensionAttributes → IntentsRestrictedWhileLocked», то Siri сможет вызывать функции из нашего приложения даже с заблокированного устройства.
Теперь переходим к файлу «MainInterface.storyboard» и для демо приложения добавляем на него два UILabel, один из них будет счетчиком, для демонстрации того, что наш UI интерфейс внутри Siri может обновляться в реальном времени.
Важно отметить, что данный интерфейс не может содержать «gesture recognizers» и перехватчики событий нажатия пальцами и, при закрытии данного окна, Siri освободит все объекты в памяти.
На следующей схеме мы можем ознакомиться с жизненным циклом нашего «Siri view интерфейса».
Итак, самое время скомпилировать наше приложение и проверить, работают ли голосовые команды. Тестировать данный пример получится только на реальном устройстве, для начала собираем приложение как обычно:
Затем нажимаем на Stop и отдельно компилируем наше расширение, выбрав схему «DemoAppSiriIntent». Во время компиляции Xcode спросит нас, для какого приложения мы собираем данное расширение, и в списке мы указываем «DemoApp».
На этом этапе мы увидим, что наше приложение появляется на секунду и тут же исчезает, это не «вылет», всё функции вывода NSLog из файла «IntentHandler.m» показывают нам, что все работает.
Ах да, чуть не зыбыл, в настройках нашего iOS девайса заходим в раздел Siri и устанавливаем галочку напротив нашей программы «DemoApp»:
Итак, самое время произнести вслух «Hey, Siri, start workout in DemoApp»
Результат вы можете наблюдать на данном видео:
Теперь мы убедились, что все работает, давайте добавим поддержку сообщений в наше приложение.
Перейдя по данной ссылке, вы можете ознакомиться со всеми «Intent» методами, которые поддерживаются в данный момент Siri:
https://developer.apple.com/…
Сейчас нас интересует секция «Messaging», открываем наш «IntentHandler.m» файл, прописываем delegate для сообщений:
@interface IntentHandler ()
Удерживая зажатой CMD — кликаем на «INSendMessageIntentHandling» и видим, что необходимой функцией в этот раз является «handleSendMessage». Для начала присваиваем «Intent» для сообщений в функции «handlerForIntent»:
- (id)handlerForIntent:(INIntent *)intent {
id handler = nil;
if ([intent isKindOfClass:[INSendMessageIntent class]]) {
handler = self;
}
handler = self;
return handler;
}
И затем пишем callback функцию для нашего «Intent»:
- (void)handleSendMessage:(INSendMessageIntent *)intent completion:(void (^)(INSendMessageIntentResponse * _Nonnull))completion {
NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass([INSendMessageIntent class])];
INSendMessageIntentResponse *response = [[INSendMessageIntentResponse alloc] initWithCode:
INSendMessageIntentResponseCodeSuccess userActivity:userActivity];
NSLog(@"handleSendMessage");
completion(response);
}
Не забываем прописать наш новый «Intent» в plist.info, в ветку »NSExtension → NSExtensionAttributes → IntentsSupported»:
Вот и все, данную статью я написал в очень сжатые строки, но если вам интересна данная тема, дайте знать в комментариях, я могу написать более расширенную публикацию, включающую такие нюансы, как локализация команд Siri в нашем приложении, работа с картами, составление синонимов для голосовых фраз и обучающие фразы для Siri, ну и конечно же проблемы бета версии Xcode 8.
Исходные файлы проекта из данной статьи вы можете скачать по ссылке:
http://big-lab.com/images/articles/sirikit/DemoApp.zip