Xamarin.iOS 中的 Siri 快捷方式

iOS 10 中,Apple 引進 SiriKit,讓您能夠建置與 Siri 互動的訊息、VoIP 通話、付款、鍛煉、乘坐預約和相片搜尋應用程式。

iOS 11 中,SiriKit 已獲得更多應用程式類型的支援,並提升 UI 自定義的彈性。

iOS 12 新增 Siri 快捷方式,允許所有類型的應用程式向 Siri 公開其功能。 Siri 瞭解特定應用程式型工作與使用者最相關的時機,並使用此知識透過 快捷方式建議潛在動作。 點選快捷方式,或使用語音命令叫用它,將會開啟應用程式或執行背景工作。

快捷方式應該用來加速使用者完成一般工作的能力– 在許多情況下,甚至不需要開啟有問題的應用程式。

範例應用程式:湯 Chef

若要進一步瞭解 Siri 快捷方式,請參閱 湯廚師 範例應用程式。 湯廚師可讓使用者從虛構的湯餐廳訂購訂單、檢視其訂單歷程記錄,以及定義在與 Siri 互動訂購湯時要使用的片語。

提示

在 iOS 12 模擬器或裝置上測試湯 Chef 之前,請啟用下列兩個設定,在偵錯快捷方式時很有用:

  • 設定 應用程式中,啟用開發人員>顯示最近的快捷方式
  • 設定 應用程式中,啟用 [鎖定畫面上的開發人員>顯示捐款]。

這些偵錯設定可讓您輕鬆地在 iOS 鎖定畫面和搜尋畫面上尋找最近建立的快捷方式(而不是預測的)。

若要使用範例應用程式:

  • 在 iOS 12 模擬器或 裝置上安裝並執行湯 Chef 範例應用程式。
  • +按兩下右上角的按鈕以建立新訂單。
  • 選取湯的類型、指定數量和選項,然後點選 [下單]。
  • 在 [ 訂單歷程記錄] 畫面上,點選新建立的訂單以檢視其詳細數據。
  • 在訂單詳細數據畫面底部,點選 [新增至 Siri]。
  • 錄製語音片語以與訂單產生關聯,然後點選 [完成]。
  • 將湯廚師最小化、叫用 Siri,然後使用您錄製的語音片語再次下單。
  • Siri 完成訂單之後,請重新開啟湯廚師,並注意到新訂單會列在 [訂單歷程記錄 ] 畫面上。

範例應用程式示範如何:

Info.plist 和 Entitlements.plist

在深入探索湯 Chef 程式代碼之前,請先看看其 Info.plistEntitlements.plist 檔案。

Info.plist

湯Chef 專案中的 Info.plist 檔案會將套件組合識別元com.xamarin.SoupChef定義為 。 此套件組合標識碼將作為本檔稍後討論之意圖和意圖 UI 延伸模組套件組合識別碼的前置詞。

Info.plist 檔案也包含下列專案:

<key>NSUserActivityTypes</key>
<array>
    <string>OrderSoupIntent</string>
    <string>com.xamarin.SoupChef.viewMenu</string>
</array>

這個 NSUserActivityTypes 機碼/值組表示湯廚師知道如何處理 OrderSoupIntent,以及 NSUserActivity 具有 ActivityType “com.xamarin.湯Chef.viewMenu” 的 。

在 中處理傳遞至應用程式本身的活動和自定義意圖,與其擴充 AppDelegateUIApplicationDelegateContinueUserActivity 功能相反。

Entitlements.plist

SoupChef 專案中的 Entitlements.plist 檔案包含下列專案:

<key>com.apple.security.application-groups</key>
<array>
    <string>group.com.xamarin.SoupChef</string>
</array>
<key>com.apple.developer.siri</key>
<true/>

此組態表示應用程式使用 「group.com.xamarin.SoupChef」 應用程式群組。 SoupChefIntents 應用程式延伸模組會使用相同的應用程式群組,這可讓兩個項目共用NSUserDefaults 數據。

com.apple.developer.siri 碼表示應用程式與 Siri 互動。

注意

湯切夫項目的組建組態會將自定義權利設定Entitlements.plist

使用 NSUserActivity 快捷方式開啟應用程式

若要建立可開啟應用程式以顯示特定內容的快捷方式,請建立 NSUserActivity ,並將它附加至您想要開啟快捷方式之畫面的檢視控制器。

設定 NSUserActivity

在功能表畫面上, SoupMenuViewController 建立 NSUserActivity 並將它指派給檢視控制器的 UserActivity 屬性:

public override void ViewDidLoad()
{
    base.ViewDidLoad();
    UserActivity = NSUserActivityHelper.ViewMenuActivity;
}

設定 屬性會將UserActivity活動捐贈給 Siri。 從這項捐贈中,Siri 會取得有關使用者何時和何處相關活動的資訊,並學會在未來進一步建議。

NSUserActivityHelper是湯Chef解決方案中包含的公用程式類別,位於湯基特類別庫中。 它會建立 NSUserActivity 並設定與 Siri 和搜尋相關的各種屬性:

public static string ViewMenuActivityType = "com.xamarin.SoupChef.viewMenu";

public static NSUserActivity ViewMenuActivity {
    get
    {
        var userActivity = new NSUserActivity(ViewMenuActivityType)
        {
            Title = NSBundleHelper.SoupKitBundle.GetLocalizedString("ORDER_LUNCH_TITLE", "View menu activity title"),
            EligibleForSearch = true,
            EligibleForPrediction = true
        };

        var attributes = new CSSearchableItemAttributeSet(NSUserActivityHelper.SearchableItemContentType)
        {
            ThumbnailData = UIImage.FromBundle("tomato").AsPNG(),
            Keywords = ViewMenuSearchableKeywords,
            DisplayName = NSBundleHelper.SoupKitBundle.GetLocalizedString("ORDER_LUNCH_TITLE", "View menu activity title"),
            ContentDescription = NSBundleHelper.SoupKitBundle.GetLocalizedString("VIEW_MENU_CONTENT_DESCRIPTION", "View menu content description")
        };
        userActivity.ContentAttributeSet = attributes;

        var phrase = NSBundleHelper.SoupKitBundle.GetLocalizedString("ORDER_LUNCH_SUGGESTED_PHRASE", "Voice shortcut suggested phrase");
        userActivity.SuggestedInvocationPhrase = phrase;
        return userActivity;
    }
}

請特別注意下列功能:

處理 NSUserActivity 快捷方式

若要處理 NSUserActivity 使用者叫用的快捷方式,iOS 應用程式必須覆寫 ContinueUserActivity 類別的 AppDelegate 方法,並根據 ActivityType 傳入 NSUserActivity 物件的欄位回應:

public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
    // ...
    else if (userActivity.ActivityType == NSUserActivityHelper.ViewMenuActivityType)
    {
        HandleUserActivity();
        return true;
    }
    // ...
}

這個方法會呼叫 HandleUserActivity,它會尋找功能表畫面的 Segue 並叫用它:

void HandleUserActivity()
{
    var rootViewController = Window?.RootViewController as UINavigationController;
    var orderHistoryViewController = rootViewController?.ViewControllers?.FirstOrDefault() as OrderHistoryTableViewController;
    if (orderHistoryViewController is null)
    {
        Console.WriteLine("Failed to access OrderHistoryTableViewController.");
        return;
    }
    var segue = OrderHistoryTableViewController.SegueIdentifiers.SoupMenu;
    orderHistoryViewController.PerformSegue(segue, null);
}

將片語指派給 NSUserActivity

若要將片語指派給 NSUserActivity,請開啟 iOS 設定 應用程式,然後選擇 [Siri & 搜尋>我的快捷方式]。 然後,選取快捷方式(在此案例中為「訂購午餐」),並記錄片語。

叫用 Siri 並使用這個片語會將湯廚師開啟至功能表畫面。

使用自定義意圖快捷方式來執行工作

定義自定義意圖

若要提供快捷方式,讓用戶能夠快速完成與您的應用程式相關的特定工作,請建立自定義意圖。 自定義意圖代表使用者可能想要完成的工作、與該工作相關的參數,以及工作執行所產生的潛在回應。 根據自定義意圖的定義方式,叫用它可以開啟您的應用程式或執行背景工作。

使用 Xcode 10 建立自定義意圖。 在湯Chef 存放庫中,自定義意圖定義於專案 OrderSoupIntentCodeGenObjective-C 中。 開啟此專案,然後選取 Project Navigator 中的 Intents.intentdefinition 檔案,以檢視 OrderSoup 意圖。

請注意下列功能:

  • 意圖具有 OrderCategory。 有各種預先定義的類別可用於自定義意圖;選取最符合您自定義意圖將啟用之工作的工作。 由於此解決方案是湯訂購應用程式, OrderSoupIntent 會使用 Order
  • [ 確認] 複選框指出 Siri 是否在執行工作之前,必須要求確認。 針對湯 Chef 中的 Order 湯意圖,因為使用者正在購買,因此會啟用此選項。
  • .intentdefinition 檔案的 Parameters 區段會定義與快捷方式相關的參數。 若要訂購湯,湯廚師必須知道湯的類型、其數量,以及任何相關聯的選項。 每個參數都有類型;無法以預先定義型別表示的參數會設定為 Custom
  • 快捷方式 類型 介面描述 Siri 在建議快捷方式時可以使用的各種參數組合。 相關聯的 [標題 ] 和 [子標題 ] 區段可讓您定義 Siri 在向使用者呈現建議快捷方式時將使用的訊息。
  • 應該針對任何可以執行的快捷方式選取 [支援背景執行] 複選框,而不需開啟應用程式以進行進一步的用戶互動。

定義自定義意圖回應

OrderSoup 意圖下方的 Response 專案代表湯訂單所產生的潛在回應。

OrderSoup 意圖的回應定義中,請注意下列功能:

  • 回應的屬性可用來自定義傳回給使用者的訊息。 OrderSoup 意圖回應具有waitTime 屬性。
  • 回應 範本 會指定各種成功和失敗訊息,這些訊息可用來指出意圖工作完成後的狀態。
  • 應該針對指出成功的響應選取 [ 成功 ] 複選框。
  • OrderSoupIntent 成功回應會使用waitTime 屬性來提供友好且實用的訊息,描述湯訂單何時就緒。

產生自定義意圖的程序代碼

建置包含此自定義意圖定義的 Xcode 專案會導致 Xcode 產生程式代碼,以程式設計方式與自定義意圖及其響應互動。

若要檢視這個產生的程式代碼:

  • 開啟 AppDelegate.m
  • 將匯入新增至自訂意圖的頭檔: #import "OrderSoupIntent.h"
  • 在類別中的任何方法中,新增 對 的 OrderSoupIntent參考。
  • 以滑鼠右鍵按下 OrderSoupIntent 並選擇 [ 跳至定義]。
  • 以滑鼠右鍵按下新開啟的檔案 OrderSoupIntent.h,然後選取 [在 Finder 中顯示]。
  • 此動作會開啟包含 .h.m 檔案的 Finder 視窗,其中包含產生的程序代碼。

此產生的程式代碼包括:

  • OrderSoupIntent – 表示自定義意圖的類別。
  • OrderSoupIntentHandling – 一種通訊協定,定義將用來確認應該執行意圖的方法,以及實際執行意圖的方法。
  • OrderSoupIntentResponseCode – 定義各種回應狀態的列舉。
  • OrderSoupIntentResponse – 類別,表示意圖執行的回應。

建立自定義意圖的系結

若要在 Xamarin.iOS 應用程式中使用 Xcode 所產生的程式代碼,請為其建立 C# 系結。

建立靜態庫和 C# 系結定義

在湯Chef 存放庫中,查看 OrderSoupIntentStaticLib 資料夾,然後開啟 OrderSoupIntentStaticLib.xcodeproj Xcode 專案。

Cocoa Touch 靜態庫 專案包含 Xcode 所產生的 OrderSoupIntent.hOrderSoupIntent.m 檔案。

設定靜態庫專案組建設定

在 Xcode 專案導覽器中,選取最上層專案 OrderSoupIntentStaticLib,然後流覽至 [建置階段 > 編譯來源]。 請注意, OrderSoupIntent.m (匯入 OrderSoupIntent.h) 列在這裡。 在 [鏈接二進位檔與連結庫] 中,請注意 會包含 Intents.frameworkFoundation.framework 。 使用這些設定,架構將會正確建置。

建置靜態庫併產生 C# 系結定義

若要建置靜態庫併為其產生 C# 系結定義,請遵循下列步驟:

  • 安裝 Objective Sharpie,此工具用來從 Xcode 所建立的 .h.m 檔案產生系結定義。

  • 將您的系統設定為使用 Xcode 10 命令列工具

    警告

    更新選取 的命令行工具 會影響系統上所有已安裝的 Xcode 版本。 當您使用湯 Chef 範例應用程式完成時,請務必將此設定還原為其原始組態。

    • 在 Xcode 中,選擇 [Xcode > 喜好>設定位置],並將 [命令行工具] 設定為系統上可用的最新 Xcode 10 安裝。
  • 在終端機中, cd 移至 OrderSoupIntentStaticLib 目錄。

  • 輸入 make,其會建置:

    • 靜態庫 libOrderSoupIntentStaticLib.a
    • bo 輸出目錄中,C# 系結定義:
      • ApiDefinitions.cs
      • StructsAndEnums.cs

依賴此靜態庫及其相關聯繫結定義的 OrderSoupIntentBindings 專案會自動建置這些專案。 不過,手動執行上述程式可確保其如預期般建置。

如需建立靜態庫和使用 Objective Sharpie 建立 C# 系結定義的詳細資訊,請參閱 系結 iOS Objective-C 連結庫 逐步解說。

建立系結連結庫

建立靜態庫和 C# 系結定義之後,Xamarin.iOS 專案中取用 Xcode 產生的意圖相關程式碼所需的其餘部分是系結連結庫。

在湯 Chef 存放庫中,開啟SoupChef.sln檔案。 除此之外,此解決方案還 包含 OrderSoupIntentBinding,這是稍早所產生靜態庫的系結連結庫。

請注意,此專案包含:

  • ApiDefinitions.cs – Objective Sharpie 稍早產生的檔案,並新增至此專案。 此檔案的 建置動作 設定為 ObjcBindingApiDefinition

  • StructsAndEnums.cs – Objective Sharpie 稍早產生的另一個檔案,並新增至此專案。 此檔案的 建置動作 設定為 ObjcBindingCoreSource

  • libOrderSoupIntentStaticLib.a 的原生參考,這是稍早建置的靜態庫。 更新原生參考屬性,並指定下列值:

    1. Frameworks = Foundation Intents
    2. Smart Link = On
    3. 強制載入 = On
    4. Kind = Static

注意

ApiDefinitions.cs和StructsAndEnums.cs都包含屬性,例如 [Watch (5,0), iOS (12,0)]。 Objective Sharpie 所產生的這些屬性已標記為批註,因為此專案並非必要屬性。

如需建立 C# 系結連結庫的詳細資訊,請參閱 系結 iOS Objective-C 連結庫 逐步解說。

請注意,湯Chef 專案包含 OrderSoupIntentBinding參考,這表示它現在可以在 C# 中存取它所包含的類別、介面和列舉:

  • OrderSoupIntent
  • OrderSoupIntentHandling
  • OrderSoupIntentResponse
  • OrderSoupIntenseResponseCode

建立 Swift 架構

根據預設,使用原生項目的語言,Xcode 會產生意圖定義機器碼。 如果您在 Swift 專案中定義 Intents.intentdefinition 檔案,Xcode 將會產生具有所有必要類別的單一 Swift 檔案,您可以使用這個檔案來建立 Swift 架構。

提示

您可以在 Xcode 組建設定中,為產生的意圖程式代碼選取所需的語言。 移至 [意圖目標>組建 設定 > 意圖定義編譯程式 - 程式代碼產生],然後選取 Swift 或 Objective-C。 您也可以讓它保持自動,以符合您的目標語言。

建立 Swift 架構的程式類似於先前所述的程式:

  1. 建立新的 Swift 架構專案。
  2. 將具有意圖程式代碼的自動產生的 Swift 檔案複製到此專案,您可以找到此檔案,如這裡所述
  3. Objective-C開啟橋接標頭,因此架構會自動產生與 sharpie 標頭檔所需的 Objective-C 。

建置架構之後,請遵循 先前所述的相同步驟 來建立 Xamarin 系結。 您可以在這裡深入瞭解如何建立 Swift 架構的系結

將意圖定義檔新增至您的解決方案

在 C# 湯Chef 解決方案中 ,湯基 特專案包含應用程式與其延伸模組之間共用的程序代碼。 Intents.intentdefinition 檔案已放在湯基Base.lproj 目錄中,且其具有內容的建置動作。 建置程式會將此檔案複製到湯 Chef 應用程式套件組合中,應用程式必須正確運作。

捐贈意圖

為了讓 Siri 建議快捷方式,必須先瞭解快捷方式何時相關。

為了給予 Siri 這個理解,湯廚師 每次使用者放置湯訂單時,都會向 Siri 捐贈 意圖。 根據這項捐贈 -- 當捐贈時,捐贈地點,它所包含的參數 – Siri 會瞭解未來何時建議快捷方式。

湯切夫 使用 SoupOrderDataManager 類別來捐贈。 呼叫 以為使用者下湯訂單時, PlaceOrder 方法會接著呼叫 DonateInteraction

void DonateInteraction(Order order)
{
    var interaction = new INInteraction(order.Intent, null);
    interaction.Identifier = order.Identifier.ToString();
    interaction.DonateInteraction((error) =>
    {
        // ...
    });
}

擷取意圖之後,它會包裝在 中 INInteractionINInteraction已提供Identifier 符合訂單的唯一標識碼(刪除不再有效的意圖捐贈時,會很有説明)。 然後,互動會捐贈給 Siri。

呼叫 order.Intent getter 會擷取 OrderSoupIntent 代表訂單的 ,方法是設定其 QuantitySoupOptions和 影像,以及當用戶記錄 Siri 與意圖關聯的片語時,用來做為建議的調用片語:

public OrderSoupIntent Intent
{
    get
    {
        var orderSoupIntent = new OrderSoupIntent();
        orderSoupIntent.Quantity = new NSNumber(Quantity);
        orderSoupIntent.Soup = new INObject(MenuItem.ItemNameKey, MenuItem.LocalizedString);

        var image = UIImage.FromBundle(MenuItem.IconImageName);
        if (!(image is null))
        {
            var data = image.AsPNG();
            orderSoupIntent.SetImage(INImage.FromData(data), "soup");
        }

        orderSoupIntent.Options = MenuItemOptions
            .ToArray<MenuItemOption>()
            .Select<MenuItemOption, INObject>(arg => new INObject(arg.Value, arg.LocalizedString))
            .ToArray<INObject>();

        var comment = "Suggested phrase for ordering a specific soup";
        var phrase = NSBundleHelper.SoupKitBundle.GetLocalizedString("ORDER_SOUP_SUGGESTED_PHRASE", comment);
        orderSoupIntent.SuggestedInvocationPhrase = String.Format(phrase, MenuItem.LocalizedString);

        return orderSoupIntent;
    }
}

拿掉無效的捐款

請務必移除不再有效的捐款,讓 Siri 不會提供無益或令人困惑的快捷方式建議。

在 [湯廚師] 中 ,[設定功能表 ] 畫面可用來將功能表項標示為無法使用。 Siri 不應該再建議快捷方式來排序無法使用的功能表項,因此刪除 RemoveDonation 不再可用的功能表項捐款的方法 SoupMenuManager 。 應用程式會透過下列方式實作這項功能:

  • 尋找與目前無法使用功能表項相關聯的訂單。
  • 擷取其標識碼。
  • 刪除具有相同標識碼的互動。
void RemoveDonation(MenuItem menuItem)
{
    if (!menuItem.IsAvailable)
    {
        Order[] orderHistory = OrderManager?.OrderHistory.ToArray<Order>();
        if (orderHistory is null)
        {
            return;
        }

        string[] orderIdentifiersToRemove = orderHistory
            .Where<Order>((order) => order.MenuItem.ItemNameKey == menuItem.ItemNameKey)
            .Select<Order, string>((order) => order.Identifier.ToString())
            .ToArray<string>();

        INInteraction.DeleteInteractions(orderIdentifiersToRemove, (error) =>
        {
            if (!(error is null))
            {
                Console.WriteLine($"Failed to delete interactions with error {error.ToString()}");
            }
            else
            {
                Console.WriteLine("Successfully deleted interactions");
            }
        });
    }
}

驗證成功的捐款

解決方案包含多個專案和特定組態。 在某些情況下,應用程式可能會因為設定不完整而當機,在其他情況下,應用程式可能會以無訊息方式無法捐贈互動。 請務必驗證成功的捐款,而 iOS 開發人員設定有助於它。 瀏覽至 設定 > 開發人員,並啟用下列開發人員選項,以查看最近的捐款和快捷方式:

  • 顯示最近的快捷方式
  • 在鎖定畫面上顯示捐款

啟用之後,每個成功的捐贈都會出現在鎖定畫面上,並在 Siri 建議選項下方顯示。 如果在執行應用程式之後,您看不到該處的捐款,請檢閱下列疑難解答案例:

  1. 應用程式無法建立 OrderSoupIntent ,並出現下列錯誤:

    無法建立 'NativeLibrary.OrderSoupIntent' 類型的原生實例:尚未載入原生類別。

    此錯誤表示 Xamarin 無法透過 Xamarin 系結載入原生類別。 若要修正此問題,請確認原生連結庫包含系結項目所參考的必要程序代碼,並已設定適當的旗標,如這裡所述,將Force Load旗標設定為 On

  2. 應用程式無法初始化意圖類別載入的原生實例,並出現下列錯誤:

    無法初始化類型 'NativeLibrary.OrderSoupIntent' 的實例:傳回 nil 的原生 'init' 方法。

    此問題與遺漏的意圖定義檔案有關。 Xamarin 應用程式應該包含具有 Content 類型的原始意圖定義檔,如這裡所述

  3. 應用程式會建立意圖並呼叫捐贈方法,而不會當機,但控制台輸出會顯示未知意圖類型的警告,而且不會進行捐贈:

    無法捐贈沒有有效快捷鍵類型的 OrderSoupIntent 互動

    若要修正意圖必須在 plist 中正確定義的問題,必須透過項目設定啟用並選取 Siri 權利以供目前的組建組態使用。

    應用程式的 info.plist

    <key>NSUserActivityTypes</key>
    <array>
        <string>ScheduleMeetingIntent</string>
    </array>
    

    具有 Siri 功能之應用程式的 Entitlements.plist

    <key>com.apple.developer.siri</key>
    <true/>
    

    應針對目標組建組態選取自定義權利。 移至 [項目設定>] [建>置 iOS 套件組合簽署],並將 [自定義權利] 設定包含所需權利的權利的 Entitlements.plist 檔案。

建立意圖延伸模組

當 Siri 叫用意圖時執行的程式代碼會放在意圖延伸模組中,其可新增為與湯 Chef 等現有 Xamarin.iOS 應用程式相同的解決方案的新專案。 在湯Chef 解決方案中,延伸模組稱為湯ChefIntents

湯ChefIntents – Info.plist 和 Entitlements.plist

SoupChefIntents – Info.plist

SoupChefIntents 專案中的 Info.plist 會將套件組合識別元com.xamarin.SoupChef.SoupChefIntents定義為 。

Info.plist 檔案也包含下列專案:

<key>NSExtension</key>
<dict>
    <key>NSExtensionAttributes</key>
    <dict>
        <key>IntentsRestrictedWhileLocked</key>
        <array/>
        <key>IntentsSupported</key>
        <array>
            <string>OrderSoupIntent</string>
        </array>
        <key>IntentsRestrictedWhileProtectedDataUnavailable</key>
        <array/>
    </dict>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.intents-service</string>
    <key>NSExtensionPrincipalClass</key>
    <string>IntentHandler</string>
</dict>

在上述 Info.plist 中:

  • IntentsRestrictedWhileLocked 列出解除鎖定裝置時要處理的意圖。
  • IntentsSupported 列出此延伸模組所處理的意圖。
  • NSExtensionPointIdentifier 指定應用程式延伸模組的類型。 如需詳細資訊,請參閱 Apple的檔
  • NSExtensionPrincipalClass 指定應該用來處理此延伸模組所支援意圖的類別。
湯ChefIntents – Entitlements.plist

湯ChefIntents 專案中的 Entitlements.plist 具有應用程式群組功能。 這項功能設定為使用與 湯Chef 專案相同的應用程式群組:

<key>com.apple.security.application-groups</key>
<array>
    <string>group.com.xamarin.SoupChef</string>
</array>

湯 Chef 會使用 NSUserDefaults保存數據。 為了在應用程式與應用程式延伸模組之間共用數據,他們會在其 Entitlements.plist 檔案中參考相同的應用程式群組。

注意

SoupChefIntents 專案的組建組態會將自定義權利設定Entitlements.plist

處理 OrderSoupIntent 背景工作

意圖延伸模組會根據自定義意圖執行快捷方式的必要背景工作。

Siri 會呼叫 GetHandler 類別的 IntentHandler 方法(定義於 Info.plist 中為 NSExtensionPrincipalClass,以取得擴充 OrderSoupIntentHandling的類別實例,可用來處理 OrderSoupIntent

[Register("IntentHandler")]
public class IntentHandler : INExtension
{
    public override NSObject GetHandler(INIntent intent)
    {
        if (intent is OrderSoupIntent)
        {
            return new OrderSoupIntentHandler();
        }
        throw new Exception("Unhandled intent type: ${intent}");
    }

    protected IntentHandler(IntPtr handle) : base(handle) { }
}

OrderSoupIntentHandler,定義於共用程式代碼的 湯基特 專案中,會實作兩個重要的方法:

  • ConfirmOrderSoup – 確認是否應該實際執行與意圖相關聯的工作
  • HandleOrderSoup – 藉由呼叫傳入的完成處理程式來放置湯順序並回應使用者

處理開啟應用程式的 OrderSoupIntent

應用程式必須正確處理未在背景執行的意圖。 在的 方法AppDelegateContinueUserActivity,這些意圖的處理方式與NSUserActivity快捷方式相同:

public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
    var intent = userActivity.GetInteraction()?.Intent as OrderSoupIntent;
    if (!(intent is null))
    {
        HandleIntent(intent);
        return true;
    }
    // ...
}  

提供自定義意圖的使用者介面

意圖UI延伸模組提供意圖延伸模組的自訂使用者介面。 在湯Chef 解決方案中湯ChefIntentsUI 是意圖UI延伸模組,可提供湯ChefIntents的介面

SoupChefIntentsUI – Info.plist 和 Entitlements.plist

SoupChefIntentsUI – Info.plist

SoupChefIntentsUI 專案中的 Info.plist 會將套件組合識別碼com.xamarin.SoupChef.SoupChefIntentsui定義為 。

Info.plist 檔案也包含下列專案:

<key>NSExtension</key>
<dict>
    <key>NSExtensionAttributes</key>
    <dict>
        <key>IntentsSupported</key>
        <array>
            <string>OrderSoupIntent</string>
        </array>
        <!-- ... -->
    </dict>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.intents-ui-service</string>
    <key>NSExtensionMainStoryboard</key>
    <string>MainInterface</string>
</dict>

在上述 Info.plist 中:

  • IntentsSupportedOrderSoupIntent表示這個意圖 UI 延伸模組會處理 。
  • NSExtensionPointIdentifier 指定應用程式延伸模組的類型。 如需詳細資訊,請參閱 Apple的檔
  • NSExtensionMainStoryboard 指定定義此延伸模組主要介面的分鏡腳本

SoupChefIntentsUI – Entitlements.plist

SoupChefIntentsUI 專案不需要 Entitlements.plist 檔案。

建立使用者介面

由於 SoupChefIntentsUIInfo.plist 會將索引鍵設定NSExtensionMainStoryboardMainInterfaceMainInterace.storyboard 檔案會定義 Intents UI 延伸模組的介面。

在此分鏡腳本中,有一個類型為IntentViewController的單一檢視控制器。 它會參考兩個檢視:

  • invoiceView,類型為 InvoiceView
  • 確認檢視,類型為 ConfirmOrderView

注意

invoiceView 和 confirmationView介面會在 Main.storyboard定義為次要檢視。 Visual Studio for Mac 和 Visual Studio 2017 不支持檢視或編輯次要檢視;若要這樣做,請在 Xcode 的 Interface Builder 中開啟 Main.storyboard

IntentViewController 實作 IINUIHostedViewControlling 介面,用來在處理 Siri 意圖時提供自定義介面。 ConfigureView 會呼叫 方法來自定義介面,並顯示確認或發票,視互動是否已確認 (INIntentHandlingStatus.Ready) 或已順利執行而定 (INIntentHandlingStatus.Success):

[Export("configureViewForParameters:ofInteraction:interactiveBehavior:context:completion:")]
public void ConfigureView(
    NSSet<INParameter> parameters,
    INInteraction interaction,
    INUIInteractiveBehavior interactiveBehavior,
    INUIHostedViewContext context,
    INUIHostedViewControllingConfigureViewHandler completion)
{
    // ...
    if (interaction.IntentHandlingStatus == INIntentHandlingStatus.Ready)
    {
        desiredSize = DisplayInvoice(order, intent);
    }
    else if(interaction.IntentHandlingStatus == INIntentHandlingStatus.Success)
    {
        var response = interaction.IntentResponse as OrderSoupIntentResponse;
        if (!(response is null))
        {
            desiredSize = DisplayOrderConfirmation(order, intent, response);
        }
    }
    completion(true, parameters, desiredSize);
}

提示

如需方法 ConfigureView 的詳細資訊,請觀看Apple的WWDC 2017簡報 SiriKit的新功能。

建立語音快捷方式

湯廚師提供一個介面,將語音快捷方式指派給每個訂單,讓您能夠使用 Siri 訂購湯。 事實上,用來錄製和指派語音快捷方式的介面是由iOS提供,而且需要很少的自定義程序代碼。

在 中 OrderDetailViewController,當使用者點選數據表的 [新增至 Siri ] 數據列時, RowSelected 方法會顯示畫面以新增或編輯語音快捷方式:

public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
    // ...
    else if (TableConfiguration.Sections[indexPath.Section].Type == OrderDetailTableConfiguration.SectionType.VoiceShortcut)
    {
        INVoiceShortcut existingShortcut = VoiceShortcutDataManager?.VoiceShortcutForOrder(Order);
        if (!(existingShortcut is null))
        {
            var editVoiceShortcutViewController = new INUIEditVoiceShortcutViewController(existingShortcut);
            editVoiceShortcutViewController.Delegate = this;
            PresentViewController(editVoiceShortcutViewController, true, null);
        }
        else
        {
            // Since the app isn't yet managing a voice shortcut for
            // this order, present the add view controller
            INShortcut newShortcut = new INShortcut(Order.Intent);
            if (!(newShortcut is null))
            {
                var addVoiceShortcutVC = new INUIAddVoiceShortcutViewController(newShortcut);
                addVoiceShortcutVC.Delegate = this;
                PresentViewController(addVoiceShortcutVC, true, null);
            }
        }
    }
}

根據目前顯示順序是否存在現有語音快捷方式, RowSelected 呈現 類型 INUIEditVoiceShortcutViewController 為 或 INUIAddVoiceShortcutViewController的檢視控制器。 在每個案例中, OrderDetailViewController 將本身設定為檢視控制器的 Delegate,這就是為什麼它也會實作的原因 IINUIAddVoiceShortcutViewControllerDelegateIINUIEditVoiceShortcutViewControllerDelegate

在裝置上進行測試

若要在裝置上執行湯 Chef,請遵循本節中的指示。 另請閱讀 關於自動布建的附註。

應用程式群組、應用程式識別碼、布建配置檔

在 Apple Developer Portal[憑證、 識別碼和設定檔] 區段中,執行下列步驟:

  • 建立應用程式群組,以在湯 Chef 應用程式與其擴充功能之間共享數據。 例如: group.com.yourcompanyname.SoupChef

  • 建立三個應用程式識別碼:一個用於應用程式本身、一個用於意圖擴充功能,另一個用於意圖UI擴充功能。 例如:

    • 應用程式: com.yourcompanyname.SoupChef

      • 若要使用此應用程式識別碼,請指派 SiriKit 和 應用程式群組 功能。
    • 意圖延伸模組: com.yourcompanyname.SoupChef.Intents

      • 若要使用此應用程式識別碼,請指派 應用程式群組 功能。
    • 意圖 UI 延伸模組: com.yourcompanyname.SoupChef.Intentsui

      • 此應用程式識別碼不需要特殊功能。
  • 建立上述應用程式識別碼之後,請編輯 指派給應用程式和意圖延伸模組的應用程式群組 功能,並指定稍早建立的特定應用程式群組。

  • 建立三個新的開發佈建配置檔,每個新的應用程式識別碼各一個。

  • 下載這些布建配置檔,然後按兩下每個設定檔加以安裝。 如果 Visual Studio for Mac 或 Visual Studio 2017 已在執行中,請重新啟動它以確定它註冊新的布建配置檔。

編輯 Info.plist、Entitlements.plist 和原始程式碼

在 Visual Studio for Mac 或 Visual Studio 2017 中,執行下列步驟:

  • 更新方案中的各種 Info.plist 檔案。 將應用程式、意圖延伸模組和意圖 UI 延伸模組 套件組合識別碼 設定為稍早定義的應用程式識別碼:

    • 應用程式: com.yourcompanyname.SoupChef
    • 意圖延伸模組: com.yourcompanyname.湯Chef.Intents
    • 意圖 UI 延伸模組: com.yourcompanyname.SoupChef.Intentsui
  • 更新 SoupChef 專案的 Entitlements.plist 檔案

    • 針對應用程式 群組 功能,請將群組設定為稍早建立的新應用程式群組(在上述範例中,它是 group.com.yourcompanyname.SoupChef)。
    • 請確定 已啟用 SiriKit
  • 更新湯ChefIntents 專案的 Entitlements.plist 檔案

    • 針對應用程式 群組 功能,請將群組設定為稍早建立的新應用程式群組(在上述範例中,它是 group.com.yourcompanyname.SoupChef)。
  • 最後,開啟 NSUserDefaultsHelper.cs。 將 AppGroup 變數設定為新應用程式群組的值(例如,將它設定為 group.com.yourcompanyname.SoupChef)。

設定組建設定

在 Visual Studio for Mac 或 Visual Studio 2017 中:

  • 開啟 SoupChef 項目的選項/屬性。 在 [iOS 套件組合簽署] 索引標籤上,將 [簽署身分識別] 設定為 [自動],並將 [布建配置檔] 設定為您稍早建立的新應用程式特定布建配置檔。

  • 開啟 SoupChefIntents 項目的選項/屬性。 在 [iOS 套件組合簽署] 索引標籤上,將 [簽署身分識別] 設定為 [自動],並將 [布建配置檔] 設定為您稍早建立的新意圖擴充功能特定布建配置檔。

  • 開啟 SoupChefIntentsUI 專案的選項/屬性。 在 [iOS 套件組合簽署] 索引標籤上,將 [簽署身分識別] 設定為 [自動],並將 [布建配置檔] 設定為您稍早建立的新意圖 UI 延伸模組專用布建配置檔。

有了這些變更,應用程式將會在iOS裝置上執行。

自動佈建

您可以使用 自動布建 ,直接在 IDE 中完成許多這些布建工作。 不過,自動布建不會設定應用程式群組。 您必須以您想要使用的應用程式群組名稱手動 設定 Entitlements.plist 檔案,請造訪 Apple Developer Portal 以建立應用程式群組、將該應用程式群組指派給自動布建所建立的每個應用程式識別碼、重新產生布建配置檔(應用程式、意圖延伸模組、意圖 UI 延伸模組)以包含新建立的應用程式群組, 並下載並安裝它們。