Skróty Siri w środowisku Xamarin.iOS

W systemie iOS 10 firma Apple wprowadziła SiriKit, umożliwiając tworzenie komunikatów, połączeń VoIP, płatności, treningów, rezerwacji przejazdów i aplikacji do wyszukiwania zdjęć, które współdziałają z Siri.

W systemie iOS 11 Zestaw SiriKit uzyskał obsługę większej liczby typów aplikacji i większą elastyczność dostosowywania interfejsu użytkownika.

System iOS 12 dodaje skróty Siri, umożliwiając wszystkim typom aplikacji uwidacznianie ich funkcjonalności siri. Siri uczy się, gdy niektóre zadania oparte na aplikacji są najbardziej istotne dla użytkownika i wykorzystuje tę wiedzę do sugerowania potencjalnych akcji za pomocą skrótów. Naciśnięcie skrótu lub wywołanie go za pomocą polecenia głosowego spowoduje otwarcie aplikacji lub uruchomienie zadania w tle.

Skróty powinny służyć do przyspieszania możliwości wykonywania typowego zadania przez użytkownika — w wielu przypadkach nawet bez otwierania danej aplikacji.

Przykładowa aplikacja: Soup Chef

Aby lepiej zrozumieć skróty Siri, zapoznaj się z przykładową aplikacją Soup Chef . Soup Chef umożliwia użytkownikom składanie zamówień z wyimaginowanej restauracji zupowej, wyświetlanie historii zamówień i definiowanie fraz używanych podczas zamawiania zupy przez interakcję z Siri.

Napiwek

Przed przetestowaniem narzędzia Soup Chef w symulatorze lub urządzeniu z systemem iOS 12 włącz następujące dwa ustawienia, które są przydatne podczas debugowania skrótów:

  • W aplikacji Ustawienia włącz pozycję Wyświetl ostatnie skróty dla deweloperów>.
  • W aplikacji Ustawienia włącz opcję Darowizny wyświetlania dla deweloperów > na ekranie blokady.

Te ustawienia debugowania ułatwiają znajdowanie ostatnio utworzonych skrótów (zamiast przewidywanych) na ekranie blokady systemu iOS i ekranie wyszukiwania.

Aby użyć przykładowej aplikacji:

  • Zainstaluj i uruchom przykładową aplikację Soup Chef na symulatorze lub urządzeniu z systemem iOS 12.
  • + Kliknij przycisk w prawym górnym rogu, aby utworzyć nowe zamówienie.
  • Wybierz typ zupy, określ ilość i opcje, a następnie naciśnij pozycję Kolejność składania.
  • Na ekranie Historia zamówień naciśnij nowo utworzone zamówienie, aby wyświetlić jego szczegóły.
  • W dolnej części ekranu szczegółów zamówienia naciśnij pozycję Dodaj do Siri.
  • Zarejestruj frazę głosową, aby skojarzyć z zamówieniem, a następnie naciśnij pozycję Gotowe.
  • Zminimalizuj szefa kuchni zupy, wywołaj Siri i ponownie umieść zamówienie, używając zarejestrowanej frazy głosowej.
  • Po zakończeniu zamówienia przez Siri otwórz ponownie aplikację Soup Chef i zwróć uwagę, że nowe zamówienie jest wyświetlane na ekranie Historia zamówień.

Przykładowa aplikacja pokazuje, jak:

Info.plist i Entitlements.plist

Przed zagłębianiem się w kod Chef zupy, przyjrzyj się swoim plikom Info.plist i Entitlements.plist.

Info.plist

Plik Info.plist w projekcie SoupChef definiuje identyfikator pakietu jako com.xamarin.SoupChef. Ten identyfikator pakietu będzie używany jako prefiks dla identyfikatorów pakietów rozszerzeń interfejsu użytkownika Intents and Intents omówionych w dalszej części tego dokumentu.

Plik Info.plist zawiera również następujący wpis:

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

Ta NSUserActivityTypes para klucz/wartość wskazuje, że chef zupy wie, jak obsługiwać element OrderSoupIntent, oraz NSUserActivity element ActivityType "com.xamarin.SoupChef.viewMenu".

Działania i niestandardowe intencje przekazywane do samej aplikacji, w przeciwieństwie do jej rozszerzeń, są obsługiwane w AppDelegate metodzie ContinueUserActivity (metoda UIApplicationDelegate .

Entitlements.plist

Plik Entitlements.plist w projekcie SoupChef zawiera następujące wpisy:

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

Ta konfiguracja wskazuje, że aplikacja używa grupy aplikacji "group.com.xamarin.SoupChef". Rozszerzenie aplikacji SoupChefIntents używa tej samej grupy aplikacji, która umożliwia udostępnianie dwóch projektów NSUserDefaults Danych.

Klucz com.apple.developer.siri wskazuje, że aplikacja współdziała z Siri.

Uwaga

Konfiguracja kompilacji projektu SoupChef ustawia niestandardowe uprawnienia do pliku Entitlements.plist.

Używanie skrótu NSUserActivity do otwierania aplikacji

Aby utworzyć skrót, który otwiera aplikację w celu wyświetlenia określonej zawartości, utwórz obiekt NSUserActivity i dołącz go do kontrolera widoku dla ekranu, który ma zostać otwarty.

Konfigurowanie elementu NSUserActivity

Na ekranie SoupMenuViewController menu tworzy obiekt NSUserActivity i przypisuje go do właściwości kontrolera UserActivity widoku:

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

UserActivity Ustawienie właściwości przekazuje działanie na Siri. Dzięki tej darowiznie Siri uzyskuje informacje o tym, kiedy i gdzie to działanie jest istotne dla użytkownika i uczy się, aby lepiej je sugerować w przyszłości.

NSUserActivityHelper jest klasą narzędziową zawartą w rozwiązaniu SoupChef w bibliotece klas SoupKit . Tworzy element NSUserActivity i ustawia różne właściwości związane z Siri i wyszukiwaniem:

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;
    }
}

Zwróć uwagę na następujące funkcje w szczególności:

  • true Ustawienie EligibleForPrediction oznacza, że Siri może przewidzieć to działanie i wyświetlić je jako skrót.
  • Tablica ContentAttributeSet jest standardem CSSearchableItemAttributeSet używanym do uwzględnienia w NSUserActivity wynikach wyszukiwania systemu iOS.
  • SuggestedInvocationPhrase to fraza, którą Siri zaproponuje użytkownikowi jako potencjalny wybór podczas przypisywania frazy do skrótu.

Obsługa skrótu NSUserActivity

Aby obsłużyć NSUserActivity skrót wywoływany przez użytkownika, aplikacja systemu iOS musi zastąpić ContinueUserActivity metodę AppDelegate klasy odpowiadającą na ActivityType podstawie pola przekazanego NSUserActivity obiektu:

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

Ta metoda wywołuje HandleUserActivitymetodę , która znajduje segue na ekranie menu i wywołuje go:

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);
}

Przypisywanie frazy do elementu NSUserActivity

Aby przypisać frazę do NSUserActivityelementu , otwórz aplikację Ustawienia systemu iOS i wybierz pozycję Siri & Search My Shortcuts (Siri & Search > My Shortcuts). Następnie wybierz skrót (w tym przypadku "Zamów lunch") i zapisz frazę.

Wywołanie Siri i użycie tej frazy spowoduje otwarcie aplikacji Soup Chef na ekranie menu.

Używanie niestandardowego skrótu intencji do wykonywania zadania

Definiowanie intencji niestandardowej

Aby podać skrót umożliwiający użytkownikowi szybkie ukończenie określonego zadania związanego z aplikacją, utwórz intencję niestandardową. Intencja niestandardowa reprezentuje zadanie, które użytkownik może chcieć wykonać, parametry istotne dla tego zadania oraz potencjalne odpowiedzi wynikające z wykonania zadania. W zależności od sposobu definiowania intencji niestandardowej wywołanie może otworzyć aplikację lub uruchomić zadanie w tle.

Użyj programu Xcode 10, aby utworzyć intencje niestandardowe. W repozytorium SoupChef intencja niestandardowa jest definiowana w elemencie OrderSoupIntentCodeGen, projekcieObjective-C. Otwórz ten projekt i wybierz plik Intents.intentdefinition w nawigatorzeprojektu, aby wyświetlić intencję OrderSoup.

Zwróć uwagę na następujące funkcje:

  • Intencja ma kategorię kolejności. Istnieją różne wstępnie zdefiniowane kategorie, które mogą być używane dla intencji niestandardowych; wybierz tę, która najlepiej odpowiada zadaniu, które zostanie włączone przez twoją intencję niestandardową. Ponieważ to rozwiązanie jest aplikacją do zamawiania zupy, funkcja OrderSoupIntent używa polecenia Order.
  • Pole wyboru Potwierdzenie wskazuje, czy Siri musi zażądać potwierdzenia przed wykonaniem zadania. W przypadku intencji Order Soup Chef ta opcja jest włączona, ponieważ użytkownik dokonuje zakupu.
  • Sekcja Parametry w pliku .intentdefinition definiuje parametry istotne dla skrótu. Aby złożyć zamówienie zupy, Soup Chef musi znać rodzaj zupy, jego ilość i wszelkie powiązane opcje. Każdy parametr ma typ; Parametr, który nie może być reprezentowany przez wstępnie zdefiniowany typ, są ustawione jako Niestandardowe.
  • Interfejs Typy skrótów opisuje różne kombinacje parametrów, których Siri może używać podczas sugerowania skrótu. Skojarzone sekcje Tytuł i Podtytuł umożliwiają zdefiniowanie wiadomości używanych przez Siri podczas prezentowania sugerowanego skrótu do użytkownika.
  • Pole wyboru Obsługuje wykonywanie w tle należy zaznaczyć dla dowolnego skrótu, który można wykonać bez otwierania aplikacji w celu dalszej interakcji użytkownika.

Definiowanie niestandardowych odpowiedzi intencji

Element Odpowiedź zagnieżdżony poniżej intencji OrderSoup reprezentuje potencjalne odpowiedzi wynikające z zamówienia zupy.

W definicji odpowiedzi intencji OrderSoup zwróć uwagę na następujące funkcje:

  • Właściwości odpowiedzi mogą służyć do dostosowywania komunikatu przekazanego użytkownikowi. Odpowiedź intencji OrderSoup ma właściwości zupy i waitTime.
  • Szablony odpowiedzi określają różne komunikaty o powodzeniu i niepowodzeniu, których można użyć do wskazania stanu po zakończeniu zadania intencji.
  • Pole wyboru Powodzenie powinno być zaznaczone dla odpowiedzi wskazujących powodzenie.
  • Odpowiedź powodzenia OrderSoupIntent używa właściwości zupy i waitTime, aby zapewnić przyjazny i przydatny komunikat opisujący, kiedy kolejność zupy będzie gotowa.

Generowanie kodu dla intencji niestandardowej

Kompilowanie projektu Xcode zawierającego tę niestandardową definicję intencji powoduje wygenerowanie kodu Xcode, który może służyć do programowej interakcji z intencją niestandardową i jej odpowiedziami.

Aby wyświetlić ten wygenerowany kod:

  • Otwórz plik AppDelegate.m.
  • Dodaj import do pliku nagłówka intencji niestandardowej: #import "OrderSoupIntent.h"
  • W dowolnej metodzie w klasie dodaj odwołanie do OrderSoupIntentklasy .
  • Kliknij prawym przyciskiem myszy OrderSoupIntent i wybierz pozycję Przejdź do definicji.
  • Kliknij prawym przyciskiem myszy nowo otwarty plik OrderSoupIntent.h i wybierz polecenie Pokaż w programie Finder.
  • Ta akcja spowoduje otwarcie okna wyszukiwania zawierającego plik h i m zawierający wygenerowany kod.

Ten wygenerowany kod zawiera następujące elementy:

  • OrderSoupIntent — klasa reprezentująca intencję niestandardową.
  • OrderSoupIntentHandling — protokół definiujący metody, które będą używane do potwierdzenia, że intencja powinna zostać wykonana, oraz metoda, która rzeczywiście je wykonuje.
  • OrderSoupIntentResponseCode — wyliczenie, które definiuje różne stany odpowiedzi.
  • OrderSoupIntentResponse — klasa reprezentująca odpowiedź na wykonanie intencji.

Tworzenie powiązania z intencją niestandardową

Aby użyć kodu wygenerowanego przez program Xcode w aplikacji platformy Xamarin.iOS, utwórz dla niego powiązanie języka C#.

Tworzenie biblioteki statycznej i definicji powiązań języka C#

W repozytorium SoupChef przyjrzyj się folderowi OrderSoupIntentStaticLib i otwórz projekt OrderSoupIntentStaticLib.xcodeproj.

Ten projekt biblioteki statycznej Cocoa Touch zawiera pliki OrderSoupIntent.h i OrderSoupIntent.m wygenerowane przez program Xcode.

Konfigurowanie ustawień kompilacji projektu biblioteki statycznej

W nawigatorze projektu Xcode wybierz projekt najwyższego poziomu OrderSoupIntentStaticLib i przejdź do pozycji Build Phases Compile Sources (Kompilowanie źródeł kompilacji faz).> Zwróć uwagę, że element OrderSoupIntent.m (który importuje element OrderSoupIntent.h) znajduje się tutaj. Zwróć uwagę, że w linku plik binarny z bibliotekami znajduje się wartość Intents.framework i Foundation.framework. Po zainstalowaniu tych ustawień struktura będzie kompilować poprawnie.

Tworzenie biblioteki statycznej i generowanie definicji powiązań języka C#

Aby skompilować bibliotekę statyczną i wygenerować dla niej definicje powiązań języka C#, wykonaj następujące kroki:

  • Zainstaluj narzędzie Objective Sharpie służące do generowania definicji powiązań z plików .h i .m utworzonych przez program Xcode.

  • Skonfiguruj system do używania narzędzi wiersza polecenia Xcode 10:

    Ostrzeżenie

    Aktualizowanie wybranych narzędzi wiersza polecenia ma wpływ na wszystkie zainstalowane wersje programu Xcode w systemie. Po zakończeniu korzystania z przykładowej aplikacji Soup Chef pamiętaj, aby przywrócić to ustawienie do oryginalnej konfiguracji.

    • W programie Xcode wybierz pozycję Lokalizacje preferencji > programu Xcode > i ustaw pozycję Narzędzia wiersza polecenia na najnowszą instalację programu Xcode 10 dostępną w systemie.
  • W terminalu cd przejdź do katalogu OrderSoupIntentStaticLib .

  • Wpisz make, który kompilacje:

    • Biblioteka statyczna libOrderSoupIntentStaticLib.a
    • W katalogu wyjściowym bo definicje powiązań języka C#:
      • ApiDefinitions.cs
      • StructsAndEnums.cs

Projekt OrderSoupIntentBindings, który opiera się na tej bibliotece statycznej i skojarzonych definicjach powiązań, tworzy te elementy automatycznie. Jednak ręcznie uruchamiane przez powyższy proces zapewni, że kompilacje będą kompilować zgodnie z oczekiwaniami.

Aby uzyskać więcej informacji na temat tworzenia biblioteki statycznej i używania języka Objective Sharpie do tworzenia definicji powiązań języka C#, zapoznaj się z przewodnikiem Wiązanie biblioteki systemu iOSObjective-C.

Tworzenie biblioteki powiązań

Po utworzeniu biblioteki statycznej i powiązań języka C# pozostała część niezbędna do korzystania z kodu powiązanego z intencją kodu Xcode w projekcie platformy Xamarin.iOS jest biblioteką powiązań.

W repozytorium Soup Chef otwórz plik SoupChef.sln. Między innymi to rozwiązanie zawiera bibliotekę OrderSoupIntentBinding, bibliotekę powiązań dla biblioteki statycznej wygenerowanej wcześniej.

Zwróć szczególną uwagę na to, że ten projekt obejmuje:

  • ApiDefinitions.cs — plik wygenerowany wcześniej przez objective Sharpie i dodany do tego projektu. Akcja kompilacji tego pliku jest ustawiona na ObjcBindingApiDefinition.

  • StructsAndEnums.cs — inny plik wygenerowany wcześniej przez aplikację Objective Sharpie i dodany do tego projektu. Akcja kompilacji tego pliku jest ustawiona na ObjcBindingCoreSource.

  • Natywne odwołanie do biblioteki libOrderSoupIntentStaticLib.a, skompilowana wcześniej biblioteka statyczna. Zaktualizuj właściwości odwołania natywnego i określ następujące wartości:

    1. Struktury = Foundation Intents
    2. Link inteligentny = On
    3. Force Load = On
    4. Rodzaj = Static

Uwaga

Zarówno ApiDefinitions.cs , jak i StructsAndEnums.cs zawierają atrybuty, takie jak [Watch (5,0), iOS (12,0)]. Te atrybuty wygenerowane przez objective Sharpie zostały skomentowane, ponieważ nie są one niezbędne dla tego projektu.

Aby uzyskać więcej informacji na temat tworzenia biblioteki powiązań języka C#, zapoznaj się z przewodnikiem Wiązanie biblioteki systemu iOSObjective-C.

Zwróć uwagę, że projekt SoupChef zawiera odwołanie do elementu OrderSoupIntentBinding, co oznacza, że teraz może uzyskać dostęp do klas, interfejsów i wyliczenie w języku C#:

  • OrderSoupIntent
  • OrderSoupIntentHandling
  • OrderSoupIntentResponse
  • OrderSoupIntenseResponseCode

Tworzenie platformy Swift

Definicja intencji kodu natywnego jest domyślnie generowana przez program Xcode przy użyciu języka projektu natywnego. Jeśli zdefiniujesz plik Intents.intentdefinition w projekcie Swift, program Xcode wygeneruje pojedynczy plik Swift ze wszystkimi wymaganymi klasami, których można użyć do utworzenia struktury Swift.

Napiwek

Możesz wybrać żądany język dla wygenerowanego kodu intencji w ustawieniach kompilacji Xcode. Przejdź do docelowej intencji > Kompilator kompilacji Ustawienia > definicji intencji — generowanie kodu i wybierz pozycję Swift lub Objective-C. Możesz również zachować automatyczne dopasowanie go do języka docelowego.

Proces tworzenia struktury Swift jest podobny do opisanego wcześniej:

  1. Utwórz nowy projekt platformy Swift.
  2. Skopiuj automatycznie wygenerowany plik Swift z kodem intencji do tego projektu. Ten plik można znaleźć zgodnie z opisem tutaj.
  3. Objective-C Włącz nagłówek mostkowania, więc platforma jest generowana automatycznie przy użyciu wymaganego pliku Objective-C nagłówka sharpie.

Po utworzeniu struktury wykonaj te same kroki opisane wcześniej, aby utworzyć powiązanie platformy Xamarin. Więcej informacji na temat tworzenia powiązania dla platformy Swift można znaleźć tutaj.

Dodawanie pliku definicji intencji do rozwiązania

W rozwiązaniu C# SoupChef projekt SoupKit zawiera kod udostępniony między aplikacją a jej rozszerzeniami. Plik Intents.intentdefinition został umieszczony w katalogu Base.lproj zestawu SoupKit i ma akcję kompilacji zawartości. Proces kompilacji kopiuje ten plik do pakietu aplikacji Soup Chef, gdzie jest wymagany, aby aplikacja działała poprawnie.

Donating an intent (Donating an intent)

Aby Siri zasugerował skrót, musi najpierw zrozumieć, kiedy skrót jest odpowiedni.

Aby dać Siri to zrozumienie, Soup Chef przekazuje intencję Siri za każdym razem, gdy użytkownik składa zamówienie zupy. Na podstawie tej darowizny — kiedy została przekazana, gdzie została przekazana, parametry, które zawiera — Siri uczy się, kiedy sugerować skrót w przyszłości.

SoupChef używa klasy do umieszczania SoupOrderDataManager darowizn. Po wywołaniu metody w celu złożenia zamówienia zupy dla użytkownika PlaceOrder metoda z kolei wywołuje metodę DonateInteraction:

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

Po pobraniu intencji jest ona owinięta w obiekcie INInteraction. Element INInteraction jest podawany Identifier który jest zgodny z unikatowym identyfikatorem zamówienia (będzie to pomocne później podczas usuwania darowizn intencji, które nie są już prawidłowe). Następnie interakcja jest przekazywana do Siri.

Wywołanie order.Intent metody getter pobiera element OrderSoupIntent reprezentujący zamówienie, ustawiając jego Quantitywartość , Soup, Optionsi obraz oraz frazę wywołania, która ma być używana jako sugestia, gdy użytkownik rejestruje frazę Siri do skojarzenia z intencją:

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;
    }
}

Usuwanie nieprawidłowych darowizn

Ważne jest, aby usunąć darowizny, które nie są już prawidłowe, aby Siri nie sprawiała, że sugestie skrótów nie są pomocne ani mylące.

W narzędziu Soup Chef ekran Konfiguruj menu może służyć do oznaczania elementu menu jako niedostępnego. Siri nie powinien już sugerować skrótu do zamawiania niedostępnego elementu menu, więc RemoveDonation metoda SoupMenuManager usuwania darowizn dla elementów menu, które nie są już dostępne. Aplikacja implementuje tę funkcję przez:

  • Znajdowanie zamówień skojarzonych z niedostępnym elementem menu.
  • Chwytanie ich identyfikatorów.
  • Usuwanie interakcji, które mają te same identyfikatory.
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");
            }
        });
    }
}

Weryfikowanie pomyślnych darowizn

Rozwiązanie obejmuje wiele projektów i określoną konfigurację. W niektórych przypadkach aplikacja może ulec awarii z powodu niekompletnej konfiguracji, w innych przypadkach może ona dyskretnie nie przekazać interakcji. Ważne jest, aby zweryfikować pomyślne darowizny i ustawienia dewelopera systemu iOS pomagają w jego użyciu. Przejdź do Ustawienia > Developer i włącz następujące opcje dla deweloperów, aby wyświetlić ostatnie darowizny i skróty:

  • Wyświetlanie ostatnich skrótów
  • Wyświetlanie darowizn na ekranie blokady

Po włączeniu każdej pomyślnej darowizny pojawi się na ekranie blokady i poniżej opcji sugestii Siri. Jeśli po uruchomieniu aplikacji nie widzisz tam darowizn, zapoznaj się z następującymi przypadkami rozwiązywania problemów:

  1. Nie można utworzyć OrderSoupIntent aplikacji z następującym błędem:

    Nie można utworzyć natywnego wystąpienia typu "NativeLibrary.OrderSoupIntent": nie załadowano klasy natywnej.

    Ten błąd oznacza, że platforma Xamarin nie może załadować klasy natywnej za pośrednictwem powiązania platformy Xamarin. Aby rozwiązać ten problem, sprawdź, czy biblioteka natywna zawiera wymagany kod, do którego odwołuje się projekt powiązania, i że ustawiono odpowiednie flagi, zgodnie z opisem w tym miejscu, ustaw flagę Force Load na On.

  2. Aplikacja nie może zainicjować załadowanego wystąpienia natywnego klasy intent z następującym błędem:

    Nie można zainicjować wystąpienia typu "NativeLibrary.OrderSoupIntent": natywna metoda "init" zwróciła zero.

    Problem jest związany z brakującym plikiem definicji intencji. Aplikacja Xamarin powinna zawierać oryginalny plik definicji intencji z typem Content , zgodnie z opisem w tym miejscu.

  3. Aplikacja tworzy intencję i wywołuje metodę darowizny bez awarii, ale dane wyjściowe konsoli wyświetla ostrzeżenie o nieznanym typie intencji i nie dokonano darowizny:

    Nie można przekazać interakcji z poleceniem OrderSoupIntent, który nie ma prawidłowych typów skrótów

    Aby rozwiązać ten problem, intencja musi być prawidłowo zdefiniowana w pliku plist, należy włączyć i wybrać uprawnienie Siri dla bieżącej konfiguracji kompilacji za pośrednictwem ustawień projektu.

    Plik info.plist aplikacji:

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

    Plik Entitlements.plist aplikacji z funkcją Siri:

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

    Dla docelowej konfiguracji kompilacji należy wybrać uprawnienia niestandardowe. Przejdź do pozycji Ustawienia > projektu Kompiluj > podpisywanie pakietu dla systemu iOS i ustaw opcję Uprawnienia niestandardowe na plik Entitlements.plist zawierający wymagane uprawnienia.

Tworzenie rozszerzenia Intents

Kod uruchamiany, gdy Siri wywołuje intencję, jest umieszczany w rozszerzeniu Intents, które można dodać jako nowy projekt do tego samego rozwiązania co istniejąca aplikacja platformy Xamarin.iOS, taka jak Soup Chef. W rozwiązaniu SoupChef rozszerzenie nosi nazwę SoupChefIntents.

SoupChefIntents — Info.plist i Entitlements.plist

SoupChefIntents — Info.plist

Plik Info.plist w projekcie SoupChefIntents definiuje identyfikator pakietu jako com.xamarin.SoupChef.SoupChefIntents.

Plik Info.plist zawiera również następujący wpis:

<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>

W powyższym pliku Info.plist:

  • IntentsRestrictedWhileLocked wyświetla intencje, które mają być obsługiwane po odblokowaniu urządzenia.
  • IntentsSupported Wyświetla listę intencji obsługiwanych przez to rozszerzenie.
  • NSExtensionPointIdentifier określa typ rozszerzenia aplikacji. Aby uzyskać więcej informacji, zobacz dokumentację firmy Apple.
  • NSExtensionPrincipalClass określa klasę, która powinna być używana do obsługi intencji obsługiwanych przez to rozszerzenie.
SoupChefIntents — Entitlements.plist

Plik Entitlements.plist w projekcie SoupChefIntents ma możliwość grup aplikacji. Ta funkcja jest skonfigurowana do używania tej samej grupy aplikacji co projekt SoupChef :

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

Funkcja Chef zupy utrwala dane za pomocą polecenia NSUserDefaults. Aby udostępniać dane między aplikacją a rozszerzeniem aplikacji, odwołują się do tej samej grupy aplikacji w swoich plikach Entitlements.plist .

Uwaga

Konfiguracja kompilacji projektu SoupChefIntents ustawia niestandardowe uprawnienia do pliku Entitlements.plist.

Obsługa zadania w tle OrderSoupIntent

Rozszerzenie Intents wykonuje niezbędne zadania w tle dla skrótu na podstawie niestandardowej intencji.

Siri wywołuje metodę GetHandlerIntentHandler klasy (zdefiniowaną w pliku Info.plist jako NSExtensionPrincipalClass), aby uzyskać wystąpienie klasy rozszerzającej OrderSoupIntentHandlingklasę , która może służyć do obsługi klasy 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, zdefiniowany w projekcie SoupKit współużytkowanego kodu, implementuje dwie ważne metody:

  • ConfirmOrderSoup — potwierdza, czy zadanie skojarzone z intencją powinno być rzeczywiście wykonane
  • HandleOrderSoup — umieszcza kolejność zupy i odpowiada użytkownikowi przez wywołanie przekazanej procedury obsługi uzupełniania

Obsługa elementu OrderSoupIntent, który otwiera aplikację

Aplikacja musi prawidłowo obsługiwać intencje, które nie są uruchamiane w tle. Te intencje są obsługiwane w taki sam sposób jak NSUserActivity skróty w ContinueUserActivity metodzie AppDelegate:

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;
    }
    // ...
}  

Udostępnianie interfejsu użytkownika dla intencji niestandardowej

Rozszerzenie interfejsu użytkownika Intents udostępnia niestandardowy interfejs użytkownika dla rozszerzenia Intents. W rozwiązaniu SoupChef, SoupChefIntentsUI to rozszerzenie interfejsu użytkownika Intents, które udostępnia interfejs dla SoupChefIntents.

SoupChefIntentsUI — Info.plist i Entitlements.plist

SoupChefIntentsUI — Info.plist

Plik Info.plist w projekcie SoupChefIntentsUI definiuje identyfikator pakietu jako com.xamarin.SoupChef.SoupChefIntentsui.

Plik Info.plist zawiera również następujący wpis:

<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>

W powyższym pliku Info.plist:

  • IntentsSupported wskazuje, że OrderSoupIntent element jest obsługiwany przez to rozszerzenie interfejsu użytkownika Intents.
  • NSExtensionPointIdentifier określa typ rozszerzenia aplikacji. Aby uzyskać więcej informacji, zobacz dokumentację firmy Apple.
  • NSExtensionMainStoryboard określa scenorys, który definiuje podstawowy interfejs tego rozszerzenia

SoupChefIntentsUI — Entitlements.plist

Projekt SoupChefIntentsUI nie potrzebuje pliku Entitlements.plist.

Tworzenie interfejsu użytkownika

Ponieważ plik Info.plist for SoupChefIntentsUI ustawia NSExtensionMainStoryboard klucz na MainInterfacewartość , plik MainInterace.storyboard definiuje interfejs rozszerzenia interfejsu użytkownika Intents.

W tym scenorysie istnieje jeden kontroler widoku o typie IntentViewController. Odwołuje się do dwóch widoków:

  • invoiceView, typu InvoiceView
  • confirmationView, typu ConfirmOrderView

Uwaga

Interfejsy dla elementu invoiceView i confirmationView są definiowane w widoku Main.storyboard jako widoki pomocnicze. Visual Studio dla komputerów Mac i Visual Studio 2017 nie zapewniają obsługi wyświetlania lub edytowania widoków pomocniczych; aby to zrobić, otwórz Main.storyboard w narzędziu Interface Builder programu Xcode.

IntentViewController implementuje IINUIHostedViewControlling interfejs używany do udostępniania interfejsu niestandardowego podczas pracy z intencjami Siri. Standard ConfigureViewMetoda jest wywoływana w celu dostosowania interfejsu, wyświetlania potwierdzenia lub faktury, w zależności od tego, czy interakcja została potwierdzona () lub została wykonana pomyślnie (INIntentHandlingStatus.ReadyINIntentHandlingStatus.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);
}

Napiwek

Aby uzyskać więcej informacji na temat ConfigureView metody, obejrzyj prezentację WWDC 2017 firmy Apple, What's New in SiriKit.

Tworzenie skrótu głosowego

Soup Chef udostępnia interfejs umożliwiający przypisanie skrótu głosowego do każdego zamówienia, dzięki czemu można zamówić zupę za pomocą Siri. W rzeczywistości interfejs używany do rejestrowania i przypisywania skrótów głosowych jest dostarczany przez system iOS i wymaga niewielkiego kodu niestandardowego.

W OrderDetailViewControllerprogramie, gdy użytkownik naciągnie wiersz Dodaj tabelę do siri , RowSelected metoda wyświetla ekran do dodania lub edytowania skrótu głosowego:

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);
            }
        }
    }
}

Na podstawie tego, czy istnieje istniejący skrót głosowy dla aktualnie wyświetlanej kolejności, RowSelected przedstawia kontroler widoku typu INUIEditVoiceShortcutViewController lub INUIAddVoiceShortcutViewController. W każdym przypadku OrderDetailViewController ustawia się jako kontroler Delegatewidoku , dlatego również implementuje IINUIAddVoiceShortcutViewControllerDelegate i IINUIEditVoiceShortcutViewControllerDelegate.

Testowanie na urządzeniu

Aby uruchomić aplikację Soup Chef na urządzeniu, postępuj zgodnie z instrukcjami w tej sekcji. Przeczytaj również notatkę dotyczącą automatycznej aprowizacji.

Grupa aplikacji, identyfikatory aplikacji, profile aprowizacji

W sekcji Certyfikaty identyfikatory i profile w portalu dla deweloperów firmy Apple wykonaj następujące czynności:

  • Utwórz grupę aplikacji, aby udostępniać dane między aplikacją Soup Chef i jej rozszerzeniami. Na przykład: group.com.yourcompanyname.SoupChef

  • Utwórz trzy identyfikatory aplikacji: jeden dla samej aplikacji, jeden dla rozszerzenia Intents i jeden dla rozszerzenia Interfejs użytkownika Intents. Na przykład:

    • Aplikacja: com.yourcompanyname.SoupChef

      • Do tego identyfikatora aplikacji przypisz możliwości SiriKit i Grupy aplikacji.
    • Rozszerzenie intencji: com.yourcompanyname.SoupChef.Intents

      • Do tego identyfikatora aplikacji przypisz możliwość grup aplikacji.
    • Rozszerzenie interfejsu użytkownika intents: com.yourcompanyname.SoupChef.Intentsui

      • Ten identyfikator aplikacji nie wymaga specjalnych możliwości.
  • Po utworzeniu powyższych identyfikatorów aplikacji zmodyfikuj funkcję Grupy aplikacji przypisaną do aplikacji i rozszerzenia Intents, określając utworzoną wcześniej grupę aplikacji.

  • Utwórz trzy nowe profile aprowizacji programowania— jeden dla każdego nowego identyfikatora aplikacji.

  • Pobierz te profile aprowizacji i kliknij dwukrotnie każdy z nich, aby go zainstalować. Jeśli Visual Studio dla komputerów Mac lub Visual Studio 2017 jest już uruchomiony, uruchom go ponownie, aby upewnić się, że rejestruje nowe profile aprowizacji.

Edytowanie pliku Info.plist, Entitlements.plist i kodu źródłowego

W programie Visual Studio dla komputerów Mac lub Visual Studio 2017 wykonaj następujące czynności:

  • Zaktualizuj różne pliki Info.plist w rozwiązaniu. Ustaw identyfikator pakietu pakietu aplikacji, rozszerzenia Intents i intents UI na zdefiniowane wcześniej identyfikatory aplikacji:

    • Aplikacja: com.yourcompanyname.SoupChef
    • Intents Extension: com.yourcompanyname.SoupChef.Intents
    • Rozszerzenie interfejsu użytkownika intents: com.yourcompanyname.SoupChef.Intentsui
  • Zaktualizuj plik Entitlements.plist projektu SoupChef:

    • W przypadku możliwości grup aplikacji ustaw grupę na nowo utworzoną wcześniej grupę aplikacji (w powyższym przykładzie została group.com.twojafirmaname.SoupChef).
    • Upewnij się, że zestaw SiriKit jest włączony.
  • Zaktualizuj plik Entitlements.plist projektu SoupChefIntents:

    • W przypadku możliwości grup aplikacji ustaw grupę na nowo utworzoną wcześniej grupę aplikacji (w powyższym przykładzie została group.com.twojafirmaname.SoupChef).
  • Na koniec otwórz NSUserDefaultsHelper.cs. Ustaw zmienną AppGroup na wartość nowej grupy aplikacji (na przykład ustaw ją na group.com.yourcompanyname.SoupChefwartość ).

Konfigurowanie ustawień kompilacji

W programie Visual Studio dla komputerów Mac lub Visual Studio 2017:

  • Otwórz opcje/właściwości projektu SoupChef . Na karcie Podpisywanie pakietu systemu iOS ustaw opcję Tożsamość podpisywania na profil automatycznego i aprowizacji na nowo utworzony wcześniej profil aprowizacji specyficzny dla aplikacji.

  • Otwórz opcje/właściwości projektu SoupChefIntents . Na karcie Podpisywanie pakietu systemu iOS ustaw opcję Tożsamość podpisywania na profil automatycznego i aprowizacji na nowo utworzony wcześniej profil aprowizacji specyficzny dla rozszerzenia Intents.

  • Otwórz opcje/właściwości projektu SoupChefIntentsUI . Na karcie Podpisywanie pakietu systemu iOS ustaw opcję Tożsamość podpisywania na profil automatycznego i aprowizacji na nowo utworzony profil aprowizacji specyficzny dla rozszerzenia intencji interfejsu użytkownika.

Po wprowadzeniu tych zmian aplikacja zostanie uruchomiona na urządzeniu z systemem iOS.

Automatyczna aprowizacja

Za pomocą automatycznej aprowizacji można wykonać wiele z tych zadań aprowizacji bezpośrednio w środowisku IDE. Automatyczna aprowizacja nie konfiguruje jednak grup aplikacji. Musisz ręcznie skonfigurować pliki Entitlements.plist o nazwie grupy aplikacji, której chcesz użyć, odwiedź portal deweloperów firmy Apple, aby utworzyć grupę aplikacji, przypisać tę grupę aplikacji do każdego identyfikatora aplikacji utworzonego przez automatyczną aprowizację, ponownie wygenerować profile aprowizacji (aplikacja, rozszerzenie Intencje, rozszerzenie interfejsu użytkownika intencji), aby uwzględnić nowo utworzoną grupę aplikacji, i pobierz i zainstaluj je.