Siri-Tastenkombinationen in Xamarin.iOS

In iOS 10 hat Apple SiriKit eingeführt, sodass Messaging, VoIP-Anrufe, Zahlungen, Training, Fahrbuchungs- und Fotosuche-Apps erstellt werden können, die mit Siri interagieren.

In iOS 11 hat SiriKit Unterstützung für mehr Arten von Apps und mehr Flexibilität bei der Anpassung der Benutzeroberfläche erhalten.

iOS 12 fügt Siri-Tastenkombinationen hinzu, sodass alle Arten von Apps ihre Funktionen für Siri verfügbar machen können. Siri lernt, wenn bestimmte app-basierte Aufgaben für den Benutzer am relevantesten sind und dieses Wissen verwendet, um potenzielle Aktionen über Verknüpfungen vorzuschlagen. Durch Tippen auf eine Tastenkombination oder das Aufrufen mit einem Sprachbefehl wird eine App geöffnet oder eine Hintergrundaufgabe ausgeführt.

Tastenkombinationen sollten verwendet werden, um die Fähigkeit eines Benutzers zu beschleunigen, eine häufige Aufgabe auszuführen – in vielen Fällen, ohne die betreffende App sogar zu öffnen.

Beispiel-App: Suppenkoch

Um Siri Shortcuts besser zu verstehen, sehen Sie sich die Beispiel-App "Suppenkoch " an. Der Suppenkoch ermöglicht es Benutzern, Bestellungen aus einem imaginären Suppenrestaurant zu tätigen, ihre Bestellgeschichte anzuzeigen und Ausdrücke zu definieren, die beim Bestellen von Suppen verwendet werden sollen, indem sie mit Siri interagieren.

Tipp

Aktivieren Sie vor dem Testen von Soup Chef auf einem iOS 12-Simulator oder -Gerät die folgenden beiden Einstellungen, die beim Debuggen von Verknüpfungen nützlich sind:

  • Aktivieren Sie in der Einstellungen-App "Entwickleranzeige > zuletzt verwendete Verknüpfungen".
  • Aktivieren Sie in der Einstellungen-App "Entwickleranzeige > spenden" auf dem Sperrbildschirm.

Diese Debugeinstellungen erleichtern das Auffinden kürzlich erstellter (statt vorhergesagter) Verknüpfungen auf dem iOS-Sperrbildschirm und dem Suchbildschirm.

So verwenden Sie die Beispiel-App:

  • Installieren und ausführen Sie die Soup Chef-Beispiel-App auf einem iOS 12-Simulator oder -Gerät.
  • Klicken Sie in der oberen rechten Ecke auf die + Schaltfläche, um eine neue Reihenfolge zu erstellen.
  • Wählen Sie eine Art Suppe aus, geben Sie eine Menge und Optionen an, und tippen Sie auf "Bestellung aufgeben".
  • Tippen Sie auf dem Bildschirm "Bestellverlauf " auf die neu erstellte Bestellung, um die Details anzuzeigen.
  • Tippen Sie unten im Bildschirm "Bestelldetails" auf " Zu Siri hinzufügen".
  • Notieren Sie einen Sprachausdruck, um der Reihenfolge zuzuordnen, und tippen Sie auf "Fertig".
  • Minimieren Sie den Suppenkoch, rufen Sie Siri auf, und platzieren Sie die Bestellung erneut, indem Sie den sprachausdruck verwenden, den Sie aufgezeichnet haben.
  • Nachdem Siri die Bestellung abgeschlossen hat, öffnen Sie den Suppenkoch erneut, und beachten Sie, dass die neue Bestellung auf dem Bildschirm "Bestellverlauf " aufgeführt ist.

Die Beispiel-App veranschaulicht Folgendes:

Info.plist und Entitlements.plist

Bevor Sie sich tiefer in den Code des Suppenkochs eingraben, sehen Sie sich die Dateien "Info.plist" und "Entitlements.plist" an.

Info.plist

Die Datei "Info.plist " im Projekt "SoupChef " definiert den Bündelbezeichner als com.xamarin.SoupChef. Dieser Bündelbezeichner wird als Präfix für die Bündelbezeichner der Intents- und Intents-UI-Erweiterungen verwendet, die weiter unten in diesem Dokument erläutert werden.

Die Datei Info.plist enthält auch den folgenden Eintrag:

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

Dieses NSUserActivityTypes Schlüssel-Wert-Paar gibt an, dass Suppenkoch weiß, wie man mit einem ActivityTypeOrderSoupIntentNSUserActivity "com.xamarin.SoupChef.viewMenu" umgeht.

Aktivitäten und benutzerdefinierte Absichten, die an die App selbst übergeben werden, im Gegensatz zu den Erweiterungen, werden in der AppDelegate (eine UIApplicationDelegate von der ContinueUserActivity Methode) behandelt.

Entitlements.plist

Die Datei "Entitlements.plist " im Projekt "SoupChef " enthält die folgenden Einträge:

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

Diese Konfiguration gibt an, dass die App die App "group.com.xamarin.SoupChef" verwendet. Die App-Erweiterung "SoupChefIntents " verwendet dieselbe App-Gruppe, mit der die beiden Projekte gemeinsam verwendet werden können. NSUserDefaults Daten.

Der com.apple.developer.siri Schlüssel gibt an, dass die App mit Siri interagiert.

Hinweis

Die Buildkonfiguration des SoupChef-Projekts legt benutzerdefinierte Berechtigungen auf "Entitlements.plist" fest.

Verwenden einer NSUserActivity-Verknüpfung zum Öffnen einer App

Um eine Verknüpfung zu erstellen, mit der eine App zum Anzeigen bestimmter Inhalte geöffnet wird, erstellen Sie eine NSUserActivity App, und fügen Sie sie an den Ansichtscontroller für den Bildschirm an, den Sie öffnen möchten.

Einrichten einer NSUserActivity

Erstellt auf dem Menübildschirm SoupMenuViewController eine NSUserActivity Und weist sie der Eigenschaft des Ansichtscontrollers UserActivity zu:

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

Das Festlegen der UserActivity Immobilie spendet die Aktivität an Siri. Von dieser Spende erhält Siri Informationen darüber, wann und wo diese Aktivität für den Benutzer relevant ist und lernt, es in Zukunft besser vorzuschlagen.

NSUserActivityHelper ist eine Hilfsklasse, die in der SoupChef-Lösung enthalten ist, in der Klassenbibliothek "SoupKit ". Es erstellt eine NSUserActivity und legt verschiedene Eigenschaften im Zusammenhang mit Siri und suche:

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

Beachten Sie insbesondere die folgenden Features:

  • Die Einstellung EligibleForPrediction zeigt true an, dass Siri diese Aktivität vorhersagen und als Verknüpfung anzeigen kann.
  • Das ContentAttributeSet Array ist ein Standard CSSearchableItemAttributeSet , der verwendet wird, um eine NSUserActivity in iOS-Suchergebnisse einzuschließen.
  • SuggestedInvocationPhrase ist ein Ausdruck, den Siri dem Benutzer als mögliche Wahl vorschlagen wird, wenn er einer Verknüpfung einen Ausdruck zuweist.

Behandeln einer NSUserActivity-Verknüpfung

Um eine NSUserActivity verknüpfung zu behandeln, die von einem Benutzer aufgerufen wird, muss eine iOS-Anwendung NSUserActivity die ContinueUserActivity Methode der AppDelegate Klasse überschreiben und basierend auf dem ActivityType Feld des übergebenen Objekts reagieren:

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

Diese Methode ruft die HandleUserActivitySegue auf dem Menübildschirm auf und ruft sie auf:

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

Zuweisen eines Ausdrucks zu einer NSUserActivity

Um einer NSUserActivityApp einen Ausdruck zuzuweisen, öffnen Sie die iOS-Einstellungen-App, und wählen Sie Siri & Search > My Shortcuts aus. Wählen Sie dann die Verknüpfung (in diesem Fall "Mittagessen bestellen") aus, und notieren Sie einen Ausdruck.

Wenn Sie Siri aufrufen und diesen Ausdruck verwenden, wird der Suppenkoch auf dem Menübildschirm geöffnet.

Verwenden einer benutzerdefinierten Absichtsverknüpfung zum Ausführen einer Aufgabe

Definieren einer benutzerdefinierten Absicht

Um eine Verknüpfung bereitzustellen, mit der ein Benutzer schnell eine bestimmte Aufgabe im Zusammenhang mit Ihrer App ausführen kann, erstellen Sie eine benutzerdefinierte Absicht. Eine benutzerdefinierte Absicht stellt eine Aufgabe dar, die ein Benutzer möglicherweise abschließen möchte, Parameter, die für diese Aufgabe relevant sind, und potenzielle Antworten, die sich aus der Ausführung der Aufgabe ergeben. Je nachdem, wie eine benutzerdefinierte Absicht definiert ist, kann das Aufrufen der App entweder ihre App öffnen oder eine Hintergrundaufgabe ausführen.

Verwenden Sie Xcode 10, um benutzerdefinierte Absichten zu erstellen. Im Repository "SoupChef" wird der benutzerdefinierte Intent in OrderSoupIntentCodeGen definiert, einem Objective-C Projekt. Öffnen Sie dieses Projekt, und wählen Sie die Intents.intentdefinition-Datei im Project Navigator aus, um die OrderSoup-Absicht anzuzeigen.

Beachten Sie die folgenden Features:

  • Die Absicht hat eine Kategorie der Bestellung. Es gibt verschiedene vordefinierte Kategorien, die für benutzerdefinierte Absichten verwendet werden können; wählen Sie die Aufgabe aus, die ihrer benutzerdefinierten Absicht am ehesten entspricht. Da es sich bei dieser Lösung um eine Suppenbestellungs-App handelt, verwendet OrderSoupIntent "Order".
  • Das Bestätigungskontrollkästchen gibt an, ob Siri eine Bestätigung anfordern muss, bevor die Aufgabe ausgeführt wird. Für den Auftrag Suppenabsicht im Suppenkoch ist diese Option aktiviert, da der Benutzer einen Kauf vornimmt.
  • Im Abschnitt "Parameters" der Intentdefinition-Datei werden die für eine Verknüpfung relevanten Parameter definiert. Um eine Suppenbestellung zu bestellen, muss der Suppenkoch die Art der Suppe, seine Menge und alle zugehörigen Optionen kennen. Jeder Parameter hat einen Typ; Parameter, der nicht durch einen vordefinierten Typ dargestellt werden kann, werden als benutzerdefiniert festgelegt.
  • Die Benutzeroberfläche für Tastenkombinationen beschreibt die verschiedenen Parameterkombinationen, die Siri verwenden kann, wenn Sie Ihre Verknüpfung vorschlagen. Mit den zugehörigen Abschnitten "Titel " und "Untertitel " können Sie die Nachrichten definieren, die Siri beim Präsentieren einer vorgeschlagenen Verknüpfung für den Benutzer verwendet.
  • Das Kontrollkästchen "Hintergrundausführung unterstützt" sollte für alle Tastenkombinationen aktiviert werden, die ausgeführt werden können, ohne die App für weitere Benutzerinteraktionen zu öffnen.

Definieren von benutzerdefinierten Absichtsantworten

Das unter der OrderSoup-Absicht geschachtelte Antwortelement stellt die potenziellen Antworten dar, die aus einer Suppenreihenfolge resultieren.

Beachten Sie in der Antwortdefinition der OrderSoup-Absicht die folgenden Features:

  • Die Eigenschaften einer Antwort können verwendet werden, um die nachricht anzupassen, die dem Benutzer mitgeteilt wurde. Die OrderSoup-Absichtsantwort verfügt über Suppen - und WaitTime-Eigenschaften .
  • Die Antwortvorlagen geben die verschiedenen Erfolgs- und Fehlermeldungen an, die verwendet werden können, um den Status anzuzeigen, nachdem die Aufgabe einer Absicht abgeschlossen wurde.
  • Das Kontrollkästchen "Erfolg " sollte für Antworten aktiviert werden, die den Erfolg angeben.
  • Die Erfolgsantwort orderSoupIntent verwendet die Suppen - und WaitTime-Eigenschaften , um eine freundliche und nützliche Nachricht bereitzustellen, die beschreibt, wann die Suppenbestellung bereit ist.

Generieren von Code für die benutzerdefinierte Absicht

Durch das Erstellen des Xcode-Projekts, das diese benutzerdefinierte Absichtsdefinition enthält, generiert Xcode Code, der für die programmgesteuerte Interaktion mit der benutzerdefinierten Absicht und den zugehörigen Antworten verwendet werden kann.

So zeigen Sie diesen generierten Code an:

  • Öffnen Sie AppDelegate.m.
  • Fügen Sie einen Import zur Headerdatei der benutzerdefinierten Absicht hinzu: #import "OrderSoupIntent.h"
  • Fügen Sie in einer beliebigen Methode der Klasse einen Verweis auf OrderSoupIntent.
  • Klicken Sie mit der rechten Maustaste, OrderSoupIntent und wählen Sie "Zur Definition springen" aus.
  • Klicken Sie mit der rechten Maustaste in die neu geöffnete Datei " OrderSoupIntent.h", und wählen Sie " In Finder anzeigen" aus.
  • Diese Aktion öffnet ein Finder-Fenster, das eine H- und M-Datei enthält, die den generierten Code enthält.

Dieser generierte Code umfasst:

  • OrderSoupIntent – Eine Klasse, die die benutzerdefinierte Absicht darstellt.
  • OrderSoupIntentHandling – Ein Protokoll, das die Methoden definiert, die verwendet werden, um zu bestätigen, dass die Absicht ausgeführt werden soll, und die Methode, die sie tatsächlich ausführt.
  • OrderSoupIntentResponseCode – Eine Enumeration, die verschiedene Antwortstatus definiert.
  • OrderSoupIntentResponse – eine Klasse, die die Antwort auf die Ausführung einer Absicht darstellt.

Erstellen einer Bindung an die benutzerdefinierte Absicht

Um den von Xcode generierten Code in einer Xamarin.iOS-App zu verwenden, erstellen Sie eine C#-Bindung dafür.

Erstellen einer statischen Bibliothek und C#-Bindungsdefinitionen

Sehen Sie sich im Repository "SoupChef" den Ordner "OrderSoupIntentStaticLib " an, und öffnen Sie das Projekt "OrderSoupIntentStaticLib.xcodeproj Xcode".

Dieses Cocoa Touch Static Library-Projekt enthält die Dateien OrderSoupIntent.h und OrderSoupIntent.m, die von Xcode generiert werden.

Konfigurieren der Buildeinstellungen für statische Bibliotheken

Wählen Sie im Xcode-Projektnavigator das Projekt der obersten Ebene, OrderSoupIntentStaticLib, aus, und navigieren Sie zu Buildphasen kompilierungsquellen>. Beachten Sie, dass OrderSoupIntent.m (der OrderSoupIntent.h importiert) hier aufgeführt ist. Beachten Sie in "Binärdatei mit Bibliotheken verknüpfen", dass Intents.framework und Foundation.framework enthalten sind. Mit diesen Einstellungen wird das Framework ordnungsgemäß erstellt.

Erstellen der statischen Bibliothek und Generieren von C#-Bindungendefinitionen

Führen Sie die folgenden Schritte aus, um die statische Bibliothek zu erstellen und C#-Bindungen zu generieren:

  • Installieren Sie Objective Sharpie, das Tool verwendet, um Bindungen aus den von Xcode erstellten H - und M-Dateien zu generieren.

  • Konfigurieren Sie Ihr System so, dass Xcode 10-Befehlszeilentools verwendet werden:

    Warnung

    Das Aktualisieren der ausgewählten Befehlszeilentools wirkt sich auf alle installierten Versionen von Xcode auf Ihrem System aus. Wenn Sie die Beispiel-App "Soup Chef" verwendet haben, müssen Sie diese Einstellung unbedingt auf die ursprüngliche Konfiguration rückgängig machen.

    • Wählen Sie in Xcode die Option "Xcode-Einstellungsspeicherorte >>" aus, und legen Sie die Befehlszeilentools auf die neueste Xcode 10-Installation fest, die auf Ihrem System verfügbar ist.
  • Im Terminal cd , zum Verzeichnis OrderSoupIntentStaticLib .

  • Typ make, der erstellt:

    • Die statische Bibliothek libOrderSoupIntentStaticLib.a
    • Im Bo-Ausgabeverzeichnis binden C#-Bindungen:
      • ApiDefinitions.cs
      • StructsAndEnums.cs

Das Projekt OrderSoupIntentBindings , das auf dieser statischen Bibliothek und den zugehörigen Bindungen basiert, erstellt diese Elemente automatisch. Die manuelle Ausführung durch den obigen Prozess stellt jedoch sicher, dass er wie erwartet erstellt wird.

Weitere Informationen zum Erstellen einer statischen Bibliothek und zum Erstellen von C#-Bindungen mit Objective Sharpie finden Sie in der exemplarischen Vorgehensweise zum Binden einer iOS-BibliothekObjective-C.

Erstellen einer Bindungsbibliothek

Nachdem die statische Bibliothek und die C#-Bindungen erstellt wurden, ist das re Standard ing-Element, das zum Verwenden des Xcode-generierten intent-bezogenen Codes in einem Xamarin.iOS-Projekt erforderlich ist, eine Bindungsbibliothek.

Öffnen Sie im Repository "Suppenkoch" die Datei "SoupChef.sln ". Diese Lösung enthält unter anderem "OrderSoupIntentBinding", eine Bindungensbibliothek für die zuvor generierte statische Bibliothek.

Beachten Sie insbesondere, dass dieses Projekt Folgendes umfasst:

  • ApiDefinitions.cs – Eine Datei, die zuvor von Objective Sharpie generiert und diesem Projekt hinzugefügt wurde. Die Buildaktion dieser Datei ist auf "ObjcBindingApiDefinition" festgelegt.

  • StructsAndEnums.cs – Eine weitere Datei, die zuvor von Objective Sharpie generiert und diesem Projekt hinzugefügt wurde. Die Buildaktion dieser Datei ist auf ObjcBindingCoreSource festgelegt.

  • Ein nativer Verweis auflibOrderSoupIntentStaticLib.a, die statische Bibliothek, die zuvor erstellt wurde. Aktualisieren Sie die systemeigenen Referenzeigenschaften, und geben Sie die folgenden Werte an:

    1. Frameworks = Foundation Intents
    2. Smart Link = On
    3. Last erzwingen = On
    4. Art = Static

Hinweis

Sowohl ApiDefinitions.cs als auch StructsAndEnums.cs enthalten Attribute wie [Watch (5,0), iOS (12,0)]. Diese Attribute, die von Objective Sharpie generiert werden, wurden auskommentiert, da sie für dieses Projekt nicht erforderlich sind.

Weitere Informationen zum Erstellen einer C#-Bindungsbibliothek finden Sie in der exemplarischen Vorgehensweise zum Binden einer iOS-BibliothekObjective-C.

Beachten Sie, dass das SoupChef-Projekt einen Verweis auf OrderSoupIntentBinding enthält, was bedeutet, dass es jetzt in C# auf die Klassen, Schnittstellen und Enumerationen zugreifen kann, die es enthält:

  • OrderSoupIntent
  • OrderSoupIntentHandling
  • OrderSoupIntentResponse
  • OrderSoupIntenseResponseCode

Erstellen eines Swift-Frameworks

Der systemeigene Absichtsdefinitionscode wird standardmäßig mithilfe der Sprache Ihres nativen Projekts von Xcode generiert. Wenn Sie die Intents.intentdefinition-Datei in einem Swift-Projekt definieren, generiert Xcode Eine einzelne Swift-Datei mit allen erforderlichen Klassen, die Sie zum Erstellen eines Swift-Frameworks verwenden können.

Tipp

Sie können eine gewünschte Sprache für den generierten Absichtscode in den Xcode-Buildeinstellungen auswählen. Wechseln Sie zum Zielbuild > Einstellungen > Intent Definition Compiler – Codegenerierung, und wählen Sie entweder Swift oder Objective-C. Sie können die Zielsprache auch automatisch anpassen.

Der Prozess der Erstellung eines Swift-Frameworks ähnelt dem zuvor beschriebenen:

  1. Erstellen Sie ein neues Swift-Framework-Projekt.
  2. Kopieren Sie die automatisch generierte Swift-Datei mit Absichtscode in dieses Projekt, sie finden Sie wie hier beschrieben.
  3. Aktivieren Sie den ÜberbrückungsheaderObjective-C, sodass das Framework automatisch mit der erforderlichen Objective-C Sharpie-Headerdatei generiert wird.

Nachdem das Framework erstellt wurde, führen Sie die gleichen Schritte aus, die weiter oben beschrieben wurden, um eine Xamarin-Bindung zu erstellen. Weitere Informationen zum Erstellen einer Bindung für ein Swift-Framework finden Sie hier.

Hinzufügen der Absichtsdefinitionsdatei zu Ihrer Lösung

In der C# -SoupChef-Lösung enthält das SoupKit-Projekt Code, der zwischen der App und den Erweiterungen gemeinsam genutzt wird. Die Intents.intentdefinition-Datei wurde im Base.lproj-Verzeichnis von SoupKit platziert und verfügt über eine Buildaktion von Inhalt. Der Buildvorgang kopiert diese Datei in das Suppe Chef-App-Bündel, wo es erforderlich ist, dass die App ordnungsgemäß funktioniert.

Donating an intent

Damit Siri eine Verknüpfung vorschlagen kann, muss sie zuerst verstehen, wann die Verknüpfung relevant ist.

Um Siri dieses Verständnis zu geben, spendet Suppenkoch jedes Mal, wenn der Benutzer eine Suppenbestellung an Siri spendet. Basierend auf dieser Spende – als sie gespendet wurde, wo sie gespendet wurde, lernt Siri, wann die Verknüpfung in der Zukunft vorgeschlagen werden soll.

SuppeChef nutzt die SoupOrderDataManager Klasse, um Spenden zu tätigen. Wenn aufgerufen wird, eine Suppenbestellung für einen Benutzer zu platzieren, ruft die PlaceOrder Methode wiederum auf DonateInteraction:

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

Nach dem Abrufen einer Absicht wird sie in eine INInteractionumschlossen. Dies INInteraction ist ein Identifier die mit der eindeutigen ID der Bestellung übereinstimmt (es ist später hilfreich, wenn Absichtsspenden gelöscht werden, die nicht mehr gültig sind). Dann wird die Interaktion an Siri gespendet.

Der Aufruf an den order.Intent Getter ruft eine, OrderSoupIntent die die Reihenfolge darstellt, indem sie deren Quantity, Soup, Optionsund Bild und einen Aufrufausdruck festlegen, der als Vorschlag verwendet werden soll, wenn der Benutzer einen Ausdruck für Siri aufzeichnet, der dem Zweck zugeordnet werden soll:

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

Entfernen ungültiger Spenden

Es ist wichtig, Spenden zu entfernen, die nicht mehr gültig sind, damit Siri keine hilfreichen oder verwirrenden Verknüpfungsvorschläge macht.

Im Suppenkoch kann der Bildschirm "Menü konfigurieren" verwendet werden, um ein Menüelement als nicht verfügbar zu markieren. Siri sollte keine Verknüpfung mehr vorschlagen, um das nicht verfügbare Menüelement zu bestellen, daher löscht die RemoveDonation Methode SoupMenuManager spenden für Menüelemente, die nicht mehr verfügbar sind. Die App implementiert diese Funktionalität durch:

  • Suchen nach Bestellungen, die dem jetzt nicht verfügbaren Menüelement zugeordnet sind.
  • Greifen Sie auf ihre Bezeichner zu.
  • Löschen von Interaktionen mit denselben Bezeichnern.
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");
            }
        });
    }
}

Überprüfen erfolgreicher Spenden

Die Lösung umfasst mehrere Projekte und eine bestimmte Konfiguration. In einigen Fällen kann die Anwendung aufgrund einer unvollständigen Konfiguration abstürzen, in anderen Fällen kann es im Hintergrund fehlschlagen, eine Interaktion zu spenden. Es ist wichtig, erfolgreiche Spenden und iOS-Entwicklereinstellungen zu überprüfen. Navigieren Sie zu Einstellungen > Entwickler, und aktivieren Sie die folgenden Entwickleroptionen, um aktuelle Spenden und Verknüpfungen anzuzeigen:

  • Zuletzt verwendete Tastenkombinationen anzeigen
  • Spenden auf dem Sperrbildschirm anzeigen

Nach der Aktivierung wird jede erfolgreiche Spende auf dem Sperrbildschirm und unterhalb der Siri-Vorschläge-Optionen angezeigt. Wenn nach dem Ausführen Ihrer Anwendung dort keine Spenden angezeigt werden, lesen Sie die folgenden Problembehandlungsfälle:

  1. Eine App kann den OrderSoupIntent folgenden Fehler nicht erstellen:

    Eine systemeigene Instanz des Typs "NativeLibrary.OrderSoupIntent" konnte nicht erstellt werden: Die systemeigene Klasse wurde nicht geladen.

    Dieser Fehler bedeutet, dass Xamarin die systemeigene Klasse nicht über die Xamarin-Bindung laden kann. Um dies zu beheben, stellen Sie sicher, dass die systemeigene Bibliothek den erforderlichen Code enthält, auf den vom Bindungsprojekt verwiesen wird, und die richtigen Flags werden festgelegt, wie hier beschrieben, die Force Load Kennzeichnung auf On.

  2. Eine App initialisiert die geladene systemeigene Instanz der Intent-Klasse nicht mit dem folgenden Fehler:

    Eine Instanz des Typs "NativeLibrary.OrderSoupIntent" konnte nicht initialisiert werden: Die systemeigene "init"-Methode hat nil zurückgegeben.

    Das Problem bezieht sich auf die fehlende Intent-Definitionsdatei. Die Xamarin-App sollte die ursprüngliche Intent-Definitionsdatei mit dem Content Typ enthalten, wie hier beschrieben.

  3. Eine App erstellt die Absicht und ruft die Spendenmethode ohne Absturz auf, aber die Konsolenausgabe zeigt eine Warnung zu unbekanntem Absichtstyp an, und es wird keine Spende getätigt:

    Interaktion mit OrderSoupIntent, die keine gültigen Tastenkombinationstypen enthält, kann nicht gespendet werden.

    Um das Problem zu beheben, muss die Absicht in der plist ordnungsgemäß definiert sein, Siri-Berechtigung muss für die aktuelle Buildkonfiguration über Projekteinstellungen aktiviert und ausgewählt werden.

    Die Info.plist der App:

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

    Die Berechtigungsliste der App mit der Siri-Funktion:

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

    Benutzerdefinierte Berechtigungen sollten für die zielorientierte Buildkonfiguration ausgewählt werden. Wechseln Sie zu project settings > Build > iOS Bundle Signing, und legen Sie benutzerdefinierte Berechtigungen auf die Datei "Entitlements.plist" fest, die die erforderlichen Berechtigungen enthält.

Erstellen einer Intents-Erweiterung

Der Code, der ausgeführt wird, wenn Siri eine Absicht aufruft, wird in eine Intents-Erweiterung eingefügt, die als neues Projekt zur gleichen Lösung wie eine vorhandene Xamarin.iOS-App wie Soup Chef hinzugefügt werden kann. In der SuppeChef Lösung heißt die Erweiterung " SoupChefIntents".

SoupChefIntents – Info.plist und Entitlements.plist

SoupChefIntents – Info.plist

Die Info.plist im Projekt "SoupChefIntents " definiert den Bündelbezeichner als com.xamarin.SoupChef.SoupChefIntents.

Die Datei Info.plist enthält auch den folgenden Eintrag:

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

In der obigen Info.plist:

  • IntentsRestrictedWhileLocked listet absichten auf, die behandelt werden sollen, wenn das Gerät entsperrt ist.
  • IntentsSupported listet die Absichten auf, die von dieser Erweiterung behandelt werden.
  • NSExtensionPointIdentifier Gibt den Typ der App-Erweiterung an. Weitere Informationen finden Sie in der Apple-Dokumentation.
  • NSExtensionPrincipalClass Gibt die Klasse an, die zum Behandeln von Absichten verwendet werden soll, die von dieser Erweiterung unterstützt werden.
SoupChefIntents – Entitlements.plist

Die "Entitlements.plist " im Projekt "SoupChefIntents " verfügt über die App-Gruppenfunktion . Diese Funktion ist so konfiguriert, dass dieselbe App-Gruppe wie das SoupChef-Projekt verwendet wird:

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

Suppenkoch speichert Daten mit NSUserDefaults. Um Daten zwischen der App und der App-Erweiterung freizugeben, verweisen sie in den Dateien "Entitlements.plist " auf dieselbe App-Gruppe.

Hinweis

Die Buildkonfiguration des Projekts "SoupChefIntents" legt benutzerdefinierte Berechtigungen auf "Entitlements.plist" fest.

Behandeln einer OrderSoupIntent-Hintergrundaufgabe

Eine Intents-Erweiterung führt die erforderlichen Hintergrundaufgaben für eine Verknüpfung basierend auf einer benutzerdefinierten Absicht aus.

Siri ruft die GetHandler Methode der IntentHandler Klasse (definiert in Info.plist als die NSExtensionPrincipalClass) auf, um eine Instanz einer Klasse abzurufen, die erweitert OrderSoupIntentHandlingwird, die verwendet werden kann, um eine 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, definiert im SoupKit-Projekt des freigegebenen Codes, implementiert zwei wichtige Methoden:

  • ConfirmOrderSoup – Bestätigt, ob die mit der Absicht verknüpfte Aufgabe tatsächlich ausgeführt werden soll.
  • HandleOrderSoup – Platziert die Suppenreihenfolge und reagiert auf den Benutzer, indem er den passed-in-Abschlusshandler aufruft

Behandeln einer OrderSoupIntent, die die App öffnet

Eine App muss Absichten, die nicht im Hintergrund ausgeführt werden, ordnungsgemäß verarbeiten. Diese Absichten werden auf die gleiche Weise wie NSUserActivity Tastenkombinationen in der ContinueUserActivity Methode von 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;
    }
    // ...
}  

Bereitstellen einer Benutzeroberfläche für eine benutzerdefinierte Absicht

Eine Intents-UI-Erweiterung stellt eine benutzerdefinierte Benutzeroberfläche für eine Intents-Erweiterung bereit. In der SoupChef-Lösung ist SoupChefIntentsUI eine Intents UI-Erweiterung, die eine Schnittstelle für SoupChefIntents bereitstellt.

SoupChefIntentsUI – Info.plist und Entitlements.plist

SoupChefIntentsUI – Info.plist

Die Info.plist im SoupChefIntentsUI-Projekt definiert den Bundle Identifier als com.xamarin.SoupChef.SoupChefIntentsui.

Die Datei Info.plist enthält auch den folgenden Eintrag:

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

In der obigen Info.plist:

  • IntentsSupported gibt an, dass dies OrderSoupIntent von dieser Intents-UI-Erweiterung behandelt wird.
  • NSExtensionPointIdentifier Gibt den Typ der App-Erweiterung an. Weitere Informationen finden Sie in der Apple-Dokumentation.
  • NSExtensionMainStoryboard Gibt das Storyboard an, das die primäre Schnittstelle dieser Erweiterung definiert.

SoupChefIntentsUI – Entitlements.plist

Das Projekt "SoupChefIntentsUI " benötigt keine Datei "Entitlements.plist ".

Erstellen der Benutzeroberfläche

Da die Info.plist für SoupChefIntentsUI den NSExtensionMainStoryboard Schlüssel festlegt MainInterface, definiert die Datei "MainInterace.storyboard " die Schnittstelle für die Intents UI-Erweiterung.

In diesem Storyboard gibt es einen einzelnen Ansichtscontroller vom Typ IntentViewController. Es verweist auf zwei Ansichten:

  • invoiceView, vom Typ InvoiceView
  • confirmationView, vom Typ ConfirmOrderView

Hinweis

Die Schnittstellen für invoiceView und confirmationView werden in "Main.storyboard " als sekundäre Ansichten definiert. Visual Studio für Mac und Visual Studio 2017 bieten keine Unterstützung für das Anzeigen oder Bearbeiten sekundärer Ansichten; öffnen Sie dies.Main.storyboard im Schnittstellen-Generator von Xcode.

IntentViewController implementiert die IINUIHostedViewControlling Schnittstelle, die verwendet wird, um eine benutzerdefinierte Schnittstelle beim Arbeiten mit Siri Intents bereitzustellen. Der ConfigureView die Methode wird aufgerufen, um die Schnittstelle anzupassen, die Bestätigung oder die Rechnung anzuzeigen, je nachdem, ob die Interaktion bestätigt (INIntentHandlingStatus.Ready) oder erfolgreich ausgeführt wurde (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);
}

Tipp

Weitere Informationen zu der Methode finden Sie in der ConfigureView WwDC 2017-Präsentation von Apple, What's New in SiriKit.

Erstellen einer Sprachkombination

Suppenkoch bietet eine Schnittstelle, um jeder Bestellung eine Sprachkombination zuzuweisen, sodass es möglich ist, Suppe mit Siri zu bestellen. Tatsächlich wird die Schnittstelle zum Aufzeichnen und Zuweisen von Sprachverknüpfungen von iOS bereitgestellt und erfordert wenig benutzerdefinierten Code.

Wenn OrderDetailViewControllerein Benutzer auf die Zeile "Zur Siri hinzufügen" der Tabelle tippt, zeigt die RowSelected Methode einen Bildschirm an, um eine Sprachkombination hinzuzufügen oder zu bearbeiten:

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

Basierend darauf, ob für die aktuell angezeigte Reihenfolge eine vorhandene Sprachkombination vorhanden ist, RowSelected wird ein Ansichtscontroller vom Typ INUIEditVoiceShortcutViewController oder INUIAddVoiceShortcutViewController. Legt sich in jedem Fall OrderDetailViewController als Ansichtscontroller Delegatefest, weshalb er auch implementiert IINUIAddVoiceShortcutViewControllerDelegate und IINUIEditVoiceShortcutViewControllerDelegate.

Testen auf dem Gerät

Um Suppenkoch auf einem Gerät auszuführen, folgen Sie den Anweisungen in diesem Abschnitt. Lesen Sie auch die Notiz zur automatischen Bereitstellung.

App-Gruppe, App-IDs, Bereitstellungsprofile

Führen Sie im Abschnitt "Zertifikate, IDs & Profile " des Apple Developer Portals die folgenden Schritte aus:

  • Erstellen Sie eine App-Gruppe, um Daten zwischen der Soup Chef-App und ihren Erweiterungen zu teilen. Beispiel: group.com.yourcompanyname.SoupChef

  • Erstellen Sie drei App-IDs: eine für die App selbst, eine für die Intents-Erweiterung und eine für die Intents-UI-Erweiterung. Beispiel:

    • App: com.yourcompanyname.SoupChef

      • Weisen Sie dieser App-ID die Funktionen SiriKit und App-Gruppen zu.
    • Intents-Erweiterung: com.yourcompanyname.SoupChef.Intents

      • Weisen Sie dieser App-ID die App-Gruppenfunktion zu.
    • Intents UI-Erweiterung: com.yourcompanyname.SoupChef.Intentsui

      • Diese App-ID benötigt keine speziellen Funktionen.
  • Nachdem Sie die obigen App-IDs erstellt haben, bearbeiten Sie die App-Gruppenfunktion , die der App und der Intents-Erweiterung zugewiesen ist, und geben Sie die zuvor erstellte bestimmte App-Gruppe an.

  • Erstellen Sie drei neue Entwicklungsbereitstellungsprofile, eines für jede der neuen App-IDs.

  • Laden Sie diese Bereitstellungsprofile herunter, und doppelklicken Sie auf die einzelnen Profile, um sie zu installieren. Wenn Visual Studio für Mac oder Visual Studio 2017 bereits ausgeführt wird, starten Sie es neu, um sicherzustellen, dass die neuen Bereitstellungsprofile registriert werden.

Bearbeiten von Info.plist, Entitlements.plist und Quellcode

Führen Sie in Visual Studio für Mac oder Visual Studio 2017 die folgenden Schritte aus:

  • Aktualisieren Sie die verschiedenen Info.plist-Dateien in der Lösung. Legen Sie die App, die Intents-Erweiterung und den Intents UI-Erweiterungsbundle-Bezeichner auf die zuvor definierten App-IDs fest:

    • App: com.yourcompanyname.SoupChef
    • Intents Extension: com.yourcompanyname.SoupChef.Intents
    • Intents UI-Erweiterung: com.yourcompanyname.SoupChef.Intentsui
  • Aktualisieren Sie die Datei "Entitlements.plist " für das Projekt "SoupChef ":

    • Legen Sie für die App-Gruppenfunktion die Gruppe auf die zuvor erstellte neue App-Gruppe fest (im obigen Beispiel lautete "group.com.yourcompanyname.SoupChef").
    • Stellen Sie sicher, dass SiriKit aktiviert ist.
  • Aktualisieren Sie die Datei "Entitlements.plist " für das Projekt "SoupChefIntents ":

    • Legen Sie für die App-Gruppenfunktion die Gruppe auf die zuvor erstellte neue App-Gruppe fest (im obigen Beispiel lautete "group.com.yourcompanyname.SoupChef").
  • Öffnen Sie schließlich NSUserDefaultsHelper.cs. Legen Sie die AppGroup Variable auf den Wert Ihrer neuen App-Gruppe fest (z. B. auf group.com.yourcompanyname.SoupChef).

Konfigurieren der Buildeinstellungen

In Visual Studio für Mac oder Visual Studio 2017:

  • Öffnen Sie die Optionen/Eigenschaften für das SoupChef-Projekt . Legen Sie auf der Registerkarte "Signierung des iOS-Bündels" die Signaturidentität auf das neue app-spezifische Bereitstellungsprofil fest, das Sie zuvor erstellt haben.

  • Öffnen Sie die Optionen/Eigenschaften für das Projekt "SoupChefIntents ". Legen Sie auf der Registerkarte "Signierung des iOS-Bündels" die Signaturidentität auf das zuvor erstellte neue Erweiterungserweiterungsprofil fest.

  • Öffnen Sie die Optionen/Eigenschaften für das Projekt "SoupChefIntentsUI ". Legen Sie auf der Registerkarte "Signierung des iOS-Bündels" die Signaturidentität auf das zuvor erstellte neue Erweiterungsprofil für die Intents-BEnutzeroberfläche fest.

Mit diesen Änderungen wird die App auf einem iOS-Gerät ausgeführt.

Automatische Bereitstellung

Sie können die automatische Bereitstellung verwenden, um viele dieser Bereitstellungsaufgaben direkt in der IDE auszuführen. Die automatische Bereitstellung richtet jedoch keine App-Gruppen ein. Sie müssen die Dateien "Entitlements.plist " manuell mit dem Namen der App-Gruppe konfigurieren, die Sie verwenden möchten, das Apple Developer Portal besuchen, um die App-Gruppe zu erstellen, diese App-Gruppe jeder App-ID zuzuweisen, die durch die automatische Bereitstellung erstellt wurde, die Bereitstellungsprofile (App, Intents Extension, Intents UI-Erweiterung) neu zu erstellen, um die neu erstellte App-Gruppe einzuschließen, und laden Sie sie herunter, und installieren Sie sie.