ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
App IntentによるAppショートカットの実装
ユーザによる設定なしで、みなさんのアプリのショートカットを作成する方法をご確認ください。App Intentでカスタムのショートカットビューを表示する方法や、パラメーター化されたフレーズのサポートを追加して、ユーザの思い通りに素早く意図を表現する方法を紹介します。また、Siri Tipやショートカットリンクを使用して、Appショートカットを見つけやすくする方法も紹介します。 このセッションを最大限活かしていただくためには、SwiftUIに関する基本的な知識を習得されていることが推奨されます。
リソース
関連ビデオ
Tech Talks
WWDC22
-
ダウンロード
♪ 落ち着いた雰囲気の ヒップホップ音楽 ♪ ♪ こんにちは Michael Sumnerです Siri とApp Intentの ソフトウェアエンジニアです このセッションでは 新しいApp Intents フレームワークを使い アプリショートカットを 作成する方法を説明します 最初にショートカットの 概要と App Intentとの 関連性を説明します 次に Swift を使用して アプリショートカットを作成し パラメータを追加する方法を お見せします 最後にユーザーがあなたの 努力から利点を得られるよう アプリショートカットを発見可能に する方法を説明します ではApp Intents フレームワークと アプリショートカットから 始めましょう ユーザーはショートカットアプリや Siriから使用可能な みなさんのアプリを利用した 複数ステップのワークフローを 作成するために ショートカットを使用します これまでは Intentを 使用可能にするために 「Siriに追加」 ボタンによる設定か ショートカットアプリでの 設定が必要がありました そこでユーザー設定が まったく不要な 新しい アプリショートカットを 発表します これでユーザーが みなさんのショートカットから メリットを得やすくなります アプリショートカットを サポートすることで アプリで定義されたIntentは アプリがインストールされた直後から 利用可能になります これにより ユーザーは みなさんのアプリの機能を 発見・使用しやすくなります 何かを設定するために ショートカットアプリや 「Siri に追加」ボタンを 使用する必要はなくなります ユーザーが構築する ショートカットのように ショートカットアプリ Spotlight Siri で 実行できます これでユーザーは複数の方法で システム内の異なる場所から アプリを発見し やりとりすることができます 例えば Spotlightで検索する場合 検索結果に アプリショートカットが 表示され アクセスしやすくなります アプリショートカットを 実装することで ユーザーはみなさんのアプリで すばやく軽いやりとりをして タスクを完了し 目的の達成へと 向かいやすくなります 私のチームは 一連の 音声によるガイドや サウンドを使い ユーザーが瞑想し 重要な ことに集中するのに役立つ 「Mediation」という アプリを作成しています 現在 瞑想を始めるには ユーザーはアプリを起動し ログインして実施する瞑想 セッションを検索します アプリショートカットと サポートすれば ユーザーは Siri にリクエスト するだけで どこからでも アプリにアクセスできるように なります セッションを すばやく開始することで ユーザーは朝の仕事前や 長い1日の緊張をほぐすため 夕方に瞑想することを 日常生活の一部に 取り入れることができます では App Intentを作成し それをアプリショートカットに するために必要な コードについて説明します 以前のショートカットとは異なり アプリショートカットは 新しい App Intents フレームワークで構築します App Intentsフレームワークは 優れたIntentを すばやく簡単に構築するための 一から構築された Swiftオンリーの新しい フレームワークです App Intentでは すべてが Swiftのソースコードで 定義でき 別のメタデータ ファイルは必要ありません これはすべてのコード生成 手順を省略でき ソースエディタと メタデータエディタの間で コンテキストを切り替える 必要がなく 集中しやすくなり コードのレビューや マージの競合の解決も 行いやすくなります アプリショートカットを 構築するには App Intentを本格的な ショートカットに変えるのに 必要なフレーズや 他の メタデータをリストする AppShortcutsProviderを 書く必要があります ここで注意が必要なのは アプリショートカットは ユーザーインタラクションなしで 設定されるため トリガーフレーズに アプリ名を含む必要がある点です Intentは AppIntentプロトコルを実装した Swiftの構造体で 定義されます 基本のIntentの 要件は2つだけ ショートカットアプリに 表示されるタイトルと performと呼ばれる メソッドです performメソッドにて Intentのロジックを実装し 結果を戻すようにします さらに ユーザーにプロンプトを出し レスポンスを待つこともできます このIntentではアプリの MeditationServiceで デフォルトの 瞑想セッションを始めます performメソッドは 非同期のため 非同期コードを実行し セッションを開始できます セッションが開始したら ユーザーに表示される ダイアログを戻します アプリが ローカライズされている場合 すべての地域でこの文字列を ローカライズします ここまでの構築によって ショートカットを設定しようとすると StartMeditationIntentが ショートカットアプリに現れます やる気のあるユーザーは このIntentを使用し セッションを開始するための ショートカットを作成できます このショートカットでは 2つ目のIntentを作成し 「集中」を有効にします デフォルトでは Intentはソースコードで 指定したタイトルで レンダリングされます アクションのレンダリングを カスタマイズするには App Intentに パラメータサマリを追加します パラメータサマリでは Intentの見た目を カスタマイズでき インラインで値を表示します このIntentは ショートカットになりますが ユーザーが ショートカットの設定なしで Intentを実行できるのが 理想的です アプリショートカットを 作成すれば この設定手順をユーザーの 代わりに行うことができ ユーザーはアプリを インストールした途端に 私のIntentを 使用できるようになります では Intentを書いたところで アプリショートカットを 作成しましょう Intentと同様に App Intentも AppShortcutsProvider プロトコルを実装して Swiftコードで定義します プロトコルを実装するには ユーザーのために設定したい すべてのショートカットを 返す単一のゲッタを 作成するだけです みなさんのアプリにおいて 最大10件の アプリショートカットを 持たせることができます しかし ほとんどのアプリは 数件必要なだけでしょう StartMeditationIntent 用に 単一の AppShortcut を 作成します 始めにIntentの インスタンスを渡します イニシャライザに パラメータが必要な場合は ここで値を指定します 次に Siri から アプリショートカットを起動する 一連のフレーズを作成します 文字列に直接アプリ名を 入力する代わりに 特別な.applicationName トークンを使用します これにより Siri は アプリのメイン名に加え 構成したアプリ名の シノニムを挿入できます ユーザーは 異なるフレーズを 使って瞑想を起動するため 代替のフレーズを もう少し追加します アプリがローカライズ されているなら これらのフレーズも ローカライズしてください
完了しました これで ユーザーが瞑想を始める時 Siri に「瞑想をスタート」と 言えばアプリが起動します Siri は StartMeditationIntentをコールし 私が返したダイアログを 読み上げます また 誰かが Spotlightで 私のアプリを検索すると 私がコードに記載した 最初のショートカットが 表示されます ユーザーが 結果をタップすると アプリを起動せずに ショートカットが すぐに実行されます ただしIntentが アプリの起動をトリガーする場合 Spotlightには表示されませんので ご注意ください これだけのコードで ユーザーが私のアプリで 瞑想するのが 非常に簡単になりました しかしこのままでは Intentを実行すると Siri はデフォルトの ビューを表示します これでも構いませんが ユーザーがショートカットを 実行した場合に詳細な 情報を表示したいとします それには Intentを 実行した際に Siri が それを表示するようカスタム ビューの実装が必要です App Intentsフレームワークの ビューは SwiftUI で構築され ウィジェットと同じ技術を 使用するため カスタムビューのために 別の UI Extension を 使用する必要はありません 代わりに Intentを実行する際に ビューを返すだけです ビューにもたらされる 特定の制約について 意識することが重要です ウィジェット同様に このカスタマイズされたビューは インタラクティビティやアニメーションを 含むことはできません UIをデザインする際に この事を忘れないでください Intentでは3つのフェーズで カスタム UI を表示できます 値の確認フェーズ Intentの確認フェーズ Intent終了後です 私のアプリでは Intent実行終了時に カスタムビューを返します 他のプロンプトを 使用する場合は これらのフェーズで カスタム UI を サポートする方法も 必ず考慮しましょう 先述のように カスタム UI の表示は簡単です Intentからビューを 返すだけです ではコードに移りましょう カスタムビューの追加は 簡単です ダイアログと共にビューを 返します App Intentsフレームワークは Siriスニペット内で ビューを提示します このビューは スニペットのタイトルや 確認ボタンなど他の Siriのビューと一緒に 表示されることを 忘れないでください そのためスニペットが Siriの中で ホームであるように感じられる デザインをします 次はアプリショートカットを 拡張し パラメータを含める方法を お見せします 前回の実装では デフォルトの瞑想の 開始を選択しましたが アプリにはすばらしい セッションが他にも多くあり ユーザーは特定のセッションを 開始したい場合が 考えられます ユーザーが私のIntentを 実行した場合に セッションを指定できるのが 理想的です このユースケースに 対応するためには ユーザーが実行したい セッションを取得する パラメータを追加して Intentを拡張します パラメータを追加するには まず パラメータの型を 定義します セッションの関する 情報がある MeditationSession 構造体を作成します 名前を含み identifier フィールドを 提供します これを UUID に することができます この構造体をIntentの パラメータとして使うには AppEntityプロトコルを 実装する必要もあります AppEntityプロトコルを 実装すると App Intentsフレームワークに 独自の型を伝え エンティティの表示方法など 追加の情報を 指定することができます エンティティプロトコルでは 型に対する識別子が必要ですが ここでは すでに提供しています 整数や文字列など 他の型も使用できます エンティティの 表示方法について 情報を 提供する必要もあります これはエンティティが 表示される ショートカットアプリや その他の場所で使用されます 最後にデフォルトクエリを つなげる必要があります クエリ名は MeditationSessionQuery これを次に実装します App Intentsフレームワークが エンティティと連動するには エンティティの識別子に 基づいて 検索できる必要があります これを可能にするために EntityQuery プロトコルは 次の1つの要件を定義します 識別子を使い 一致するエンティティを 返す関数です SessionManagerで このセッションを検索し この関数を実装します StartMeditationIntentを 更新して パラメータを追加します パラメータは簡単です 構造体の 通常のプロパティです しかしApp Intentに パラメータを伝えるには @Parameter Property Wrapperの追加が必要です このProperty Wrapper は App Intentに セッションプロパティが Intentの一部だと伝え 表示名など 追加のメタデータを @Parameter Property Wrapper で指定できます パラメータプロパティを Intentに追加したら どのセッションを実行するか ユーザーに聞く必要があります App Intents フレームワークには Intentのパラメータの 値を得るために ユーザーに補足の質問ができる 堅牢なサポートがあります これらの指示はIntentが 実行される場所で表示され Siri から実行される場合であれば Siri が質問を読み上げ ユーザーは答えを言うように 指示されます Spotlight と ショートカットアプリでは ユーザーは タッチドリブンなUIで 同じプロンプトが出ます App Intentに対応する 値を得るプロンプトは3つ 曖昧性解消はリストからの 選択を指示します 曖昧性解消は Intentのパラメータが 一定のオプションに 限定される場合に 最適です 値のプロンプトでは 制限のない値を ユーザーに聞くことができます これは任意の値を使用できる 文字列や整数に 最適です 最後に 確認は ユーザーに特定の値の確認を要求し ユーザーがIntentを 理解していることを 再確認するのに 最適です 値のためのプロンプトは Intentの 柔軟性を高め ユーザーからより多くの 情報を得るのに すばらしい方法です しかし会話の速度を下げ 頻繁に使用するとユーザーが 苛立つ場合があります 優れたIntentの作成の 詳細については Lynnによる 『アプリショートカットの デザイン』をご覧ください ではセッションパラメータを StartMeditationIntentに 追加したところで performメソッドに ロジックを追加して この値をプロンプトします 私のアプリにはユーザーが 実行できる 一定数の セッションがあります セッションがまだ 指定されていない場合 SessionManagerから リストを取得し ユーザーに曖昧性解消を 示します 各セッションにDisplay Representationを使用すると App Intentは セッションをリスト項目にし ユーザーに表示します ユーザーが1つ選択すると 選択した項目が 戻されます 選択されたセッションが MeditationServiceに渡され セッションが開始します 次にユーザーに Intentが開始したことを 知らせるダイアログを 返します ユーザーがセッションを 渡したので ダイアログに セッション名を表示し リクエストを把握したことを 知らせるのがよいでしょう 今ユーザーが「瞑想をスタート」 と言っています アプリはユーザーが 開始したいセッションに 移動します ただし 先述のように ユーザーはすばやく明確な Siri とのやりとりを望み 理想的には 補足的な質問ではなく 初期の段階でユーザーが 好みのセッションを 伝えられることが 好ましいです ここでいいニュースが あります アプリショートカットは 事前定義されたパラメータで トリガーフレーズを 拡張することができます パラメータ化された フレーズの実装により アプリは 「落ち着く瞑想をスタート」や 「歩く瞑想をスタート」などの 発言に対応することができます パラメータは Siri に 事前に指定できる 一定数の決まった パラメータ値がある場合に 役立ちます 私のアプリでは セッション名を使用します パラメータは制限なしの値で 使用するものではありません 例えば最初の語りかけで ユーザーから任意の文字列を 収集することはできません そのためアプリは Xがユーザーの任意の 入力となる場合 「Xの日記を検索」などの 語りかけに 対応することはできません アプリの実行中より前の タイミングで パラメータ値を事前に 指定する必要があります。 パラメータ化されたフレーズを 実装してみましょう アプリでこれを行う場合 いくつかの変更を 行う必要があります まず suggestedResults() メソッドを実行し ショートカットに エンティティのリストを 返すためにSessionEntityの クエリを更新します 次にApp Intents フレームワークに SessionEntitiesが 変更したことを伝えます これによりApp Intents フレームワークは Siri で使用される 新しいフレーズを作成します これを行うには アプリのモデルレイヤを更新し セッションリストが 変更されるたびに App Intentsフレームワークに 通知されるよう設定します 最後に StartMeditationIntentで セッションパラメータを 参照するアプリショートカットに 新しいフレーズを いくつか追加します まず suggestedEntities 関数を実装し MeditationSessionQueryを 更新します App Intentsフレームワークは 関数から戻されたセッションで パラメータ化された ショートカットを作成します このメソッドは オプショナルでして このメソッドを実装しない場合 パラメータ化された ショートカットは 利用できません またセッションのリストが 変更された場合 それを App Intentsフレームワークに それを知らせるために アプリのモデルレイヤを 更新する必要があります ここではバックグラウンドで サーバから取得した 新しいセッションタイプを 不定期に公開しています SessionModelを更新して 新しいセッションを 受信するたびに update AppShortcutParameters()を 呼び出します これはApp Intents フレームワークが提供し 自身で実装する必要はなく App Intentは エンティティの クエリを呼び出し ショートカットフレーズの パラメータを収集します 最後にアプリショートカットに Intentのセッション キーパスを含む 新しいフレーズを追加します フレームワークは このフレーズを クエリから返されるすべての セッションと組み合わせます 各値で使用されるテキストは SessionEntityの Display Representationで タイトルプロパティから取得されます 先ほどのように ユーザーが 私にアプリショートカットに 使う異なるフレーズを数件 追加したいと思います これで ユーザーがみなさんが 設定したフレーズを 思い出せない時でも スムーズな体験を確保します これで完全に機能する ショートカットができました ユーザーが使用するのが 待ち遠しいです しかしそうなるためには ユーザーがショートカットを 発見する方法が必要です まずお伝えしたいのは良い フレーズを選択すること これは短くて覚えやすい フレーズを意味します ユーザーのiPhoneには App ショートカットに対応する 多くのアプリが インストールされるはずです そのためユーザーが ショートカットのフレーズを 思い出せないことが 考えられます なので短くて簡単な フレーズにしましょう それに加えアプリ名が 名詞または動詞に できる場合は フレーズでそれらを 使用するようにします このアプリではフレーズを 短く覚えやすくするために 瞑想を 名詞として使っています またアプリ名のシノニムは ユーザーにとって便利です ユーザーがアプリを呼ぶ際に アプリの表示名以外で 呼ぶ場合があるので アプリのシノニムを 追加することを推奨します iOS 11から アプリ名の シノニムに対応しています まだ作成していないなら 今がチャンスです 次にお話ししたいのは Siri Tipと ショートカットリンクです アプリショートカットは ユーザー設定が必要ないので ユーザーがみなさんの アプリショートカットを 発見・使用するために 見つけやすさは重要です アプリショートカットでは ユーザーはショートカットの 追加のために 「Siriに追加」ボタンが不要です すでに追加されているためです しかし「Siriに追加」 ボタンが提供する 見つけやすさを 失いたくありません それを考慮して新しい Siri Tipビューを作成しました このビューは過去に 「Siriに追加」ボタンを 使用していた場所で うまく機能します TipビューはSwiftUIと UIKitで使用することができ さまざまな スタイルが利用可能です どのアプリでもTipが すばらしい形で見えます Siri Tipは 画面のコンテンツに 関連性がある場合 状況に応じて配置します ユーザーがみなさんのアプリで 注文したところなら 注文状況を示す ショートカットの Tipを表示することを 考慮します Siri Tipは ユーザーが近い将来 アプリショートカットを 使うだろうと感じた時に それを十分に考慮して配置します Siri Tipは消すことにも 対応します ビューには消すためのボタンが 含まれ コードが タップされた時にカスタムの クロージャがトリガーされます レイアウトからビューを 削除して 関連性があると感じるまで 表示しないことを 考慮してください ショートカットの リストを起動する ショートカットリンクが 追加されました この新しい要素は アプリに多数の ショートカットがあり ユーザーにすべて探索して ほしい場合に便利です アプリショートカットの すばらしい点は アプリをインストールして すぐに利用できることです アプリが最初に起動する前に ユーザーはショートカットを Spotlight Siri ショートカットアプリから 実行し確認できます アプリショートカットを 構築する時は この事を配慮してください 例えばアプリに ログインフローが必要な場合 ユーザーがIntent実行前に ログインしていなければ Intentは失敗し ユーザーのログインが必要だと 説明するメッセージが 表示されます 次にアプリショートカットの パラメータ化されたフレーズは アプリが起動するまで 利用することはできず App Intents フレームワークに 新しいパラメータ値が あることを伝えます アプリショートカットに パラメータ化されていない フレーズが含まれていると アプリを起動するまで ショートカットは 表示されません これを避けるために いくつかの パラメータ化されていないフレーズを 追加することを おすすめします さらに Siri は 「ここでなにをしますか」 「瞑想で何ができますか」 などのフレーズに対応します Siri はショートカット フレーズを自動的に収集 推薦し みなさんの代わりに 提示します この機能が動作するために アプリが追加で 何かをする必要はありません Siri とショートカット アプリの両方で ショートカットが表示される 順番は ソースコードに記載した ショートカットの順番で 表示されます 最も良い便利な アプリショートカットを 最初に並べて 注意を引くようにしましょう 同様にフレーズの配列に 最初に載せるフレーズは アプリショートカットの プライマリのフレーズとして ショートカットタイルの ラベルとして使用されます またユーザーが Siri に アプリへのヘルプを 依頼した時に表示されます App Intentsフレームワークと ショートカットで 多くのご案内をしました 最後に2つの主要な 考えをお伝えします アプリショートカットは ユーザーがシステムのあらゆる 場所からアプリを 使用できるようになるので この軽量なモデルに最適な ユースケースを考えましょう 次にアプリショートカットを 実装したら ユーザーにそのことを 伝える必要があります 見つけやすくするための 方法を熟考してください Siri Tipや Webサイトや店舗のサインなど プロダクト外の場所での 表示を考慮してください 新しいApp Intents フレームワークで 作成するショートカットを 見るのが楽しみです デザインについての詳細 App Intents フレームワークの詳細は 今週の別のトークを ご覧ください ありがとうございました WWDCをお楽しみください ♪
-
-
3:43 - Implement an AppIntent
// StartMeditationIntent creates a meditation session. import AppIntents struct StartMeditationIntent: AppIntent { static let title: LocalizedStringResource = "Start Meditation Session" func perform() async throws -> some IntentResult & ProvidesDialog { await MeditationService.startDefaultSession() return .result(dialog: "Okay, starting a meditation session.") } }
-
5:31 - Create an AppShortcutsProvider
// An AppShortcut turns an Intent into a full fledged shortcut // AppShortcuts are returned from a struct that implements the AppShortcuts // protocol import AppIntents struct MeditationShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: StartMeditationIntent(), phrases: ["Start a \(.applicationName)"] ) } }
-
6:35 - Provide multiple phrases
// An AppShortcut turns an Intent into a full fledged shortcut // AppShortcuts are returned from a struct that implements the AppShortcuts // protocol import AppIntents struct MeditationShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: StartMeditationIntent(), phrases: [ "Start a \(.applicationName)", "Begin \(.applicationName)", "Meditate with \(.applicationName)", "Start a session with \(.applicationName)" ] ) } }
-
8:54 - Provide a dialog and snippet view
// Custom views give your intent more personality // and can convey more information func perform() async throws -> some ProvidesDialog & ShowsSnippetView { await MeditationService.startDefaultSession() return .result( dialog: "Okay, starting a meditation session.", view: MeditationSnippetView() ) }
-
10:09 - Implement an AppEntity
// An entity is a type that can be used as a parameter // for an AppIntent. import AppIntents struct MeditationSession: AppEntity { let id: UUID let name: LocalizedStringResource static var typeDisplayName: LocalizedStringResource = "Meditation Session" var displayRepresentation: AppIntents.DisplayRepresentation { DisplayRepresentation(title: name) } static var defaultQuery = MeditationSessionQuery() }
-
10:55 - Query for entities
// Queries allow the App Intents framework to // look up your entities by their identifier struct MeditationSessionQuery: EntityQuery { func entities(for identifiers: [UUID]) async throws -> [MeditationSession] { return identifiers.compactMap { SessionManager.session(for: $0) } } }
-
11:16 - Define a parameter
// Adding a parameter to an intent allows you to prompt the user // to provide a value for the parameter struct StartMeditationIntent: AppIntent { @Parameter(title: "Session Type") var sessionType: SessionType? // ... }
-
13:15 - Prompt for values
// Prompting for values can be done by calling methods // on the property's wrapper type. func perform() async throws -> some ProvidesDialog { let sessionToRun = self.session ?? try await $session.requestDisambiguation( among: SessionManager.allSessions, dialog: IntentDialog("What session would you like?") ) } await MeditationService.start(session: sessionToRun) return .result( dialog: "Okay, starting a \(sessionToRun.name) meditation session." ) }
-
16:11 - Implement suggestedEntities()
// Queries can provide suggested values for your Entity // that serve as parameters for App Shortcuts struct MeditationSessionQuery: EntityQuery { func entities(for identifiers: [UUID]) async throws -> [MeditationSession] { return identifiers.compactMap { SessionManager.session(for: $0) } } func suggestedEntities() async throws -> [MeditationSession] { return SessionManager.allSessions } }
-
16:34 - Update App Shortcut parameters
// Your app must notify App Intents when your values change // This is typically best done in your app’s model layer class SessionModel { @Published var sessions: [MeditationSession] = [] private var cancellable: AnyCancellable? init() { self.cancellable = $sessions.sink { _ in MeditationShortcuts.updateAppShortcutParameters() } } // ... }
-
17:09 - Add parameterized phrases
// Phrases can also contain a single parameter reference import AppIntents struct MeditationShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: StartMeditationIntent(), phrases: [ "Start a \(.applicationName)", "Begin \(.applicationName)", "Meditate with \(.applicationName)", "Start a \(\.$session) session with \(.applicationName)", "Begin a \(\.$session) session with \(.applicationName)", "Meditate on \(\.$session) with \(.applicationName)" ] ) } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。