SiriKitを試す
2016年 07月 11日
SiriKitができること
iOS10からSiriからアプリを操作できるようになります。
なので例えば、
といったフレーズでSiriを使えたらいいなと思いますが、
残念なことに現段階では以下の6つのDomainに関連したフレーズでないとこの機能は使えないようです。
- Audio or video calling
- Messaging
- Payments
- Searching photos
- Workouts
- Ride booking
それぞれのDomainにいくつかIntent(アクション)がClassで定義されています。
Intents Domains


上記のセッションでも説明している通り、Siriは音声データをテキストデータに変換した後に、テキストデータからDomain, Intent, 各Intent固有のパラメーターを読み取る必要があります。
単に読み取ると言っても、ひとつのIntentを表現するフレーズでも何通りもあり、さらにそれを全ての言語に対応させなければならないのが非常に大変そうなので、少しずつ対応Domainを増やしていくしかないだろうなと思います。
Siriの処理の流れ

Intentが、受け取ったテキストデータを処理するフェーズはResolve, Confirm, Handleの3つがあります。
Resolve
後の処理に必要なパラメーターをチェックするフェーズです。それぞれのIntentに含まれるパラメーターごとに用意されたResolveメソッドの返り値を調整することで、必須パラメーターのチェックや曖昧性の排除などをSiriが対話的に行ってくれ、以下のようなものがあります。
success
confirmationRequired

disambiguation

needsValue

Confirm

ユーザーから適切なパラメーターを受け取った後の最終確認フェーズです。
ここのビューは独自に実装することができます。
Handle

アプリ内で決済やメッセージ送信の処理を行うフェーズです。
処理中の場合はスピナーを表示させたり、正常に処理が終了した時はそれがわかるUIにすることが大切です。
Siri上で処理を完結させずに、NSUserActivityを使って情報をアプリに渡して遷移させることも可能です。
SiriKitを試してみる
今回は、弊社のiOSアプリの 寝たまんまヨガ をSiriからハンドリングできるかどうか試してみました。
寝たまんまヨガは、リラクゼーションや瞑想などのいろいろなヨガのプログラムを楽しめるアプリです。
以下のフレーズでSiriからインテントハンドリングしたいと思います。
フレーズ | 寝たまんまヨガでディープリラクゼーションを開始 |
---|---|
Domain | Workouts |
Intent | INStartWorkoutIntent |
App | 寝たまんまヨガ |
workoutName | ディープリラクゼーション |
これでうまくいくとよかったですが、残念ながら、色々と試してみたところまだWorkoutsドメインの日本語対応が不十分なのか、日本語のフレーズではWorkoutsのインテントハンドリングをすることができませんでした。。少し残念でしたが、英語でのハンドリングには成功したので、以下にそれについてまとめてみました。ここではアプリの英語名を「Excite Yoga」にしています。
フレーズ | Start the Deep Relaxation with Excite Yoga |
---|---|
Domain | Workouts |
Intent | INStartWorkoutIntent |
App | Excite Yoga |
workoutName | Deep Relaxation |
Intents Extensionを追加する
SiriKitを使うためには、Intents Extensionを既存のアプリに追加します。
追加されたExtensionのInfo.plistのIntentsSupported内にサポートするIntentのクラス名を追加します。
<key>IntentsSupported</key>
<array>
<string>INStartWorkoutIntent</string>
</array>
Siriからの使用を許可するアラートを表示させる
Intents Extensionを有効にするためには、ユーザーからの許可が必要なのでそのためのアラートを任意のタイミングで表示させます。
INPreferences.requestSiriAuthorization { status in }
アプリの方のInfo.plistのNSSiriUsageDescriptionにアラートに含める説明文を追加します。
<key>NSSiriUsageDescription</key>
<string>説明文を追加</string>
独自の語彙を追加する
SiriKitにはアプリ独自の語彙を追加する機能があります。
App Vocabulary File Format
今回はSiriがDeep RelaxationをworkoutNameとして認識するように設定しました。
Intent Phrasesに例文を追加すると、Siriのアプリごとの使い方画面にそれが表示されます。
AppIntentVocabulary.plistファイルをアプリに追加します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ParameterVocabularies</key>
<array>
<dict>
<key>ParameterNames</key>
<array>
<string>INStartWorkoutIntent.workoutName</string>
</array>
<key>ParameterVocabulary</key>
<array>
<dict>
<key>VocabularyItemIdentifier</key>
<string>deep_relaxation</string>
<key>VocabularyItemSynonyms</key>
<array>
<dict>
<key>VocabularyItemPhrase</key>
<string>Deep Relaxation</string>
<key>VocabularyItemPronunciation</key>
<string>deep relaxation</string>
<key>VocabularyItemExamples</key>
<array>
<string>Start the deep relaxation with Excite Yoga</string>
</array>
</dict>
</array>
</dict>
</array>
</dict>
</array>
<key>IntentPhrases</key>
<array>
<dict>
<key>IntentName</key>
<string>INStartWorkoutIntent</string>
<key>IntentExamples</key>
<array>
<string>Start the deep relaxation with Excite Yoga</string>
</array>
</dict>
</array>
</dict>
</plist>
Intent Handler の実装
今回はSiriがworkoutNameを聞き取れなかった場合は、あらかじめ定義した選択肢から選択させるようにresolve部分を実装しました。
workoutの配列を宣言
let workoutNames = [
"Deep Relaxation",
"Chakra Mediation",
"Prana Relaxation",
"Natures Grace",
"Forest Walk"
]
Intentごとに定義されているプロトコルメソッドを実装します。
INStartWorkoutIntentにはINStartWorkoutIntentHandlingプロトコルが定義されています。
resolveメソッド
func resolveWorkoutName(forStartWorkout intent: INStartWorkoutIntent, with completion: (INStringResolutionResult) -> Void) {
guard let workoutName = intent.workoutName where workoutNames.contains(workoutName) else {
completion(INStringResolutionResult.disambiguation(with: workoutNames))
return
}
completion(INStringResolutionResult.success(with: workoutName))
}
該当するworkoutNameでない場合は、 .disambiguationを返すとSiriがユーザーに選択肢を提示してくれます。
handleメソッド
func handle(startWorkout startWorkoutIntent: INStartWorkoutIntent, completion: (INStartWorkoutIntentResponse) -> Void) {
guard let workoutName = startWorkoutIntent.workoutName else {
completion(INStartWorkoutIntentResponse(code: .failure, userActivity: nil))
return
}
let userActivity = NSUserActivity(activityType: String(INStartWorkoutIntent))
userActivity.userInfo = ["workoutName": workoutName]
completion(INStartWorkoutIntentResponse(code: .success, userActivity: userActivity))
}
ここでNSUserActivityに設定した情報は、UIApplicationDelegateの
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: ([AnyObject]?)
メソッド内で受け取ることができます。
テスト
これで実装が終わったので実際に使ってみます。
まずはworkoutNameは言わずに、
Start something with Excite Yoga
と試してみると、
Which one?
---
Deep Relaxation
Chakra Mediation
Prana Relaxation
Natures Grace
Forest Walk
と、disambiguationで設定したリストを表示してくれました。
ここで、
Deep Relaxation
と答えると、handleメソッドが実行された後にアプリが起動しました。
ここでuserActivityをみてみると、
(lldb) p userActivity.userInfo
([NSObject : AnyObject]?) $R0 = 1 key/value pair {
[0] = {
key = 0xe0000000170032820 "workoutName"
value = 0x0000000170055750 "Deep Relaxation"
}
}
という具合に、しっかりアプリ内でworkoutNameを受け取れています。
次はworkoutNameを省略せずに、
Start the Deep Relaxation with Excite Yoga
と試したところ一発でアプリが起動しました。
まとめ
今回はSiriKitを使って、寝たまんまヨガをWorkoutsドメインでインテントハンドリングする例を紹介しました。
日本語でインテントハンドリングすることができなくて残念でしたが、対応している言語であれば、その言語にローカライズされたAppIntentVocabularyファイルを追加するだけで多言語対応できそうです。
さらにIntents UI Extensionを追加すれば、カスタムUIをSiri上で表示することができるのでアプリに遷移することなく処理を完結させることもできます。Providing a Custom Interface
まだ対応ドメインが6つだけと少ないですが、ユーザビリティ向上のために実装しておきたい機能だと思いました。
参考
Session
Introducing SiriKit
Extending Your Apps with SiriKit
ドキュメント
SiriKit Programming Guide
Intents Domains
App Vocabulary File Format
Providing a Custom Interface