Xamarin.iOS での SiriKit の実装

この記事では、Xamarin.iOS アプリで SiriKit サポートを実装するために必要な手順を説明します。

iOS 10 の新機能である SiriKit を使用すると、Xamarin.iOS アプリは、iOS デバイス上の Siri と Maps アプリを使用してユーザーがアクセスできるサービスを提供できます。 この記事では、必要な Intents 拡張機能、Intents UI 拡張機能、ボキャブラリを追加して、Xamarin.iOS アプリで SiriKit のサポートを実装するために必要な手順について説明します。

Siri は、関連するタスクの認識アクションのグループである、ドメインの概念により機能します。 アプリが Siri とやり取りする各対話は、次のように既知のサービス ドメインのいずれかに分類される必要があります。

  • 音声通話またはビデオ通話。
  • 乗車予約。
  • トレーニングの管理。
  • メッセージング。
  • 写真の検索。
  • 支払いの送受信。

ユーザーが Siri に App Extension のサービスのいずれかが関与する要求を行うと、SiriKit は拡張機能に、サポート データと共にユーザーの要求を説明する Intent オブジェクトを送信します。 その後、アプリの拡張機能は、指定された Intent に対して適切な Response オブジェクトを生成し、拡張機能による要求の処理方法の詳細を伝えます。

このガイドでは、既存のアプリに SiriKit のサポートを含める簡単な例を示します。 この例では、架空の MonkeyChat アプリを使用します。

MonkeyChat アイコン

MonkeyChat は、このアプリ専用のユーザーの友人の連絡帳を保持し、各友人が画面名 (Bobo など) と関連付けられ、ユーザーが画面名で各友人にテキスト チャットを送信できるようにします。

SiriKit を使用したアプリの拡張

SiriKit の概念の理解」ガイドに示すように、SiriKit を使用したアプリの拡張には、次の 3 つの主要な部分があります。

「SiriKit を使用したアプリの拡張」の図

これには以下が含まれます。

  1. Intents 拡張機能 - ユーザーの応答を検証し、アプリが要求を処理できることを確認し、ユーザーの要求を満たすためのタスクを実際に実行します。
  2. Intents UI 拡張機能 - オプションで、Siri 環境での応答に対するカスタム UI を提供し、アプリ UI とブランド化を Siri に持ち込んで、ユーザー エクスペリエンスに豊かさをもたらします。
  3. アプリ - Siri の動作を支援するために、ユーザー固有のボキャブラリをアプリに提供します。

これらの要素のすべてと、それらをアプリに含める手順については、以下のセクションで詳しく説明します。

アプリの準備

SiriKit は拡張機能に基づいて構築されていますが、アプリに拡張機能を追加する前に、開発者が SiriKit の導入を支援するために行う必要があることがいくつかあります。

共通の共有コードの移動

最初に、開発者は、アプリと拡張機能の間で共有される共通のコードの一部を、共有プロジェクトポータブル クラス ライブラリ (PCL)、またはネイティブ ライブラリのいずれかに移動できます。

拡張機能は、アプリが実行するすべてのことを実行できる必要があります。 サンプルの MonkeyChat アプリでは、連絡先の検索、新しい連絡先の追加、メッセージの送信、メッセージ履歴の取得などです。

この共通のコードを共有プロジェクト、PCL、またはネイティブ ライブラリに移動することで、そのコードを 1 つの共通の場所で簡単に保守し、拡張機能と親アプリが統一されたエクスペリエンスと機能をユーザーに提供できるようにします。

サンプル アプリの MonkeyChat の場合、データ モデルと、ネットワークやデータベースへのアクセスなどの処理コードはネイティブ ライブラリに移動されます。

次の操作を行います。

  1. Visual Studio for Mac を起動し、MonkeyChat アプリを開きます。

  2. Solution Pad でソリューション名を右クリックし、[追加]>[新しいプロジェクト...] を選択します。

    新しいプロジェクトを追加します

  3. [iOS]>[ライブラリ]>[クラス ライブラリ] を選択し、[次へ] ボタンをクリックします。

    [クラス ライブラリ] を選択します

  4. [名前] に「MonkeyChatCommon」と入力し、[作成] ボタンをクリックします。

    [名前] に「MonkeyChatCommon」と入力します

  5. ソリューション エクスプローラーのメイン アプリの References フォルダーを右クリックし、[参照の編集...] を選択します。MonkeyChatCommon プロジェクトにチェックを付け、[OK] ボタンをクリックします。

    MonkeyChatCommon プロジェクトを確認します

  6. ソリューション エクスプローラーで、共通の共有コードをメイン アプリからネイティブ ライブラリにドラッグします。

  7. MonkeyChat の場合は、DataModels フォルダーと Processors フォルダーを、メイン アプリからネイティブ ライブラリにドラッグします。

    ソリューション エクスプローラーの DataModels フォルダーと Processors フォルダー

ネイティブ ライブラリに移動されたファイルを編集し、ライブラリの名前空間と一致するように名前空間を変更します。 たとえば、MonkeyChatMonkeyChatCommon に変更するとします。

using System;
namespace MonkeyChatCommon
{
    /// <summary>
    /// A message sent from one user to another within a conversation.
    /// </summary>
    public class MonkeyMessage
    {
        public MonkeyMessage ()
        {
        }
        ...
    }
}

次に、メイン アプリに戻り、移動されたクラスの 1 つをアプリが使用するすべての場所でネイティブ ライブラリの名前空間の using ステートメントを追加します。

using System;
using System.Collections.Generic;
using UIKit;
using Foundation;
using CoreGraphics;
using MonkeyChatCommon;

namespace MonkeyChat
{
    public partial class MasterViewController : UITableViewController
    {
        public DetailViewController DetailViewController { get; set; }

        DataSource dataSource;
        ...
    }
}

拡張機能に合わせたアプリの設計

通常、アプリは複数のインテントにサイン アップするため、開発者はアプリが適切な数の Intents 拡張機能に合わせて設計されていることを確認する必要があります。

アプリで複数のインテントが必要な場合、開発者には、すべてのインテント処理を 1 つの Intents 拡張機能に配置するか、または各インテントについて個別の Intents 拡張機能を作成するという選択肢があります。

インテントごとに個別の Intents 拡張機能を作成することを選択する場合、開発者は各拡張機能に大量の定型コードを複製し、結果として大量のプロセッサとメモリのオーバーヘッドを作り出してしまう可能性があります。

2 つの選択肢のいずれかを選択するには、対象のインテントに本質的に同種のものがあるかどうかを検討します。 たとえば、オーディオ呼び出しとビデオ呼び出しを行ったアプリでは、これらのインテントの両方を 1 つの Intents 拡張機能に含めて、類似のタスクを処理し、コードの再利用を最大化できる可能性があります。

既存のグループになじまないインテントまたはインテントのグループについては、アプリのソリューションに新しい Intents 拡張機能を作成して含めます。

必須エンタイトルメントの設定

SiriKit 統合を含む Xamarin.iOS アプリには、適切なエンタイトルメントが設定されている必要があります。 開発者がこれらの必要なエンタイトルメントを適切に設定していない場合、実際の iOS 10 (またはそれ以降) のハードウェアにアプリをインストールしたりテストしたりすることができません。これは、iOS 10 シミュレーターが SiriKit をサポートしていないこともあり、要件となっています。

次の操作を行います。

  1. ソリューション エクスプローラーEntitlements.plist ファイルをダブルクリックして、編集用に開きます。

  2. [ソース] タブに切り替えます。

  3. com.apple.developer.siri Propertyを追加し、TypeBooleanに設定し、ValueYesに設定します。

    com.apple.developer.siri プロパティを追加します

  4. 変更をファイルに保存します。

  5. ソリューション エクスプローラープロジェクト ファイルをダブルクリックして、編集用に開きます。

  6. [iOS バンドル署名] を選択し、[カスタム エンタイトルメント] フィールドで Entitlements.plist ファイルが選択されていることを確認します。

    [カスタム エンタイトルメント] フィールドで Entitlements.plist ファイルを選択します

  7. [OK] ボタンをクリックして、変更を保存します。

完了すると、アプリの Entitlements.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>com.apple.developer.siri</key>
    <true/>
</dict>
</plist>

アプリの適切なプロビジョニング

Apple では SiriKit フレームワークの周辺に厳密なセキュリティを課しており、そのため、SiriKit を実装する Xamarin.iOS アプリには、適切なアプリ ID とエンタイトルメント (上記のセクションを参照) が必須であり、適切なプロビジョニング プロファイルで署名する必要があります。

使用する Mac で次のことを行います。

  1. Web ブラウザーで https://developer.apple.com に移動し、アカウントにログインします。

  2. [証明書][識別子][プロファイル] をクリックします。

  3. [プロビジョニング プロファイル] を選択し、[アプリ ID] を選択し、+ ボタンをクリックします。

  4. 新しいプロファイルの [名前] を入力します。

  5. Apple の名前付けの推奨事項に従って [バンドル ID] を入力します。

  6. [App Services] セクションまで下にスクロールし、[SiriKit] を選択し、[続行] ボタンをクリックします。

    SiriKit を選択します

  7. すべての設定を確認し、アプリ ID を [送信] します。

  8. [プロビジョニング プロファイル]>[開発] を選択し、+ ボタンをクリックして [Apple ID] を選択して、[続行] をクリックします。

  9. [すべて選択] をクリックし、[続行] をクリックします。

  10. [すべて選択] をもう一度クリックし、[続行] をクリックします。

  11. Apple の名前付け推奨を使用して [プロファイル名] を入力し、[続行] をクリックします。

  12. Xcode を起動します。

  13. [Xcode] メニューから、[基本設定...] を選択します。

  14. [アカウント] を選択し、[詳細の表示..] ボタンをクリックします。

    [アカウント] を選択する

  15. 左下隅にある [すべてのプロファイルのダウンロード] ボタンをクリックします。

    すべてのプロファイルをダウンロードします

  16. 上記で作成した [プロビジョニング プロファイル] が Xcode にインストールされていることを確認します。

  17. プロジェクトを開き、Visual Studio for Mac で SiriKit のサポートを追加します。

  18. ソリューション エクスプローラーで、Info.plist ファイルをダブルクリックします。

  19. [バンドル識別子] が、上記の Apple の開発者ポータルで作成したものと一致していることを確認します。

    バンドル識別子

  20. ソリューション エクスプローラー[プロジェクト] をクリックします。

  21. プロジェクトを右クリックし、[オプション] を選択します。

  22. [iOS バンドル署名] を選択し、[スピニング ID] と上記で作成した [プロビジョニング プロファイル] を選択します。

    署名 ID とプロビジョニング プロファイルを選択します

  23. [OK] ボタンをクリックして、変更を保存します。

重要

SiriKit のテストは、実際の iOS 10 ハードウェア デバイスでのみ動作します。iOS 10 シミュレーターでは動作しません。 SiriKit 対応 Xamarin.iOS アプリを実際のハードウェアにインストールする際に問題が発生する場合は、Apple の開発者ポータルと Visual Studio for Mac の両方で、必要なエンタイトルメント、アプリ ID、署名識別子、プロビジョニング プロファイルが適切に構成されていることを確認してください。

Siri 認可の要求

アプリがユーザー固有のボキャブラリを追加したり Intents 拡張機能が Siri に接続したりする前に、ユーザーから Siri にアクセスするための認可を要求する必要があります。

アプリの Info.plist ファイルを編集し、[ソース] ビューに切り替えて、アプリで Siri を使用する方法と送信されるデータの種類を説明する文字列値を含む NSSiriUsageDescription キーを追加します。 たとえば、MonkeyChat アプリでは "MonkeyChat の連絡先が Siri に送信されます" と表示される場合があります。

Info.plist エディターの NSSiriUsageDescription

アプリの初回起動時に INPreferences クラスの RequestSiriAuthorization メソッドを呼び出します。 AppDelegate.cs クラスを編集し、FinishedLaunching メソッドを次のようにします:

using Intents;
...

public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{

    // Request access to Siri
    INPreferences.RequestSiriAuthorization ((INSiriAuthorizationStatus status) => {
        // Respond to returned status
        switch (status) {
        case INSiriAuthorizationStatus.Authorized:
            break;
        case INSiriAuthorizationStatus.Denied:
            break;
        case INSiriAuthorizationStatus.NotDetermined:
            break;
        case INSiriAuthorizationStatus.Restricted:
            break;
        }
    });

    return true;
}

このメソッドが初めて呼び出されると、アプリが Siri にアクセスすることを許可するようユーザーに求めるアラートが表示されます。 開発者が上記 NSSiriUsageDescription に追加したメッセージがこのアラートに表示されます。 ユーザーが最初にアクセスを拒否した場合は、Settings アプリを使用してアプリへのアクセスを許可できます。

アプリでは、INPreferences クラスの SiriAuthorizationStatus メソッドを呼び出すことで、アプリが Siri にアクセスできるかどうかをいつでもチェックできます。

ローカリゼーションと Siri

iOS デバイスでは、ユーザーは、システムの既定の言語とは異なる言語を Siri について選択できます。 ローカライズされたデータを処理する場合、アプリは INPreferences クラスの SiriLanguageCode メソッドを使用して Siri から言語コードを取得する必要があります。 次に例を示します。

var language = INPreferences.SiriLanguageCode();

// Take action based on language
if (language == "en-US") {
    // Do something...
}

ユーザー固有のボキャブラリの追加

ユーザー固有のボキャブラリは、アプリの個々のユーザーに固有の単語または語句を提供します。 これらは、実行時に (アプリ拡張機能ではなく) メイン アプリから、ユーザーにとって最も重要な使用優先順位で並べ替えられた一連の用語として、最も重要な用語が一覧の先頭に表示された状態で提供されます。

ユーザー固有のボキャブラリは、次のいずれかのカテゴリに属している必要があります。

  • 連絡先名 (連絡先フレームワークによって管理されていない)。
  • 写真のタグ。
  • フォト アルバム名。
  • ワークアウト名。

カスタム ボキャブラリとして登録する用語を選択する際には、アプリに慣れていないユーザーが誤解する可能性がある用語のみを選択します。 "マイ ワークアウト" や "マイ アルバム" などの一般的な用語を登録しないでください。 たとえば、MonkeyChat アプリでは、ユーザーのアドレス帳の各連絡先に関連付けられているニックネームが登録されます。

このアプリは、INVocabulary クラスの SetVocabularyStrings メソッドを呼び出し、メイン アプリから NSOrderedSet コレクション内で渡すことによって、ユーザー固有のボキャブラリを提供します。 アプリでは、新しい用語を追加する前に既存の用語を除去するために、常に最初に RemoveAllVocabularyStrings メソッドを呼び出す必要があります。 次に例を示します。

using System;
using System.Linq;
using System.Collections.Generic;
using Foundation;
using Intents;

namespace MonkeyChatCommon
{
    public class MonkeyAddressBook : NSObject
    {
        #region Computed Properties
        public List<MonkeyContact> Contacts { get; set; } = new List<MonkeyContact> ();
        #endregion

        #region Constructors
        public MonkeyAddressBook ()
        {
        }
        #endregion

        #region Public Methods
        public NSOrderedSet<NSString> ContactNicknames ()
        {
            var nicknames = new NSMutableOrderedSet<NSString> ();

            // Sort contacts by the last time used
            var query = Contacts.OrderBy (contact => contact.LastCalledOn);

            // Assemble ordered list of nicknames by most used to least
            foreach (MonkeyContact contact in query) {
                nicknames.Add (new NSString (contact.ScreenName));
            }

            // Return names
            return new NSOrderedSet<NSString> (nicknames.AsSet ());
        }

        // This method MUST only be called on a background thread!
        public void UpdateUserSpecificVocabulary ()
        {
            // Clear any existing vocabulary
            INVocabulary.SharedVocabulary.RemoveAllVocabularyStrings ();

            // Register new vocabulary
            INVocabulary.SharedVocabulary.SetVocabularyStrings (ContactNicknames (), INVocabularyStringType.ContactName);
        }
        #endregion
    }
}

このコードが適切に配置されると、次のように呼び出されることになります。

using System;
using System.Threading;
using UIKit;
using MonkeyChatCommon;
using Intents;

namespace MonkeyChat
{
    public partial class ViewController : UIViewController
    {
        #region AppDelegate Access
        public AppDelegate ThisApp {
            get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
        }
        #endregion

        #region Constructors
        protected ViewController (IntPtr handle) : base (handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Do we have access to Siri?
            if (INPreferences.SiriAuthorizationStatus == INSiriAuthorizationStatus.Authorized) {
                // Yes, update Siri's vocabulary
                new Thread (() => {
                    Thread.CurrentThread.IsBackground = true;
                    ThisApp.AddressBook.UpdateUserSpecificVocabulary ();
                }).Start ();
            }
        }

        public override void DidReceiveMemoryWarning ()
        {
            base.DidReceiveMemoryWarning ();
            // Release any cached data, images, etc that aren't in use.
        }
        #endregion
    }
}

重要

Siri はカスタム ボキャブラリをヒントとして扱い、できるだけ多くの用語を組み込みます。 ただし、カスタム ボキャブラリの領域は限られているため、混乱を招く可能性のある用語のみを登録することが重要であり、登録される用語の合計数を最小限に抑える必要があります。

詳細については、「ユーザー固有のボキャブラリの参照」とAppleの「カスタム ボキャブラリの参照の指定」を参照してください。

アプリ固有のボキャブラリの追加

アプリ固有のボキャブラリでは、車両の種類やワークアウト名など、アプリのすべてのユーザーに知られる特定の単語とフレーズを定義します。 これらはそのアプリケーションの一部であるため、メイン アプリ バンドルの一部として AppIntentVocabulary.plist ファイルで定義されます。 さらに、これらの単語と語句はローカライズする必要があります。

アプリ固有のボキャブラリ用語は、次のいずれかのカテゴリに属している必要があります。

  • 乗車オプション。
  • ワークアウト名。

アプリ固有のボキャブラリ ファイルには、次の 2 つのルート レベル のキーが含まれています。

  • ParameterVocabulariesRequired - 適用するアプリのカスタム用語と意図パラメーターを定義します。
  • IntentPhrasesOptional - ParameterVocabulariesで定義されているカスタム用語を使用したフレーズの例が含まれます。

ParameterVocabularies 内の各エントリは、ID 文字列、用語、および用語が適用されるインテントを指定する必要があります。 さらに、1 つの用語が複数のインテントに適用される場合があります。

許容される値と必要なファイル構造の完全な一覧については、Apple の「アプリ ボキャブラリ ファイル形式リファレンス」を参照してください。

アプリ プロジェクトに AppIntentVocabulary.plist ファイルを追加するには、次を行います。

  1. ソリューション エクスプローラーでプロジェクト名を右クリックして、[追加]>[新しいファイル...]>[iOS] を選択します。

    プロパティ リストを追加します

  2. ソリューション エクスプローラーAppIntentVocabulary.plist ファイルをダブルクリックして、編集用に開きます。

  3. キーを追加するには + をクリックし、[名前]ParameterVocabularies に、[種類]Array に設定します。

    名前を ParameterVocabularies に設定し、型を配列に設定します

  4. ParameterVocabularies を展開して + ボタンをクリックし、[種類]Dictionary に設定します。

    型をディクショナリに設定します

  5. 新しいキーを追加するには + をクリックし、[名前]ParameterNames に、[種類]Array に設定します。

    名前を ParameterNames に設定し、型を配列に設定します

  6. + をクリックして、[種類]String で値が使用可能なパラメーター名の 1 である新しいキーを追加します。 INStartWorkoutIntent.workoutName の例を次に示します。

    INStartWorkoutIntent.workoutName キー

  7. ParameterVocabularies キーに [種類]ArrayParameterVocabulary キーを追加します。

    ParameterVocabularies キーに、配列型の ParameterVocabulary キーを追加します

  8. [種類]Dictionary の新しいキーを追加します。

    Visual Studio for Mac で辞書型の新しいキーを追加します。

  9. [種類]StringVocabularyItemIdentifier キーを追加し、用語の一意の ID を指定します。

    文字列型の VocabularyItemIdentifier キーを追加し、一意の ID を指定します

  10. [種類]ArrayVocabularyItemSynonyms キーを追加します。

    配列型の VocabularyItemSynonyms キーを追加します

  11. [種類]Dictionary の新しいキーを追加します。

    Visual Studio for Mac で辞書型の新しいキーをもう 1 つ追加します。

  12. [種類]String でアプリが定義している用語を含む VocabularyItemPhrase キーを追加します。

    アプリが定義している用語を使用して、文字列型の VocabularyItemPhrase キーを追加します

  13. [種類]StringVocabularyItemPronunciation キーを、用語の発音と共に追加します。

    用語の発音を使用して、文字列型の VocabularyItemPronunciation キーを追加します

  14. [種類]ArrayVocabularyItemExamples キーを追加します。

    配列型の VocabularyItemExamples キーを追加します

  15. 用語の使用例と共に、いくつかの String キーを追加します。

    Visual Studio for Mac で用語の使用例を使用して、いくつかの文字列型のキーを追加します。

  16. アプリで定義する必要があるその他のカスタム用語について、上記の手順を繰り返します。

  17. ParameterVocabularies キーの表示を折りたたみます。

  18. [種類]ArrayIntentPhrases キーを追加します。

    配列型の IntentPhrases キーを追加します

  19. [種類]Dictionary の新しいキーを追加します。

    Visual Studio for Mac で追加の辞書型の新しいキーを追加します。

  20. [種類]String で例についてのインテントをもつ IntentName キーを追加します。

    例の意図を使用して、文字列型の IntentName キーを追加します

  21. [種類]ArrayIntentExamples キーを追加します。

    配列型の IntentExamples キーを追加します

  22. 用語の使用例と共に、いくつかの String キーを追加します。

    Visual Studio for Mac で用語の使用例を使用して、いくつかの文字列型のキーを追加します。

  23. アプリが使用例を提供するために必要なインテントについて、上記の手順を繰り返します。

重要

この AppIntentVocabulary.plist は開発中にテスト デバイスで Siri に登録され、Siri がカスタム ボキャブラリを組み込むのに時間がかかる場合があります。 その結果、テスト担当者は、アプリ固有のボキャブラリが更新されたときに、そのテストの前に数分待つ必要があります。

詳細については、「アプリ固有のボキャブラリの参照」とAppleの「カスタム ボキャブラリの参照の指定」を参照してください。

Intents 拡張機能の追加

SiriKit を導入する準備ができました。開発者は、Siri 統合に必要なインテントを処理するために、1 つ (または複数) の Intents 拡張機能をソリューションに追加する必要があります。

必要な Intents 拡張機能ごとに、次の操作を行います。

  • Intents 拡張機能プロジェクトを Xamarin.iOS アプリ ソリューションに追加します。
  • Intents 拡張機能 Info.plist ファイルを構成します。
  • Intents 拡張機能の main クラスを変更します。

詳細については、「Intents 拡張機能のリファレンス」と Apple の「Intents 拡張機能の作成に関するリファレンス」を参照してください。

拡張機能の作成

ソリューションに Intents 拡張機能を追加するには、次のようにします。

  1. Solution Pad[ソリューション名] を右クリックし、[追加]>[新しいプロジェクトの追加...] を選択します。

  2. ダイアログ ボックスで [iOS]>[拡張機能]>[Intents 拡張機能] を選択し、[次へ] ボタンをクリックします。

    意図拡張機能を選択します

  3. 次に、Intents 拡張機能の [名前] を入力し、[次へ] ボタンをクリックします。

    意図拡張機能の名前を入力します。

  4. 最後に、[作成] ボタンをクリックして、Intents ト拡張機能をアプリ ソリューションに追加します。

    意図拡張機能をアプリ ソリューションに追加します。

  5. ソリューション エクスプローラーで、新しく作成された Intents 拡張機能の References フォルダーを右クリックします。 共通の共有コード ライブラリ プロジェクト (上記でアプリにより作成されたもの) の名前を確認し、[OK] ボタンをクリックします。

    共通の共有コード ライブラリ プロジェクトの名前を選択します。

アプリに必要な Intents 拡張機能の数 (上記の 「拡張機能のためのアプリの設計」セクションに基づく) だけ、これらの手順を繰り返します。

Info.plist の構成

アプリのソリューションに追加されたそれぞれの Intents 拡張機能について、アプリと協調して動作するよう、Info.plist ファイルで構成する必要があります。

他の一般的なアプリ拡張機能と同様に、アプリには既存の NSExtension キーと NSExtensionAttributes キーがあります。 Intents 拡張機能には、構成が必要な次の 2 つの新しい属性があります。

必ず構成する必要がある 2 つの新しい属性

  • IntentsSupported - 必須であり、アプリが Intents 拡張機能によるサポートを必要とする Intent クラス名の配列で構成されます。
  • IntentsRestrictedWhileLocked - 拡張機能のロック画面の動作を指定するアプリの省略可能なキーです。 これは、アプリが Intents 拡張機能から使用するためにユーザーのログインを要求する Intent クラス名の配列で構成されます。

Intents 拡張機能の Info.plist ファイルを構成するには、ソリューション エクスプローラーでダブルクリックして編集用に開きます。 次に、ソース ビューに切り替え、エディターで NSExtension キーと NSExtensionAttributes キーを展開します。

IntentsSupported キーを展開し、この拡張機能でサポートされる Intent クラスの名前を追加します。 例の MonkeyChat アプリでは、INSendMessageIntent がサポートされています。

アプリで、必要に応じて、特定のインテントを使用するためにはユーザーがデバイスにログオンしている必要がある場合は、IntentRestrictedWhileLocked キーを展開し、アクセスが制限されているインテントのクラス名を追加します。 例の MonkeyChat アプリでは、チャット メッセージを送信するにはユーザーがログインしている必要があるため、次のように INSendMessageIntent を追加しました。

使用可能な Intent ドメインの完全な一覧については、Apple の「Intent ドメイン リファレンス」を参照してください。

Main クラスの構成

次に、開発者は、Intents 拡張機能の Siri への主要なエントリ ポイントとして機能する main クラスを構成する必要があります。 これは、IINIntentHandler デリゲートに準拠する INExtension のサブクラスである必要があります。 次に例を示します。

using System;
using System.Collections.Generic;

using Foundation;
using Intents;

namespace MonkeyChatIntents
{
    [Register ("IntentHandler")]
    public class IntentHandler : INExtension, IINSendMessageIntentHandling, IINSearchForMessagesIntentHandling, IINSetMessageAttributeIntentHandling
    {
        #region Constructors
        protected IntentHandler (IntPtr handle) : base (handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
        #endregion

        #region Override Methods
        public override NSObject GetHandler (INIntent intent)
        {
            // This is the default implementation.  If you want different objects to handle different intents,
            // you can override this and return the handler you want for that particular intent.

            return this;
        }
        #endregion
        ...
    }
}

アプリが Intents 拡張機能の main クラスに実装しなければならないメソッドが 1 つだけあります。GetHandler メソッドです。 このメソッドは SiriKit によってインテントを渡され、アプリは、指定されたインテントの種類に一致するインテント ハンドラーを返す必要があります。

例の MonkeyChat アプリでは 1 つのインテントのみを処理するため、GetHandler メソッド内で自身を返しています。 拡張機能が複数のインテントを処理するとした場合、開発者はインテントの種類ごとにクラスを追加し、メソッドに渡された Intent に基づいてここでインスタンスを返します。

解決ステージの処理

解決ステージは、Intents 拡張機能が Siri から渡され、ユーザーの会話を介して設定されたパラメーターを明確にし、検証する場所です。

Siri から送信されるパラメーターそれぞれについて、Resolve メソッドがあります。 アプリでは、ユーザーから適切な回答を得るために Siri の助けが必要になる可能性があるすべてのパラメーターについて、このメソッドを実装する必要があります。

例の MonkeyChat アプリの場合、Intents 拡張機能では、メッセージの送信先として 1 人以上の受信者が必要になります。 リスト内の受信者ごとに、拡張機能は連絡先検索を実行する必要があります。その結果は、次のようになる可能性があります。

  • 一致する連絡先が 1 つだけ見つかる。
  • 一致する連絡先が 2 つ以上見つかる。
  • 一致する連絡先が見つからない。

さらに、MonkeyChat には、メッセージ本文の内容が必要です。 ユーザーがこれを指定していない場合、Siri はユーザーに内容の入力を求める必要があります。

Intents 拡張機能では、これらの各ケースを適切に処理する必要があります。

[Export ("resolveRecipientsForSearchForMessages:withCompletion:")]
public void ResolveRecipients (INSendMessageIntent intent, Action<INPersonResolutionResult []> completion)
{
    var recipients = intent.Recipients;
    // If no recipients were provided we'll need to prompt for a value.
    if (recipients.Length == 0) {
        completion (new INPersonResolutionResult [] { (INPersonResolutionResult)INPersonResolutionResult.NeedsValue });
        return;
    }

    var resolutionResults = new List<INPersonResolutionResult> ();

    foreach (var recipient in recipients) {
        var matchingContacts = new INPerson [] { recipient }; // Implement your contact matching logic here to create an array of matching contacts
        if (matchingContacts.Length > 1) {
            // We need Siri's help to ask user to pick one from the matches.
            resolutionResults.Add (INPersonResolutionResult.GetDisambiguation (matchingContacts));
        } else if (matchingContacts.Length == 1) {
            // We have exactly one matching contact
            resolutionResults.Add (INPersonResolutionResult.GetSuccess (recipient));
        } else {
            // We have no contacts matching the description provided
            resolutionResults.Add ((INPersonResolutionResult)INPersonResolutionResult.Unsupported);
        }
    }

    completion (resolutionResults.ToArray ());
}

[Export ("resolveContentForSendMessage:withCompletion:")]
public void ResolveContent (INSendMessageIntent intent, Action<INStringResolutionResult> completion)
{
    var text = intent.Content;
    if (!string.IsNullOrEmpty (text))
        completion (INStringResolutionResult.GetSuccess (text));
    else
        completion ((INStringResolutionResult)INStringResolutionResult.NeedsValue);
}

詳細については、「解決ステージ リファレンス」と Apple の「インテントの解決と処理のリファレンス」を参照してください。

確認ステージの処理

確認ステージは、Intents 拡張機能がユーザーの要求を満たすためにすべての情報が揃っていることを確認する場所です。 アプリは、Siri に何が起こっているのかをサポートするすべての詳細と共に確認を送信して、これが意図したアクションであることをユーザーに確認する必要があります。

[Export ("confirmSendMessage:completion:")]
public void ConfirmSendMessage (INSendMessageIntent intent, Action<INSendMessageIntentResponse> completion)
{
    // Verify user is authenticated and the app is ready to send a message.
    ...

    var userActivity = new NSUserActivity (nameof (INSendMessageIntent));
    var response = new INSendMessageIntentResponse (INSendMessageIntentResponseCode.Ready, userActivity);
    completion (response);
}

詳細については、「確認ステージのリファレンス」を参照してください。

インテントの処理

これは、Intents 拡張機能が実際にユーザーの要求を満たすためのタスクを実行し、結果を Siri に渡して、ユーザーに知らせることができるようにする箇所です。

public void HandleSendMessage (INSendMessageIntent intent, Action<INSendMessageIntentResponse> completion)
{
    // Implement the application logic to send a message here.
    ...

    var userActivity = new NSUserActivity (nameof (INSendMessageIntent));
    var response = new INSendMessageIntentResponse (INSendMessageIntentResponseCode.Success, userActivity);
    completion (response);
}

public void HandleSearchForMessages (INSearchForMessagesIntent intent, Action<INSearchForMessagesIntentResponse> completion)
{
    // Implement the application logic to find a message that matches the information in the intent.
    ...

    var userActivity = new NSUserActivity (nameof (INSearchForMessagesIntent));
    var response = new INSearchForMessagesIntentResponse (INSearchForMessagesIntentResponseCode.Success, userActivity);

    // Initialize with found message's attributes
    var sender = new INPerson (new INPersonHandle ("sarah@example.com", INPersonHandleType.EmailAddress), null, "Sarah", null, null, null);
    var recipient = new INPerson (new INPersonHandle ("+1-415-555-5555", INPersonHandleType.PhoneNumber), null, "John", null, null, null);
    var message = new INMessage ("identifier", "I am so excited about SiriKit!", NSDate.Now, sender, new INPerson [] { recipient });
    response.Messages = new INMessage [] { message };
    completion (response);
}

public void HandleSetMessageAttribute (INSetMessageAttributeIntent intent, Action<INSetMessageAttributeIntentResponse> completion)
{
    // Implement the application logic to set the message attribute here.
    ...

    var userActivity = new NSUserActivity (nameof (INSetMessageAttributeIntent));
    var response = new INSetMessageAttributeIntentResponse (INSetMessageAttributeIntentResponseCode.Success, userActivity);
    completion (response);
}

詳細については、「処理ステージのリファレンス」を参照してください。

Intents UI 拡張機能の追加

オプションの Intents UI 拡張機能は、アプリの UI とブランドを Siri エクスペリエンスに持ち込み、ユーザーがアプリと繋がっていると感じさせる機会を提供します。 この拡張機能を使用すると、アプリはブランドだけでなく、ビジュアルやその他の情報をトランスクリプトに取り込むことができます。

意図 UI 拡張機能の出力例

Intents 拡張機能と同様に、開発者は Intents UI 拡張機能について次の手順を実行します。

  • Intents UI 拡張機能プロジェクトを Xamarin.iOS アプリ ソリューションに追加します。
  • Intents UI 拡張機能 Info.plist ファイルを構成します。
  • Intents UI 拡張機能の main クラスを変更します。

詳細については、「Intents UI 拡張機能のリファレンス」と Apple の「カスタム インターフェイスの提供のリファレンス」を参照してください。

拡張機能の作成

ソリューションに Intents UI 拡張機能を追加するには、次のようにします。

  1. Solution Pad[ソリューション名] を右クリックし、[追加]>[新しいプロジェクトの追加...] を選択します。

  2. ダイアログ ボックスで [iOS]>[拡張機能]>[Intents UI 拡張機能] を選択し、[次へ] ボタンをクリックします。

    意図 UI 拡張機能を選択します

  3. 次に、Intents 拡張機能の [名前] を入力し、[次へ] ボタンをクリックします。

    Visual Studio for Mac で意図拡張機能の名前を入力します。

  4. 最後に、[作成] ボタンをクリックして、Intents ト拡張機能をアプリ ソリューションに追加します。

    Visual Studio for Mac のアプリ ソリューションに意図拡張機能を追加します。

  5. ソリューション エクスプローラーで、新しく作成された Intents 拡張機能の References フォルダーを右クリックします。 共通の共有コード ライブラリ プロジェクト (上記でアプリにより作成されたもの) の名前を確認し、[OK] ボタンをクリックします。

    Visual Studio for Mac で共通の共有コード ライブラリ プロジェクトの名前を選択します。

Info.plist の構成

Intents UI 拡張機能の Info.plist ファイルを構成して、アプリで動作するようにします。

他の一般的なアプリ拡張機能と同様に、アプリには既存の NSExtension キーと NSExtensionAttributes キーがあります。 Intents 拡張機能には、構成が必要な次の 1 つの新しい属性があります。

必ず構成する必要がある 1 つの新しい属性

IntentsSupported - 必須であり、アプリが Intents 拡張機能によるサポートを必要とする Intent クラス名の配列で構成されます。

Intents UI 拡張機能の Info.plist ファイルを構成するには、ソリューション エクスプローラーでダブルクリックして編集用に開きます。 次に、ソース ビューに切り替え、エディターで NSExtension キーと NSExtensionAttributes キーを展開します。

エディターの NSExtension キーと NSExtensionAttributes キー。

IntentsSupported キーを展開し、この拡張機能でサポートされる Intent クラスの名前を追加します。 例の MonkeyChat アプリでは、INSendMessageIntent がサポートされています。

使用可能な Intent ドメインの完全な一覧については、Apple の「Intent ドメイン リファレンス」を参照してください。

Main クラスの構成

Intents UI 拡張機能の Siri への主要なエントリ ポイントとして機能する main クラスを構成します。 これは、IINUIHostedViewController インターフェイスに準拠する UIViewController のサブクラスである必要があります。 次に例を示します。

using System;
using Foundation;
using CoreGraphics;
using Intents;
using IntentsUI;
using UIKit;

namespace MonkeyChatIntentsUI
{
    public partial class IntentViewController : UIViewController, IINUIHostedViewControlling
    {
        #region Constructors
        protected IntentViewController (IntPtr handle) : base (handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Do any required interface initialization here.
        }

        public override void DidReceiveMemoryWarning ()
        {
            // Releases the view if it doesn't have a superview.
            base.DidReceiveMemoryWarning ();

            // Release any cached data, images, etc that aren't in use.
        }
        #endregion

        #region Public Methods
        [Export ("configureWithInteraction:context:completion:")]
        public void Configure (INInteraction interaction, INUIHostedViewContext context, Action<CGSize> completion)
        {
            // Do configuration here, including preparing views and calculating a desired size for presentation.

            if (completion != null)
                completion (DesiredSize ());
        }

        [Export ("desiredSize:")]
        public CGSize DesiredSize ()
        {
            return ExtensionContext.GetHostedViewMaximumAllowedSize ();
        }
        #endregion
    }
}

Siri は、INInteraction クラス インスタンスを Intents UI 拡張機能内の UIViewController インスタンスの Configure メソッドに渡します。

この INInteraction オブジェクトは、拡張機能に次の 3 つの重要な情報を提供します。

  1. 処理中の Intent オブジェクト。
  2. Intents 拡張機能の Confirm メソッドと Handle メソッドからの Intent Response オブジェクト。
  3. アプリと Siri の間の対話の状態を定義する Interaction State。

この UIViewController インスタンスは、Siri との対話の原則クラスであり、UIViewController から継承されるため、UIKit のすべての機能にアクセスできます。

Siri が UIViewControllerConfigure メソッドを呼び出すと、ビュー コントローラーが Siri Snippit と Maps Card のどちらでホストされるかを示すビュー コンテキストで渡されます。

Siri は、アプリが構成を完了したときに、アプリがビューの目的のサイズを返すために必要な完了ハンドラーも渡します。

iOS Designer で UI を設計する

iOS Designer で Intents UI 拡張機能のユーザー インターフェイスをレイアウトします。 ソリューション エクスプローラーで拡張機能の MainInterface.storyboard ファイルをダブルクリックして、編集用に開きます。 必要なすべての UI 要素をドラッグしてユーザー インターフェイスを構築し、変更を保存します。

重要

UIButtonsUITextFields などの対話型要素は、Intents UI 拡張機能の UIViewController に追加できますが、非対話型での Intents UI は厳密に禁止されており、ユーザーはそれらを操作できません。

ユーザー インターフェイスを接続する

iOS Designer で作成された Intents UI 拡張機能のユーザー インターフェイスを使用して、UIViewController サブクラスを編集し、次のように Configure メソッドをオーバーライドします。

[Export ("configureWithInteraction:context:completion:")]
public void Configure (INInteraction interaction, INUIHostedViewContext context, Action<CGSize> completion)
{
    // Do configuration here, including preparing views and calculating a desired size for presentation.
    ...

    // Return desired size
    if (completion != null)
        completion (DesiredSize ());
}

[Export ("desiredSize:")]
public CGSize DesiredSize ()
{
    return ExtensionContext.GetHostedViewMaximumAllowedSize ();
}

既定の Siri UI のオーバーライド

Intents UI 拡張機能は、UI の上部にあるアプリ アイコンや名前などの他の Siri コンテンツと共に常に表示されるか、インテントに基づいてボタン ([送信] や [キャンセル] など) が下部に表示されます。

Siri が既定でユーザーに表示しているメッセージングやマップなどの情報を、アプリが置き換えられる場合がいくつかあります。この場合、アプリは、既定のエクスペリエンスをそのアプリに合わせて調整されたエクスペリエンスに置き換えられます。

Intents UI 拡張機能で既定の Siri UI の要素をオーバーライドする必要がある場合、UIViewController サブクラスは IINUIHostedViewSiriProviding インターフェイスを実装し、特定のインターフェイス要素を表示することをオプトインする必要があります。

次のコードを UIViewController サブクラスに追加して、Intents UI 拡張機能にメッセージの内容が既に表示されていることを Siri に伝えます。

public bool DisplaysMessage {
    get {return true;}
}

考慮事項

Apple では、Intents UI 拡張機能を設計して実装する際に、開発者が次の事項を考慮するよう提案しています。

  • メモリ使用量を意識する - Intents UI 拡張機能は一時的なもので、短時間しか表示されないため、システムでは、完全なアプリで使用されるよりも厳密なメモリ制約が適用されます。
  • 最小ビュー サイズと最大ビュー サイズを考慮する - Intents UI 拡張機能がすべての iOS デバイスの種類、サイズ、向きに適していることを確認します。 さらに、アプリが Siri に送り返す目的のサイズを許可できない場合があります。
  • 柔軟なアダプティブ レイアウト パターンを使用する - 繰り返しになりますが、すべてのデバイスで UI が適切に表示されるようにします。

まとめ

この記事では、SiriKit について説明し、それを Xamarin.iOS アプリに追加して、iOS デバイス上で Siri と Maps アプリを使用してユーザーがアクセスできるサービスを提供する方法を示しました。