良い Siri ショートカットの作り方

WWDC19の動画、[Building Great Shortcuts](https://developer.apple.com/videos/play/wwdc2019/805/) をなぞる記事です。記事中のスクショは、上記セッションのスライドを撮ったものです。

# 概要

ショートカットの構築手順と、ユーザ体験を最適化する方法について。[Soup Chef](https://developer.apple.com/documentation/sirikit/soup_chef_accelerating_app_interactions_with_shortcuts)（クラムチャウダーかトマトスープを注文できるアプリ）を例に取って説明している。

# 出てくる用語について

## アクション

ショートカットを実行させるための動作のこと。アクションの集合がショートカット。

## パラメータ

アクションを行う上で必要になる変数。「スープをx個注文する」の場合のxを指す。

## サマリ

ショートカットの動作を説明する文。「スープをx個注文する」などの文（だと思われる）。

# ショートカットアプリ内での設定方法

アクションのパラメータは編集可能になっている。
<img width="350" alt="スクリーンショット 2019-08-25 15.42.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/c2cc1da5-2d6a-34e4-811d-6b9fd08f5b2f.png">

内部的には Xcode の .intentdefinition ファイルで定義している。
<img width="988" alt="スクリーンショット 2019-08-25 15.49.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/7d018fa1-e95a-6364-cb07-e25b9ff89baa.png">

サマリはショートカットの動作を説明する文で、以下の点に注意すると良い。

* 動詞で始まる文章のようにする
* アプリ名は上部に表示されているので、アプリケーション名はいらない
* できるだけ短くして、必要最低限のパラメータのみを記述する
* 残りのパラメータは「表示を増やす」の下に表示されており、パラメータを修正できる

サマリは Xcode の Shortcuts の項目で定義している。Soup Chef は持ち帰り用と配達用の複数のサマリを持っている。アクションの中で持ち帰りか配達かを変更すれば、それに伴ってパラメータ、サマリも更新される。

<img width="300" alt="スクリーンショット 2019-08-25 16.07.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/4e7fb30c-d0d2-9c60-bf83-f79be0b34a8d.png"> <img width="300" alt="スクリーンショット 2019-08-25 16.07.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/ecd65dc0-e911-e8bf-cdbb-286ede30eb4b.png">

# ショートカットを見つけてもらう方法

ショートカットを作らせるなら、そのアプリ内が一番良い。

例えばトマトスープとチーズを注文したとする。繰り返す可能性が高いので Soup Chef は注文情報を Intents に渡し、「Siriに追加」（INUIAddVoiceShortcutButton）ボタンを表示する。
<img width="143" alt="スクリーンショット 2019-08-22 18.19.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/e532718d-c3ae-49ef-75ff-3ad64dd6d931.png">
ボタンをタップすれば Siri に追加ができる。この API 自体は iOS 12 と変わらないが、ViewController 内でできることが増えた。

まず、タイプや音声入力での保存が可能になった。Intents の suggestedInvocationPhrase でデフォルトのフレーズ設定ができる。Siri に言いやすく、また覚えやすいように、アクションを端的に表す短いフレーズにするのが良い。
<img width="565" alt="スクリーンショット 2019-08-22 18.23.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/29d91865-a400-8f68-1381-116618196b99.png">

下のDoセクションにプレビューが表示されるようになった。ここでは可能な限り多くの情報を Intents に入れるのが良い。そうすることで追加で質問しなくてもスムーズにスープを注文することができる。設定可能な項目があれば、プレビューをタップすることで初期値を書き換えてカスタマイズすることができる。
<img width="389" alt="スクリーンショット 2019-08-25 16.16.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/453334be-e253-4f9b-aed9-214e8c14995d.png">
これらの手順を踏んだ後、「Siriに追加ボタン」をタップするとアプリケーションに戻る。

とはいえ初めてのユーザはまずギャラリーから見始めることが多い。ここには既存のショートカットが並んでいる。iOS 13 では新しい項目が追加され、よく使うアプリのショートカットが提案される。ユーザの使用状況に応じてショートカットが目立つ形で配信される。
<img width="258" alt="スクリーンショット 2019-08-25 16.24.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/19fd33bb-f04a-cfae-c087-ab936c2d8f9e.png">

この提案がされるようにする方法が2つある。INVoiceShortcutCenter を使えば提案のリストを作ることができる。これはユーザの習慣や好みを学びつつ何度でも更新できる。なのでユーザの最近のアクションからリストを生成することもできる。ユーザの行動を知るためには、去年紹介した Donation が役立つ。ユーザの行動をシステムに伝えることで、より適切なタイミングで提案が行える。伝えるためには INInteraction を作成する。

```swift
INVoiceShortcutCenter.shared.setShortcutSuggestions([ 
    INShortcut(intent: orderClamChowder), 
    INShortcut(intent: orderTomatoSoup)
])

let interaction = INInteraction(intent: myIntent, response: nil)
interaction.donate(completion: nil)
```

こうすることでギャラリーで表示されるだけでなく、ロック画面やSpotlight検索時に提案することもできる。
<img width="328" alt="スクリーンショット 2019-08-25 16.28.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/4a85d35d-85dd-0f78-cfdf-f9a9ee45ba9d.png">

この他にユーザがショートカットを目にするタイミングは、ショートカットアプリ内で新しくショートカットを作る時。エディタには実行可能なアクションが表示され、その中にはループやif文のようなアクションも含まれる。
<img width="302" alt="スクリーンショット 2019-08-25 16.31.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/f98621bb-57d2-2a4e-cb50-71b749f0297a.png">

アクションの提案リスト（Suggestionsのセクション）もデバイスの使用状況に沿っている。ここにSoup Chef オプションを表示させるには2つの簡単な手順を踏む必要がある。

**キーパラメータを何にするか決める**：ユーザにとってわかりやすいものにすること。Soup Chef では量やトッピングより大事な「スープ種別」をキーパラメータにした。ユーザが何かアクションをするたびにアプリはユーザの行動をシステムに報告する。INVoiceShortcutCenter や INInteration 経由で報告していれば、追加の操作は特に必要ない。
<img width="990" alt="スクリーンショット 2019-08-25 16.37.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/1fc2f454-9f0e-3798-5f61-9c152048a7ec.png">
<img width="732" alt="スクリーンショット 2019-08-25 16.41.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/607914fb-4ce6-7125-030b-3fd9edea854e.png">

**キーパラメータのイメージを追加する。**特に指定しない場合はアプリアイコンが表示される。

# 複数ステップのショートカット構築方法

StickyNote というメモを取るアプリがある。このアプリで重要なのはメモをタイトルで検索できること。加えて、見つけたメモに対して文章を追加したり削除したりしたい。iOS 13 ではアクションの出力情報を他のアプリが活用できるようになっている。StickyNote では識別子、名称、内容、最終修正日などの情報を取り出すことができる。2つのショートカットを連携させ、メモを探して情報を追加することを考えてみる。メモの内容が最初のアクションの出力であり、2番目のアクションの入力になるようにする。

まずはStickyNoteを示す新しいタイプを追加する。
<img width="1041" alt="スクリーンショット 2019-08-25 23.10.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/68782238-9b02-0468-9d43-eb3769438506.png">
タイプにはすでに識別子と表示名が存在している。メモには内容と最終修正日の情報もあるので、これらもプロパティとして追加して、ユーザからアクセス可能な状態を作る。
<img width="992" alt="スクリーンショット 2019-08-25 23.14.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/7c00b90c-7e66-0864-8395-d7458d2cd0fe.png">

次に、Intentsの結果を表すオブジェクトであるレスポンスを選択する。noteプロパティの追加、先程追加したNoteタイプを選択する。
<img width="992" alt="スクリーンショット 2019-08-25 23.20.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/39d66b15-b688-15af-1619-6dc1bdd4b028.png">

最後にOutputのドロップダウンからnoteプロパティを選択する（レスポンスに複数のプロパティがある場合は、そのうちの1つを選択する）。
<img width="990" alt="スクリーンショット 2019-08-25 23.25.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/c415dc81-9363-fc5f-05f5-cebacdef41b8.png">
これで他のアクションがこれらの情報を見て活用することができる。

次に新しいアクションを追加して、検索で見つかったメモを修正対象として選択する。
<img width="300" alt="スクリーンショット 2019-08-25 23.28.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/3cd9d501-4609-72d2-fba3-7ed43665e2df.png">

もし2番目のアクションに自動的に情報が渡せたら、毎回対象を選択する必要がなくなるはず。そこで1つ目の出力を次のアクションの入力にするように設定して、うまく連携できるようにします。

AddTextというアクションに対して、入力パラメータとしてnoteを選択する。
<img width="996" alt="スクリーンショット 2019-08-25 23.33.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/d27c51f3-02d9-b9d5-8dec-d1bac1c5a246.png">

これで、2番目のアクションを追加したときにnoteパラメータにデフォルトでメモが入っている状態を作ることができる。
<img width="298" alt="スクリーンショット 2019-08-25 23.34.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100736/e96a3669-b622-7748-66f0-b4e1af130b56.png">