Tasti di scelta rapida siri in Xamarin.iOS

In iOS 10 Apple ha introdotto SiriKit, consentendo di creare messaggi, chiamate VoIP, pagamenti, allenamenti, prenotazione di corse e app di ricerca foto che interagiscono con Siri.

In iOS 11 SiriKit ha ottenuto il supporto per più tipi di app e maggiore flessibilità per la personalizzazione dell'interfaccia utente.

iOS 12 aggiunge collegamenti Siri, consentendo a tutti i tipi di app di esporre le funzionalità a Siri. Siri apprende quando alcune attività basate su app sono più rilevanti per l'utente e usano questa conoscenza per suggerire potenziali azioni tramite collegamenti. Toccando un collegamento o richiamandolo con un comando vocale, si aprirà un'app o si eseguirà un'attività in background.

I tasti di scelta rapida devono essere usati per accelerare la capacità di un utente di eseguire un'attività comune, in molti casi senza nemmeno aprire l'app in questione.

App di esempio: Soup Chef

Per comprendere meglio i tasti di scelta rapida di Siri, vedere l'app di esempio Soup Chef . Soup Chef consente agli utenti di effettuare ordini da un ristorante di zuppa immaginaria, visualizzare la cronologia degli ordini e definire frasi da usare per ordinare zuppa interagendo con Siri.

Suggerimento

Prima di testare Soup Chef in un simulatore o un dispositivo iOS 12, abilitare le due impostazioni seguenti, utili durante il debug dei tasti di scelta rapida:

  • Nell'app Impostazioni abilitare i tasti di scelta rapida recenti visualizzati dallo sviluppatore>.
  • Nell'app Impostazioni abilitare Le donazioni per la visualizzazione degli sviluppatori > nella schermata di blocco.

Queste impostazioni di debug semplificano la ricerca di collegamenti creati di recente (anziché stimati) nella schermata di blocco iOS e nella schermata di ricerca.

Per usare l'app di esempio:

  • Installare ed eseguire l'app di esempio Soup Chef in un simulatore o un dispositivo iOS 12.
  • Fare clic sul + pulsante nell'angolo superiore destro per creare un nuovo ordine.
  • Selezionare un tipo di zuppa, specificare una quantità e opzioni e toccare Inserisci ordine.
  • Nella schermata Cronologia ordini toccare l'ordine appena creato per visualizzarne i dettagli.
  • Nella parte inferiore della schermata dei dettagli dell'ordine toccare Aggiungi a Siri.
  • Registrare una frase vocale da associare all'ordine e toccare Fine.
  • Ridurre al minimo Soup Chef, richiamare Siri e riordinare l'ordine usando la frase vocale registrata.
  • Dopo che Siri ha completato l'ordine, riapriRe Soup Chef e notare che il nuovo ordine è elencato nella schermata Cronologia ordini.

L'app di esempio illustra come:

Info.plist e Entitlements.plist

Prima di approfondire il codice Soup Chef, esaminare i relativi file Info.plist e Entitlements.plist .

Info.plist

Il file Info.plist nel progetto SoupChef definisce l'identificatore bundle come com.xamarin.SoupChef. Questo identificatore di bundle verrà usato come prefisso per gli identificatori bundle delle estensioni finalità e finalità dell'interfaccia utente descritte più avanti in questo documento.

Il file Info.plist contiene anche la voce seguente:

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

Questa NSUserActivityTypes coppia chiave/valore indica che Soup Chef sa come gestire un OrderSoupIntentoggetto e un oggetto NSUserActivity con " ActivityType com.xamarin.SoupChef.viewMenu".

Le attività e le finalità personalizzate passate all'app stessa, anziché le relative estensioni, vengono gestite in AppDelegate (da un UIApplicationDelegate metodo ContinueUserActivity .

Entitlements.plist

Il file Entitlements.plist nel progetto SoupChef contiene le voci seguenti:

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

Questa configurazione indica che l'app usa il gruppo di app "group.com.xamarin.SoupChef". L'estensione dell'app SoupChefIntents usa lo stesso gruppo di app, che consente ai due progetti di condividere NSUserDefaults Dati.

La com.apple.developer.siri chiave indica che l'app interagisce con Siri.

Nota

La configurazione di compilazione del progetto SoupChef imposta entitlement personalizzati su Entitlements.plist.

Uso di un collegamento NSUserActivity per aprire un'app

Per creare un collegamento che apre un'app per visualizzare contenuto specifico, creare un oggetto NSUserActivity e collegarlo al controller di visualizzazione per la schermata che si desidera aprire il collegamento.

Configurazione di un'attività NSUserActivity

Nella schermata del menu crea SoupMenuViewController un oggetto NSUserActivity e lo assegna alla proprietà del controller di UserActivity visualizzazione:

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

Impostando la proprietà, l'attività UserActivity viene donata a Siri. Da questa donazione Siri ottiene informazioni su quando e dove questa attività è rilevante per l'utente e impara a suggerire meglio in futuro.

NSUserActivityHelper è una classe di utilità inclusa nella soluzione SoupChef , nella libreria di classi SoupKit . Crea un oggetto NSUserActivity e imposta varie proprietà correlate a Siri e alla ricerca:

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

Si notino in particolare le funzionalità seguenti:

  • L'impostazione EligibleForPrediction su true indica che Siri può prevedere questa attività e visualizzarla come collegamento.
  • La ContentAttributeSet matrice è uno standard CSSearchableItemAttributeSet usato per includere un nei NSUserActivity risultati della ricerca iOS.
  • SuggestedInvocationPhrase è una frase che Siri suggerisce all'utente come potenziale scelta quando si assegna una frase a un collegamento.

Gestione di un collegamento NSUserActivity

Per gestire un NSUserActivity collegamento richiamato da un utente, un'applicazione iOS deve eseguire l'override del ContinueUserActivity metodo della AppDelegate classe, rispondendo in base al ActivityType campo dell'oggetto passato NSUserActivity :

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

Questo metodo chiama HandleUserActivity, che trova il segue nella schermata del menu e lo richiama:

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

Assegnazione di una frase a un NSUserActivity

Per assegnare una frase a un oggetto , aprire l'app iOS Impostazioni e scegliere Siri & Search My Shortcuts .To assign a phrase to an NSUserActivity, open the iOS Impostazioni app and choose Siri & Search > My Shortcuts. Selezionare quindi il collegamento (in questo caso "Order Lunch") e registrare una frase.

Richiamando Siri e usando questa frase si aprirà Soup Chef nella schermata del menu.

Uso di un collegamento di finalità personalizzato per eseguire un'attività

Definizione di una finalità personalizzata

Per fornire un collegamento che consente a un utente di completare rapidamente un'attività specifica correlata all'app, creare una finalità personalizzata. Una finalità personalizzata rappresenta un'attività che un utente può voler completare, i parametri rilevanti per tale attività e le potenziali risposte risultanti dall'esecuzione dell'attività. A seconda della modalità di definizione di una finalità personalizzata, richiamarla può aprire l'app o eseguire un'attività in background.

Usare Xcode 10 per creare finalità personalizzate. Nel repository SoupChef la finalità personalizzata viene definita in OrderSoupIntentCodeGen, un Objective-C progetto. Aprire questo progetto e selezionare il file Intents.intentdefinition nello strumento di navigazione del progetto per visualizzare la finalità OrderSoup.

Prestare attenzione alle funzionalità seguenti:

  • La finalità ha una categoria di ordine. Esistono diverse categorie predefinite che possono essere usate per finalità personalizzate; selezionare quella che corrisponde più strettamente all'attività che verrà abilitata dalla finalità personalizzata. Poiché questa soluzione è un'app per l'ordinamento di zuppa, OrderSoupIntent usa Order.
  • La casella di controllo Conferma indica se Siri deve richiedere o meno conferma prima di eseguire l'attività. Per la finalità Order Soup in Soup Chef, questa opzione è abilitata perché l'utente sta effettuando un acquisto.
  • La sezione Parameters del file con estensione intentdefinition definisce i parametri rilevanti per un collegamento. Per effettuare un ordine di zuppa, Soup Chef deve conoscere il tipo di zuppa, la sua quantità e tutte le opzioni associate. Ogni parametro ha un tipo; il parametro che non può essere rappresentato da un tipo predefinito viene impostato su Custom.
  • L'interfaccia Tipi di collegamento descrive le varie combinazioni di parametri che Siri può usare quando suggerisce il collegamento. Le sezioni Titolo e Sottotitolo associate consentono di definire i messaggi che Siri userà quando si presenta un collegamento suggerito all'utente.
  • La casella di controllo Supporta l'esecuzione in background deve essere selezionata per qualsiasi collegamento che può essere eseguito senza aprire l'app per un'ulteriore interazione dell'utente.

Definizione di risposte con finalità personalizzate

L'elemento Response annidato sotto la finalità OrderSoup rappresenta le potenziali risposte risultanti da un ordine di zuppa.

Nella definizione di risposta della finalità OrderSoup prendere nota delle funzionalità seguenti:

  • Le proprietà di una risposta possono essere usate per personalizzare il messaggio comunicato all'utente. La risposta della finalità OrderSoup ha proprietà soup e waitTime .
  • I modelli di risposta specificano i vari messaggi di esito positivo e negativo che possono essere usati per indicare lo stato dopo il completamento dell'attività di una finalità.
  • La casella di controllo Operazione riuscita deve essere selezionata per le risposte che indicano l'esito positivo.
  • La risposta di successo OrderSoupIntent usa le proprietà soup e waitTime per fornire un messaggio descrittivo e utile che descrive quando l'ordine di zuppa sarà pronto.

Generazione di codice per la finalità personalizzata

La compilazione del progetto Xcode contenente questa definizione di finalità personalizzata fa sì che Xcode generi codice che può essere usato per interagire a livello di codice con la finalità personalizzata e le relative risposte.

Per visualizzare questo codice generato:

  • Aprire AppDelegate.m.
  • Aggiungere un'importazione al file di intestazione della finalità personalizzata: #import "OrderSoupIntent.h"
  • In qualsiasi metodo della classe aggiungere un riferimento a OrderSoupIntent.
  • Fare clic con il pulsante destro del mouse su OrderSoupIntent e scegliere Passa alla definizione.
  • Fare clic con il pulsante destro del mouse nel file appena aperto, OrderSoupIntent.h e selezionare Mostra nel Finder.
  • Questa azione aprirà una finestra del Finder che contiene un file con estensione h e m contenente il codice generato.

Questo codice generato include:

  • OrderSoupIntent : classe che rappresenta la finalità personalizzata.
  • OrderSoupIntentHandling : protocollo che definisce i metodi che verranno usati per confermare che la finalità deve essere eseguita e il metodo che lo esegue effettivamente.
  • OrderSoupIntentResponseCode : enumerazione che definisce vari stati di risposta.
  • OrderSoupIntentResponse : classe che rappresenta la risposta all'esecuzione di una finalità.

Creazione di un'associazione alla finalità personalizzata

Per usare il codice generato da Xcode in un'app Xamarin.iOS, creare un'associazione C#.

Creazione di una libreria statica e di definizioni di associazione C#

Nel repository SoupChef esaminare la cartella OrderSoupIntentStaticLib e aprire il progetto OrderSoupIntentStaticLib.xcodeproj Xcodeproj.

Questo progetto Cocoa Touch Static Library contiene i file OrderSoupIntent.h e OrderSoupIntent.m generati da Xcode.

Configurazione delle impostazioni di compilazione del progetto di libreria statica

In Strumento di spostamento progetto Xcode selezionare il progetto di primo livello, OrderSoupIntentStaticLib e passare a Compilazione fasi Compila origini>. Si noti che OrderSoupIntent.m (che importa OrderSoupIntent.h) è elencato qui. In Collegamento binario con librerie si noti che sono inclusi Intents.framework e Foundation.framework . Con queste impostazioni sul posto, il framework verrà compilato correttamente.

Compilazione della libreria statica e generazione di definizioni di associazioni C#

Per compilare la libreria statica e generare definizioni di associazioni C#, seguire questa procedura:

  • Installare Objective Sharpie, lo strumento usato per generare definizioni di associazioni dai file con estensione h e m creati da Xcode.

  • Configurare il sistema per l'uso degli strumenti da riga di comando Xcode 10:

    Avviso

    L'aggiornamento degli strumenti da riga di comando selezionati influisce su tutte le versioni installate di Xcode nel sistema. Al termine dell'uso dell'app di esempio Soup Chef, assicurarsi di ripristinare questa impostazione alla configurazione originale.

    • In Xcode scegliere Percorsi preferenze > Xcode > e impostare Strumenti da riga di comando sull'installazione Xcode 10 più recente disponibile nel sistema.
  • Nel terminale passare cd alla directory OrderSoupIntentStaticLib .

  • Digitare make, che compila:

    • Libreria statica, libOrderSoupIntentStaticLib.a
    • Nella directory di output bo le definizioni delle associazioni C#:
      • ApiDefinitions.cs
      • StructsAndEnums.cs

Il progetto OrderSoupIntentBindings , che si basa su questa libreria statica e sulle definizioni delle associazioni associate, compila automaticamente questi elementi. Tuttavia, l'esecuzione manuale del processo precedente garantisce che venga compilata come previsto.

Per altre informazioni sulla creazione di una libreria statica e sull'uso di Objective Sharpie per creare definizioni di associazioni C#, vedere la procedura dettagliata Binding di una libreria iOSObjective-C.

Creazione di una libreria di associazioni

Con la libreria statica e le definizioni di associazioni C# create, la parte rimanente necessaria per usare il codice correlato alle finalità generate da Xcode in un progetto Xamarin.iOS è una libreria di binding.

Nel repository Soup Chef aprire il file SoupChef.sln. Tra le altre cose, questa soluzione contiene OrderSoupIntentBinding, una libreria di associazioni per la libreria statica generata in precedenza.

Si noti in particolare che questo progetto include:

  • ApiDefinitions.cs: file generato in precedenza da Objective Sharpie e aggiunto a questo progetto. L'azione di compilazione di questo file è impostata su ObjcBindingApiDefinition.

  • StructsAndEnums.cs : un altro file generato in precedenza da Objective Sharpie e aggiunto a questo progetto. L'azione di compilazione di questo file è impostata su ObjcBindingCoreSource.

  • Riferimento nativo a libOrderSoupIntentStaticLib.a, la libreria statica compilata in precedenza. Aggiornare le proprietà di riferimento native e specificare i valori seguenti:

    1. Framework = Foundation Intents
    2. Collegamento intelligente = On
    3. Force Load = On
    4. Tipo = Static

Nota

Sia ApiDefinitions.csche StructsAndEnums.cs contengono attributi come [Watch (5,0), iOS (12,0)]. Questi attributi, generati da Objective Sharpie, sono stati commentati perché non sono necessari per questo progetto.

Per altre informazioni sulla creazione di una libreria di associazioni C#, vedere la procedura dettagliata binding di una libreria iOSObjective-C.

Si noti che il progetto SoupChef contiene un riferimento a OrderSoupIntentBinding, il che significa che ora può accedere, in C#, alle classi, alle interfacce e alle enumerazioni che contiene:

  • OrderSoupIntent
  • OrderSoupIntentHandling
  • OrderSoupIntentResponse
  • OrderSoupIntenseResponseCode

Creazione di un framework Swift

Il codice nativo per la definizione della finalità viene generato da Xcode per impostazione predefinita usando il linguaggio del progetto nativo. Se si definisce il file Intents.intentdefinition in un progetto Swift, Xcode genererà un singolo file Swift con tutte le classi necessarie, che è possibile usare per creare un framework Swift.

Suggerimento

È possibile selezionare una lingua desiderata per il codice finalità generato nelle impostazioni di compilazione Xcode. Passare a Compilazione > finalità Impostazioni > compilatore di definizioni finalità - Generazione di codice e selezionare Swift o Objective-C. È anche possibile mantenerlo automatico in modo che corrisponda alla lingua di destinazione.

Il processo di creazione di un framework Swift è simile a quello descritto in precedenza:

  1. Creare un nuovo progetto framework Swift.
  2. Copiare il file Swift generato automaticamente con il codice intento in questo progetto, come descritto qui.
  3. Abilitare l'intestazioneObjective-C bridging, in modo che il framework venga generato automaticamente con il file di intestazione sharpie richiestoObjective-C.

Dopo aver compilato il framework, seguire la stessa procedura descritta in precedenza per creare un'associazione Xamarin. Per altre informazioni sulla creazione di un'associazione per un framework Swift, vedere qui.

Aggiunta del file di definizione della finalità alla soluzione

Nella soluzione C# SoupChef il progetto SoupKit contiene codice condiviso tra l'app e le relative estensioni. Il file Intents.intentdefinition è stato inserito nella directory Base.lproj di SoupKit e include un'azione di compilazione del contenuto. Il processo di compilazione copia questo file nel bundle dell'app Soup Chef, in cui è necessario che l'app funzioni correttamente.

Donating an intent

Per consentire a Siri di suggerire un collegamento, deve prima comprendere quando il collegamento è rilevante.

Per dare a Siri questa comprensione, Soup Chef dona una finalità a Siri ogni volta che l'utente inserisce un ordine di zuppa. Sulla base di questa donazione – quando è stata donata, dove è stata donata, i parametri che contiene – Siri impara quando suggerire il collegamento in futuro.

SoupChef usa la SoupOrderDataManager classe per inserire donazioni. Quando viene chiamato per inserire un ordine di zuppa per un utente, il PlaceOrder metodo a sua volta chiama DonateInteraction:

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

Dopo aver recuperato una finalità, viene eseguito il wrapping in un oggetto INInteraction. L'oggetto INInteraction viene assegnato a Identifier che corrisponde all'ID univoco dell'ordine (sarà utile in seguito quando si eliminano donazioni di finalità che non sono più valide). Quindi, l'interazione viene donata a Siri.

La chiamata al order.Intent getter recupera un oggetto OrderSoupIntent che rappresenta l'ordine impostando la relativa Quantityimmagine , Soup, Optionse un'immagine e una frase di chiamata da usare come suggerimento quando l'utente registra una frase per Siri da associare alla finalità:

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

Rimozione di donazioni non valide

È importante rimuovere le donazioni che non sono più valide in modo che Siri non faccia suggerimenti di scelta rapida inutili o confusi.

In Soup Chef la schermata Configura menu può essere usata per contrassegnare una voce di menu come non disponibile. Siri non dovrebbe più suggerire un collegamento per ordinare la voce di menu non disponibile, quindi il RemoveDonation metodo di elimina le donazioni per le voci di SoupMenuManager menu che non sono più disponibili. L'app implementa questa funzionalità in base a:

  • Ricerca di ordini associati alla voce di menu non disponibile.
  • Afferrare gli identificatori.
  • Eliminazione di interazioni con gli stessi identificatori.
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");
            }
        });
    }
}

Convalida delle donazioni riuscite

La soluzione include più progetti e una configurazione specifica. In alcuni casi, l'applicazione può arrestarsi in modo anomalo a causa di una configurazione incompleta, in altri casi può non riuscire a donare un'interazione in modo invisibile all'utente. È importante convalidare le donazioni riuscite e le impostazioni per sviluppatori iOS. Passare a Impostazioni > Sviluppatore e abilitare le opzioni per sviluppatori seguenti per visualizzare le donazioni e i collegamenti recenti:

  • Visualizza collegamenti recenti
  • Visualizzare le donazioni nella schermata di blocco

Una volta abilitata, ogni donazione di successo verrà visualizzata nella schermata di blocco e sotto le opzioni di suggerimenti di Siri. Se dopo l'esecuzione dell'applicazione non vengono visualizzate le donazioni, esaminare i seguenti casi di risoluzione dei problemi:

  1. Un'app non riesce a creare con OrderSoupIntent l'errore seguente:

    Impossibile creare un'istanza nativa del tipo 'NativeLibrary.OrderSoupIntent': la classe nativa non è stata caricata.

    Questo errore indica che Xamarin non è in grado di caricare la classe nativa tramite l'associazione Xamarin. Per risolvere questo problema, verificare che la libreria nativa includa il codice necessario, a cui fa riferimento il progetto di associazione e che siano impostati flag appropriati, come descritto di seguito, impostare il Force Load flag su On.

  2. Un'app non riesce a inizializzare l'istanza nativa caricata della classe intent con l'errore seguente:

    Impossibile inizializzare un'istanza del tipo 'NativeLibrary.OrderSoupIntent': il metodo nativo 'init' ha restituito nil.

    Il problema è correlato al file di definizione delle finalità mancante. L'app Xamarin deve includere il file di definizione della finalità originale con il Content tipo , come descritto qui.

  3. Un'app crea la finalità e chiama il metodo donate senza un arresto anomalo, ma l'output della console mostra un avviso relativo al tipo di finalità sconosciuto e non viene effettuata alcuna donazione:

    Impossibile donare l'interazione con OrderSoupIntent senza tipi di collegamento validi

    Per risolvere il problema, la finalità deve essere definita correttamente nell'elenco plist, il diritto siri deve essere abilitato e selezionato per la configurazione di compilazione corrente tramite le impostazioni del progetto.

    Info.plist dell'app:

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

    Entitlements.plist dell'app con la funzionalità Siri:

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

    I diritti personalizzati devono essere selezionati per la configurazione di compilazione di destinazione. Passare a Impostazioni progetto > Compilare > firma bundle iOS e impostare Entitlement personalizzati sul file Entitlements.plist contenente i diritti necessari.

Creazione di un'estensione Intents

Il codice eseguito quando Siri richiama una finalità viene inserito in un'estensione Intents, che può essere aggiunto come nuovo progetto alla stessa soluzione di un'app Xamarin.iOS esistente, ad esempio Soup Chef. Nella soluzione SoupChef l'estensione è denominata SoupChefIntents.

SoupChefIntents - Info.plist e Entitlements.plist

SoupChefIntents - Info.plist

Il file Info.plist nel progetto SoupChefIntents definisce l'identificatore bundle come com.xamarin.SoupChef.SoupChefIntents.

Il file Info.plist contiene anche la voce seguente:

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

Nell'info.plist precedente:

  • IntentsRestrictedWhileLocked elenca le finalità da gestire quando il dispositivo viene sbloccato.
  • IntentsSupported elenca le finalità gestite da questa estensione.
  • NSExtensionPointIdentifier specifica il tipo di estensione dell'app. Per altre informazioni, vedere la documentazione di Apple.
  • NSExtensionPrincipalClass specifica la classe che deve essere utilizzata per gestire le finalità supportate da questa estensione.
SoupChefIntents - Entitlements.plist

Entitlements.plist nel progetto SoupChefIntents ha la funzionalità Gruppi di app. Questa funzionalità è configurata per usare lo stesso gruppo di app del progetto SoupChef :

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

Soup Chef rende persistenti i dati con NSUserDefaults. Per condividere i dati tra l'app e l'estensione dell'app, fanno riferimento allo stesso gruppo di app nei file Entitlements.plist .

Nota

La configurazione di compilazione del progetto SoupChefIntents imposta entitlement personalizzati su Entitlements.plist.

Gestione di un'attività in background OrderSoupIntent

Un'estensione Intents esegue le attività in background necessarie per un collegamento basato su una finalità personalizzata.

Siri chiama il GetHandler metodo della IntentHandler classe (definita in Info.plist come NSExtensionPrincipalClass) per ottenere un'istanza di una classe che estende OrderSoupIntentHandling, che può essere usata per gestire un oggetto 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, definito nel progetto SoupKit di codice condiviso, implementa due metodi importanti:

  • ConfirmOrderSoup : conferma se l'attività associata alla finalità deve essere effettivamente eseguita
  • HandleOrderSoup – Inserisce l'ordine di zuppa e risponde all'utente chiamando il gestore di completamento passato

Gestione di un OrderSoupIntent che apre l'app

Un'app deve gestire correttamente le finalità che non vengono eseguite in background. Queste finalità vengono gestite nello stesso modo dei NSUserActivity tasti di scelta rapida, nel ContinueUserActivity metodo di 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;
    }
    // ...
}  

Fornire un'interfaccia utente per una finalità personalizzata

Un'estensione dell'interfaccia utente Intents fornisce un'interfaccia utente personalizzata per un'estensione Intents. Nella soluzione SoupChef SoupChefIntentsUI è un'estensione dell'interfaccia utente Intents che fornisce un'interfaccia per SoupChefIntents.

SoupChefIntentsUI - Info.plist e Entitlements.plist

SoupChefIntentsUI - Info.plist

Info.plist nel progetto SoupChefIntentsUI definisce l'identificatore del bundle come com.xamarin.SoupChef.SoupChefIntentsui.

Il file Info.plist contiene anche la voce seguente:

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

Nell'info.plist precedente:

  • IntentsSupported indica che l'oggetto OrderSoupIntent viene gestito da questa estensione dell'interfaccia utente intents.
  • NSExtensionPointIdentifier specifica il tipo di estensione dell'app. Per altre informazioni, vedere la documentazione di Apple.
  • NSExtensionMainStoryboard specifica lo storyboard che definisce l'interfaccia primaria di questa estensione

SoupChefIntentsUI - Entitlements.plist

Il progetto SoupChefIntentsUI non richiede un file Entitlements.plist .

Creazione dell'interfaccia utente

Poiché Info.plist per SoupChefIntentsUI imposta la NSExtensionMainStoryboard chiave su MainInterface, il file MainInterace.storyboard definisce l'interfaccia per l'estensione dell'interfaccia utente Intents.

In questo storyboard è presente un controller di visualizzazione singolo di tipo IntentViewController. Fa riferimento a due visualizzazioni:

  • invoiceView, di tipo InvoiceView
  • confirmationView, di tipo ConfirmOrderView

Nota

Le interfacce per invoiceView e confirmationView sono definite in Main.storyboard come visualizzazioni secondarie. Visual Studio per Mac e Visual Studio 2017 non supportano la visualizzazione o la modifica delle visualizzazioni secondarie. A tale scopo, aprire Main.storyboard in Interface Builder di Xcode.

IntentViewController implementa l'oggetto IINUIHostedViewControlling interfaccia, usata per fornire un'interfaccia personalizzata quando si usano le finalità siri. La ConfigureView viene chiamato per personalizzare l'interfaccia, visualizzare la conferma o la fattura, a seconda che l'interazione venga confermata (INIntentHandlingStatus.Ready) o che sia stata eseguita correttamente (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);
}

Suggerimento

Per altre informazioni sul metodo, guarda la ConfigureView presentazione WWDC 2017 di Apple, What's New in SiriKit.

Creazione di un collegamento vocale

Soup Chef fornisce un'interfaccia per assegnare un collegamento vocale a ogni ordine, rendendo possibile ordinare la zuppa con Siri. L'interfaccia usata per registrare e assegnare collegamenti vocali è infatti fornita da iOS e richiede poco codice personalizzato.

In OrderDetailViewController, quando un utente tocca la riga Aggiungi a Siri della tabella, il RowSelected metodo presenta una schermata per aggiungere o modificare un collegamento vocale:

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

In base al fatto che esista o meno un collegamento vocale esistente per l'ordine attualmente visualizzato, RowSelected presenta un controller di visualizzazione di tipo INUIEditVoiceShortcutViewController o INUIAddVoiceShortcutViewController. In ogni caso, OrderDetailViewController imposta se stesso come controller di Delegatevisualizzazione , motivo per cui implementa anche IINUIAddVoiceShortcutViewControllerDelegate e IINUIEditVoiceShortcutViewControllerDelegate.

Test nel dispositivo

Per eseguire Soup Chef in un dispositivo, seguire le istruzioni riportate in questa sezione. Leggere anche la nota sul provisioning automatico.

Gruppo di app, ID app, profili di provisioning

Nella sezione Certificati, ID e profili del portale per sviluppatori Apple seguire questa procedura:

  • Creare un gruppo di app per condividere i dati tra l'app Soup Chef e le relative estensioni. Ad esempio: group.com.nomeazienda.SoupChef

  • Creare tre ID app: uno per l'app stessa, uno per l'estensione Intents e uno per l'estensione dell'interfaccia utente Intents. Ad esempio:

    • App: com.yourcompanyname.SoupChef

      • A questo ID app assegnare le funzionalità SiriKit e Gruppi di app.
    • Estensione intents: com.yourcompanyname.SoupChef.Intents

      • A questo ID app assegnare la funzionalità Gruppi di app.
    • Estensione dell'interfaccia utente intents: com.yourcompanyname.SoupChef.Intentsui

      • Questo ID app non necessita di funzionalità speciali.
  • Dopo aver creato gli ID app precedenti, modificare la funzionalità Gruppi di app assegnata all'app e all'estensione Finalità, specificando il gruppo di app specifico creato in precedenza.

  • Creare tre nuovi profili di provisioning di sviluppo, uno per ognuno dei nuovi ID app.

  • Scaricare questi profili di provisioning e fare doppio clic su ognuno di essi per installarlo. Se Visual Studio per Mac o Visual Studio 2017 è già in esecuzione, riavviarlo per assicurarsi che registri i nuovi profili di provisioning.

Modifica di Info.plist, Entitlements.plist e codice sorgente

In Visual Studio per Mac o Visual Studio 2017 seguire questa procedura:

  • Aggiornare i vari file Info.plist nella soluzione. Impostare l'app, l'estensione Intents e l'identificatore bundle dell'estensione dell'interfaccia utente Intents su ID app definiti in precedenza:

    • App: com.yourcompanyname.SoupChef
    • Estensione Intents: com.yourcompanyname.SoupChef.Intents
    • Estensione dell'interfaccia utente intents: com.yourcompanyname.SoupChef.Intentsui
  • Aggiornare il file Entitlements.plist per il progetto SoupChef :

    • Per la funzionalità Gruppi di app, impostare il gruppo sul nuovo gruppo di app creato in precedenza (nell'esempio precedente è stato group.com.yourcompanyname.SoupChef).
    • Assicurarsi che SiriKit sia abilitato.
  • Aggiornare il file Entitlements.plist per il progetto SoupChefIntents :

    • Per la funzionalità Gruppi di app, impostare il gruppo sul nuovo gruppo di app creato in precedenza (nell'esempio precedente è stato group.com.yourcompanyname.SoupChef).
  • Aprire infine NSUserDefaultsHelper.cs. Impostare la AppGroup variabile sul valore del nuovo gruppo di app , ad esempio impostarla su group.com.yourcompanyname.SoupChef.

Configurazione delle impostazioni di compilazione

In Visual Studio per Mac o Visual Studio 2017:

  • Aprire le opzioni/proprietà per il progetto SoupChef . Nella scheda Firma bundle iOS impostare Identità di firma su Profilo di provisioning e automatico sul nuovo profilo di provisioning specifico dell'app creato in precedenza.

  • Aprire le opzioni/proprietà per il progetto SoupChefIntents . Nella scheda Firma bundle iOS impostare Identità di firma su Profilo di provisioning automatico e Provisioning sul nuovo profilo di provisioning specifico dell'estensione Intents creato in precedenza.

  • Aprire le opzioni/proprietà per il progetto SoupChefIntentsUI . Nella scheda Firma bundle iOS impostare Identità di firma su Profilo di provisioning automatico e Provisioning sul nuovo profilo di provisioning specifico dell'estensione dell'interfaccia utente intents creato in precedenza.

Con queste modifiche, l'app verrà eseguita in un dispositivo iOS.

Provisioning automatico

È possibile usare il provisioning automatico per eseguire molte di queste attività di provisioning direttamente nell'IDE. Tuttavia, il provisioning automatico non configura i gruppi di app. Sarà necessario configurare manualmente i file Entitlements.plist con il nome del gruppo di app che si vuole usare, visitare il portale per sviluppatori Apple per creare il gruppo di app, assegnare tale gruppo di app a ogni ID app creato tramite provisioning automatico, rigenerare i profili di provisioning (app, estensione Intents, estensione dell'interfaccia utente intenti) per includere il gruppo di app appena creato, e scaricarli e installarli.