Розробка інтеграції Siri Shortcuts для iOS-додатку
Siri Shortcuts дозволяє користувачам запускати дії вашого додатку голосом або через автоматизації в додатку Shortcuts. З iOS 16 та App Intents framework це стало значно простіше — і одночасно з'явилися нові можливості, які сломали старий NSUserActivity/Intent підхід.
App Intents vs SiriKit Intents: що вибрати
До iOS 16 — SiriKit з .intentdefinition файлом, кодогенерацією та INExtension. Складно, багато шаблонного коду.
З iOS 16 — AppIntents framework. Структура, яка реалізує AppIntent, автоматично доступна Siri, Spotlight та додатку Shortcuts. Жодних extension targets, жодної кодогенерації.
struct OrderCoffeeIntent: AppIntent {
static var title: LocalizedStringResource = "Замовити кавуИ"
static var description = IntentDescription("Створює замовлення в додатку")
@Parameter(title: "Напиток", default: "Еспресо")
var drinkName: String
func perform() async throws -> some IntentResult & ProvidesDialog {
let order = try await CoffeeService.shared.placeOrder(drink: drinkName)
return .result(dialog: "Замовлення \(drinkName) прийнято, номер \(order.id)")
}
}
Цей Intent одразу з'являється в Siri, Spotlight та додатку Shortcuts. Без додаткової реєстрації.
Параметри та Entity
Якщо параметр — не проста рядок, а сутність з вашого додатку (продукт, контакт, маршрут), потрібен AppEntity. Він дозволяє Siri запитувати в користувача уточнення через діалог.
struct CoffeeItem: AppEntity {
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Напиток")
static var defaultQuery = CoffeeItemQuery()
var id: String
var displayRepresentation: DisplayRepresentation { .init(title: "\(name)") }
var name: String
}
AppEntityQuery з методом entities(matching:) — дозволяє Siri шукати сутності за текстом. Користувач каже «Замовити великий капучино» — Siri запитує в додатку список капучино й пропонує вибрати.
Помилки, які ломають Siri інтеграцію
perform() викидає помилку без обробки. Якщо perform() throws, Siri показує дефолтне сообщение «Щось пішло не так» без деталей. Правильно: кидати AppIntentError з кастомним повідомленням або повертати result(dialog:) з описом помилки.
Довге виконання без зворотного зв'язку. perform() повинен завершитися за розумний час (до 30 секунд). Для довгих операцій — проміжний діалог через requestConfirmation(). Без нього Siri просто зависає в очікуванні з крутящимся індикатором.
Втрата авторизації в Extension. INExtension (старий підхід) працює в окремому процесі. Якщо авторизаційний токен зберігається в Keychain без kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlock, Extension не отримає доступ коли телефон заблокований. App Intents виконуються в процесі основного додатку — ця проблема менш гострова, але Keychain access group все равно потрібно налаштовувати.
App Shortcuts (Siri Tips)
З iOS 16.4 можна визначити AppShortcutsProvider — готові фрази, які одразу працюють без настройки користувачем:
struct CoffeeAppShortcuts: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: OrderCoffeeIntent(),
phrases: ["Замовити каву в \(.applicationName)", "Хочу каву в \(.applicationName)"],
shortTitle: "Замовлення кави",
systemImageName: "cup.and.saucer"
)
}
}
Фраза \(.applicationName) обов'язкова — без імені додатку в фразі Siri не зможе однозначно маршрутизувати команду. Apple перевіряє це на ревью.
Тестування
Simulator + Siri працює тільки з реального голосу або через XCTest з INUIAddVoiceShortcutButton. Краще тестувати на реальному пристрої. Для App Intents: Settings → Siri & Search → [додаток] показує зареєстровані інтенти.
Розклад
Базова інтеграція 2–3 App Intents без Entity: 2–4 тижні. Повна інтеграція з AppEntity, App Shortcuts, кастомними діалогами: 5–8 тижнів. Міграція зі старого SiriKit на App Intents: 3–6 тижнів залежно від обсягу. Вартість розраховується після аудиту існуючої інтеграції.







