Consegna in Xamarin.iOS
Questo articolo illustra l'uso di Handoff in un'app Xamarin.iOS per trasferire le attività utente tra app in esecuzione negli altri dispositivi dell'utente.
Apple ha introdotto Handoff in iOS 8 e OS X Yosemite (10.10) per fornire un meccanismo comune per consentire all'utente di trasferire le attività avviate in uno dei dispositivi, in un altro dispositivo che esegue la stessa app o un'altra app che supporta la stessa attività.
Questo articolo illustra in dettaglio l'abilitazione della condivisione delle attività in un'app Xamarin.iOS e illustra in dettaglio il framework Handoff:
Informazioni su Handoff
Handoff (noto anche come Continuità) è stato introdotto da Apple in iOS 8 e OS X Yosemite (10.10) come modo per consentire all'utente di avviare un'attività su uno dei propri dispositivi (iOS o Mac) e continuare la stessa attività su un altro dei propri dispositivi (come identificato dall'account iCloud dell'utente).
Handoff è stato ampliato in iOS 9 per supportare anche nuove funzionalità di ricerca avanzate. Per altre informazioni, vedere la documentazione relativa ai miglioramenti della ricerca.
Ad esempio, l'utente può avviare un messaggio di posta elettronica sul proprio i Telefono e continuare facilmente l'e-mail sul proprio Mac, con tutte le stesse informazioni sul messaggio compilate e il cursore nella stessa posizione in cui l'hanno lasciata in iOS.
Tutte le tue app che condividono lo stesso ID team sono idonee per l'uso di Handoff per continuare le attività degli utenti tra le app, purché queste app vengano recapitate tramite iTunes App Store o firmate da uno sviluppatore registrato (per Mac, Enterprise o app ad hoc).
Tutte NSDocument
le app basate su o UIDocument
includono automaticamente il supporto handoff predefinito e richiedono modifiche minime per supportare handoff.
Continuare le attività degli utenti
La NSUserActivity
classe (insieme ad alcune piccole modifiche a UIKit
e AppKit
) fornisce il supporto per la definizione dell'attività di un utente che può potenzialmente essere continuata in un altro dei dispositivi dell'utente.
Affinché un'attività venga passata a un altro dei dispositivi dell'utente, deve essere incapsulata in un'istanza NSUserActivity
, contrassegnata come attività corrente, avere il payload impostato (i dati usati per eseguire la continuazione) e l'attività deve quindi essere trasmessa a tale dispositivo.
L'handoff passa il minimo di informazioni per definire l'attività da continuare, con pacchetti di dati più grandi sincronizzati tramite iCloud.
Nel dispositivo ricevente, l'utente riceverà una notifica che informa che un'attività è disponibile per la continuazione. Se l'utente sceglie di continuare l'attività nel nuovo dispositivo, l'app specificata viene avviata (se non è già in esecuzione) e il payload da NSUserActivity
viene usato per riavviare l'attività.
Solo le app che condividono lo stesso ID del team di sviluppo e rispondono a un determinato tipo di attività sono idonee per la continuazione. Un'app definisce i tipi di attività supportati sotto la NSUserActivityTypes
chiave del relativo file Info.plist . Dato questo, un dispositivo continuo sceglie l'app per eseguire la continuazione in base all'ID team, al tipo di attività e, facoltativamente, al titolo dell'attività.
L'app ricevente usa le informazioni del NSUserActivity
dizionario del UserInfo
per configurare l'interfaccia utente e ripristinare lo stato dell'attività specificata in modo che la transizione venga visualizzata senza problemi all'utente finale.
Se la continuazione richiede più informazioni di quanto possa essere inviato in modo efficiente tramite un NSUserActivity
, l'app di ripresa può inviare una chiamata all'app di origine e stabilire uno o più flussi per trasmettere i dati necessari. Ad esempio, se l'attività stava modificando un documento di testo di grandi dimensioni con più immagini, lo streaming sarebbe necessario per trasferire le informazioni necessarie per continuare l'attività nel dispositivo ricevente. Per altre informazioni, vedere la sezione Support Continuation Flussi di seguito.
Come indicato in precedenza, NSDocument
le app basate su o UIDocument
includono automaticamente il supporto handoff predefinito. Per altre informazioni, vedere la sezione Supporto delle app basate su documenti di seguito.
Classe NSUserActivity
La NSUserActivity
classe è l'oggetto primario in uno scambio handoff e viene usato per incapsulare lo stato di un'attività utente disponibile per la continuazione. Un'app crea un'istanza di una copia di NSUserActivity
per qualsiasi attività supportata e vuole continuare su un altro dispositivo. Ad esempio, l'editor di documenti crea un'attività per ogni documento attualmente aperto. Tuttavia, solo il documento più anteriore (visualizzato nella finestra o nella scheda anteriore) è l'attività corrente e disponibile per la continuazione.
Un'istanza di NSUserActivity
viene identificata dalle relative ActivityType
proprietà e Title
. La UserInfo
proprietà del dizionario viene utilizzata per contenere informazioni sullo stato dell'attività. Impostare la NeedsSave
proprietà su true
se si desidera eseguire il caricamento differita delle informazioni sullo stato tramite il NSUserActivity
delegato del . Usare il AddUserInfoEntries
metodo per unire nuovi dati da altri client nel UserInfo
dizionario in base alle esigenze per mantenere lo stato dell'attività.
Classe NSUserActivityDelegate
Viene NSUserActivityDelegate
utilizzato per mantenere aggiornate le informazioni in un NSUserActivity
UserInfo
dizionario e sincronizzate con lo stato corrente dell'attività. Quando il sistema deve aggiornare le informazioni nell'attività , ad esempio prima della continuazione in un altro dispositivo, chiama il UserActivityWillSave
metodo del delegato.
Sarà necessario implementare il UserActivityWillSave
metodo e apportare eventuali modifiche a NSUserActivity
(ad esempio UserInfo
, Title
e così via) per assicurarsi che rifletta ancora lo stato dell'attività corrente. Quando il sistema chiama il UserActivityWillSave
metodo , il NeedsSave
flag verrà cancellato. Se si modifica una delle proprietà dei dati dell'attività, sarà necessario impostare NeedsSave
di nuovo su true
.
Invece di usare il UserActivityWillSave
metodo presentato in precedenza, è possibile avere UIKit
o AppKit
gestire automaticamente l'attività dell'utente. A tale scopo, impostare la proprietà dell'oggetto UserActivity
risponditore e implementare il UpdateUserActivityState
metodo . Per altre informazioni, vedere la sezione Supporto handoff nei risponditori di seguito.
Supporto di App Framework
Sia (iOS) che UIKit
AppKit
(OS X) forniscono il supporto predefinito per Handoff nelle NSDocument
classi , Responder (UIResponder
/NSResponder
) e AppDelegate
. Mentre ogni sistema operativo implementa handoff leggermente diversamente, il meccanismo di base e le API sono gli stessi.
Attività utente nelle app basate su documenti
Le app iOS e OS X basate su documenti includono automaticamente il supporto handoff predefinito. Per attivare questo supporto, dovrai aggiungere una chiave e un NSUbiquitousDocumentUserActivityType
valore per ogni CFBundleDocumentTypes
voce nel file Info.plist dell'app.
Se questa chiave è presente, entrambe NSDocument
e UIDocument
automaticamente creano NSUserActivity
istanze per i documenti basati su iCloud del tipo specificato. Dovrai fornire un tipo di attività per ogni tipo di documento supportato dall'app e più tipi di documento possono usare lo stesso tipo di attività. Sia NSDocument
che UIDocument
popolano automaticamente la UserInfo
proprietà di con il NSUserActivity
valore della proprietà FileURL
.
In OS X, l'oggetto NSUserActivity
gestito da AppKit
e associato ai risponditori diventa automaticamente l'attività corrente quando la finestra del documento diventa la finestra principale. In iOS, per NSUserActivity
gli oggetti gestiti da UIKit
, è necessario chiamare BecomeCurrent
il metodo in modo esplicito o impostare la proprietà del UserActivity
documento su un UIViewController
quando l'app si trova in primo piano.
AppKit
ripristina automaticamente qualsiasi UserActivity
proprietà creata in questo modo in OS X. Ciò si verifica se il ContinueUserActivity
metodo restituisce false
o se è non implementato. In questo caso, il documento viene aperto con il OpenDocument
metodo di NSDocumentController
e riceverà quindi una RestoreUserActivityState
chiamata al metodo .
Per altre informazioni, vedere la sezione Supporto delle app basate su documenti più avanti.
Attività e risponditori utente
Sia UIKit
che AppKit
possono gestire automaticamente un'attività utente se la si imposta come proprietà dell'oggetto UserActivity
risponditore. Se lo stato è stato modificato, sarà necessario impostare la NeedsSave
proprietà del risponditore UserActivity
su true
. Il sistema salverà automaticamente quando UserActivity
necessario, dopo aver dato al risponditore il tempo necessario per aggiornare lo stato chiamando il relativo UpdateUserActivityState
metodo.
Se più risponditori condividono una singola NSUserActivity
istanza, ricevono un UpdateUserActivityState
callback quando il sistema aggiorna l'oggetto attività utente. Il risponditore deve chiamare il metodo per aggiornare il AddUserInfoEntries
NSUserActivity
dizionario per UserInfo
riflettere lo stato dell'attività corrente a questo punto. Il UserInfo
dizionario viene cancellato prima di ogni UpdateUserActivityState
chiamata.
Per annullare l'associazione da un'attività, un risponditore può impostare la relativa UserActivity
proprietà su null
. Quando un'istanza gestita del framework dell'app NSUserActivity
non ha più risponditori o documenti associati, viene invalidata automaticamente.
Per altre informazioni, vedere la sezione Supporto handoff nei risponditori di seguito.
Attività utente e AppDelegate
L'app AppDelegate
è il punto di ingresso principale quando si gestisce una continuazione handoff. Quando l'utente risponde a una notifica handoff, l'app appropriata viene avviata (se non è già in esecuzione) e verrà chiamato il WillContinueUserActivityWithType
metodo di AppDelegate
. A questo punto, l'app deve informare l'utente che la continuazione è in corso.
L'istanza NSUserActivity
viene recapitata quando viene chiamato il AppDelegate
metodo .ContinueUserActivity
A questo punto, è necessario configurare l'interfaccia utente dell'app e continuare l'attività specificata.
Per altre informazioni, vedere la sezione Implementazione handoff di seguito.
Abilitazione dell'handoff in un'app Xamarin
A causa dei requisiti di sicurezza imposti da Handoff, un'app Xamarin.iOS che usa il framework Handoff deve essere configurata correttamente sia nel portale per sviluppatori Apple che nel file di progetto Xamarin.iOS.
Effettua le operazioni seguenti:
Accedere al portale per sviluppatori Apple.
Fare clic su Certificati, Identificatori e profili.
Se non è già stato fatto, fare clic su Identificatori e creare un ID per l'app ( ad esempio
com.company.appname
), altrimenti modificare l'ID esistente.Verificare che il servizio iCloud sia stato controllato per l'ID specificato:
Salva le modifiche.
Fare clic su Provisioning Profiles Development (Sviluppo profili>di provisioning) e creare un nuovo profilo di provisioning di sviluppo per l'app:
Scaricare e installare il nuovo profilo di provisioning o usare Xcode per scaricare e installare il profilo.
Modificare le opzioni del progetto Xamarin.iOS e assicurarsi di usare il profilo di provisioning appena creato:
Modificare quindi il file Info.plist e assicurarsi di usare l'ID app usato per creare il profilo di provisioning:
Scorrere fino alla sezione Modalità di sfondo e controllare gli elementi seguenti:
Salvare le modifiche apportate a tutti i file.
Con queste impostazioni, l'applicazione è ora pronta per accedere alle API handoff framework. Per informazioni dettagliate sul provisioning, vedere le guide Device Provisioning e Provisioning dell'app .
Implementazione dell'handoff
Le attività degli utenti possono essere continuate tra le app firmate con lo stesso ID team per sviluppatori e supportano lo stesso tipo di attività. L'implementazione di Handoff in un'app Xamarin.iOS richiede di creare un oggetto attività utente (in UIKit
o AppKit
), aggiornare lo stato dell'oggetto per tenere traccia dell'attività e continuare l'attività in un dispositivo ricevente.
Identificazione delle attività utente
Il primo passaggio nell'implementazione di Handoff consiste nell'identificare i tipi di attività utente supportate dall'app e vedere quali di queste attività sono buoni candidati per la continuazione in un altro dispositivo. Ad esempio, un'app ToDo potrebbe supportare la modifica di elementi come tipo di attività utente e supportare l'esplorazione dell'elenco di elementi disponibili come un altro.
Un'app può creare tutti i tipi di attività utente necessari, una per qualsiasi funzione fornita dall'app. Per ogni tipo di attività utente, l'app dovrà tenere traccia dell'inizio e della fine di un'attività del tipo e dovrà mantenere informazioni aggiornate sullo stato per continuare l'attività in un altro dispositivo.
Le attività utente possono essere continuate su qualsiasi app firmata con lo stesso ID team senza alcun mapping uno-a-uno tra l'invio e la ricezione delle app. Ad esempio, una determinata app può creare quattro diversi tipi di attività, utilizzate da app diverse e singole app in un altro dispositivo. Si tratta di un'occorrenza comune tra una versione Mac dell'app (che potrebbe avere molte funzionalità e funzioni) e le app iOS, in cui ogni app è più piccola e incentrata su un'attività specifica.
Creazione di identificatori del tipo di attività
L'identificatoredel tipo di attività è una stringa breve aggiunta alla NSUserActivityTypes
matrice del file Info.plist dell'app usata per identificare in modo univoco un determinato tipo di attività utente. Nella matrice sarà presente una voce per ogni attività supportata dall'app. Apple suggerisce di usare una notazione in stile DNS inversa per l'identificatore del tipo di attività per evitare conflitti. Ad esempio: com.company-name.appname.activity
per attività specifiche basate su app o com.company-name.activity
per attività che possono essere eseguite tra più app.
L'identificatore del tipo di attività viene usato durante la creazione di un'istanza NSUserActivity
per identificare il tipo di attività. Quando un'attività viene continuata in un altro dispositivo, il tipo di attività (insieme all'ID team dell'app) determina l'app da avviare per continuare l'attività.
Ad esempio, creeremo un'app di esempio denominata MonkeyBrowser. Questa app presenterà quattro schede, ognuna con un URL diverso aperto in una visualizzazione del Web browser. L'utente sarà in grado di continuare qualsiasi scheda in un dispositivo iOS diverso che esegue l'app.
Per creare gli identificatori del tipo di attività necessari per supportare questo comportamento, modificare il file Info.plist e passare alla visualizzazione Origine . Aggiungere una NSUserActivityTypes
chiave e creare gli identificatori seguenti:
Sono stati creati quattro nuovi identificatori del tipo di attività, uno per ognuna delle schede nell'app MonkeyBrowser di esempio. Quando si creano app personalizzate, sostituire il contenuto della NSUserActivityTypes
matrice con gli identificatori del tipo di attività specifici per le attività supportate dall'app.
Rilevamento delle modifiche delle attività utente
Quando si crea una nuova istanza della NSUserActivity
classe , verrà specificata un'istanza NSUserActivityDelegate
per tenere traccia delle modifiche apportate allo stato dell'attività. Ad esempio, il codice seguente può essere usato per tenere traccia delle modifiche dello stato:
using System;
using CoreGraphics;
using Foundation;
using UIKit;
namespace MonkeyBrowse
{
public class UserActivityDelegate : NSUserActivityDelegate
{
#region Constructors
public UserActivityDelegate ()
{
}
#endregion
#region Override Methods
public override void UserActivityReceivedData (NSUserActivity userActivity, NSInputStream inputStream, NSOutputStream outputStream)
{
// Log
Console.WriteLine ("User Activity Received Data: {0}", userActivity.Title);
}
public override void UserActivityWasContinued (NSUserActivity userActivity)
{
Console.WriteLine ("User Activity Was Continued: {0}", userActivity.Title);
}
public override void UserActivityWillSave (NSUserActivity userActivity)
{
Console.WriteLine ("User Activity will be Saved: {0}", userActivity.Title);
}
#endregion
}
}
Il UserActivityReceivedData
metodo viene chiamato quando un flusso di continuazione ha ricevuto dati da un dispositivo di invio. Per altre informazioni, vedere la sezione Support Continuation Flussi di seguito.
Il UserActivityWasContinued
metodo viene chiamato quando un altro dispositivo ha acquisito un'attività dal dispositivo corrente. A seconda del tipo di attività, ad esempio l'aggiunta di un nuovo elemento a un elenco ToDo, l'app potrebbe dover interrompere l'attività nel dispositivo di invio.
Il UserActivityWillSave
metodo viene chiamato prima che le modifiche apportate all'attività vengano salvate e sincronizzate tra i dispositivi disponibili in locale. È possibile utilizzare questo metodo per apportare modifiche dell'ultimo minuto alla UserInfo
proprietà dell'istanza prima dell'invio NSUserActivity
.
Creazione di un'istanza NSUserActivity
Ogni attività che l'app vuole fornire la possibilità di continuare in un altro dispositivo deve essere incapsulata in un'istanza NSUserActivity
di . L'app può creare tutte le attività necessarie e la natura di tali attività dipende dalle funzionalità e dalle funzionalità dell'app in questione. Ad esempio, un'app di posta elettronica potrebbe creare un'attività per la creazione di un nuovo messaggio e un'altra per la lettura di un messaggio.
Per l'app di esempio, viene creato un nuovo NSUserActivity
oggetto ogni volta che l'utente immette un nuovo URL in una delle visualizzazioni del Web browser a schede. Il codice seguente archivia lo stato di una determinata scheda:
public NSString UserActivityTab1 = new NSString ("com.xamarin.monkeybrowser.tab1");
public NSUserActivity UserActivity { get; set; }
...
UserActivity = new NSUserActivity (UserActivityTab1);
UserActivity.Title = "Weather Tab";
UserActivity.Delegate = new UserActivityDelegate ();
// Update the activity when the tab's URL changes
var userInfo = new NSMutableDictionary ();
userInfo.Add (new NSString ("Url"), new NSString (url));
UserActivity.AddUserInfoEntries (userInfo);
// Inform Activity that it has been updated
UserActivity.BecomeCurrent ();
Crea un nuovo NSUserActivity
oggetto usando uno dei tipi di attività utente creati in precedenza e fornisce un titolo leggibile per l'attività. Viene collegato a un'istanza dell'oggetto NSUserActivityDelegate
creato in precedenza per controllare le modifiche di stato e informa iOS che questa attività utente è l'attività corrente.
Popolamento del dizionario UserInfo
Come illustrato in precedenza, la UserInfo
proprietà della NSUserActivity
classe è una NSDictionary
delle coppie chiave-valore usate per definire lo stato di una determinata attività. I valori archiviati in UserInfo
devono essere uno dei tipi seguenti: NSArray
, , NSData
NSDate
, NSDictionary
, NSSet
NSString
NSNull
NSNumber
o .NSURL
NSURL
i valori dei dati che puntano ai documenti iCloud verranno modificati automaticamente in modo che puntino agli stessi documenti in un dispositivo ricevente.
Nell'esempio precedente è stato creato un NSMutableDictionary
oggetto e lo è stato popolato con una singola chiave che fornisce l'URL attualmente visualizzato dall'utente nella scheda specificata. Il AddUserInfoEntries
metodo dell'attività utente è stato usato per aggiornare l'attività con i dati che verranno usati per ripristinare l'attività nel dispositivo ricevente:
// Update the activity when the tab's URL changes
var userInfo = new NSMutableDictionary ();
userInfo.Add (new NSString ("Url"), new NSString (url));
UserActivity.AddUserInfoEntries (userInfo);
Apple suggerisce di mantenere le informazioni inviate al minimo minimo per garantire che l'attività venga inviata in modo tempestivo al dispositivo ricevente. Se sono necessarie informazioni più grandi, ad esempio un'immagine associata a un documento da modificare, è necessario usare il Flussi continuazione. Per altri dettagli, vedere la sezione Flussi di supporto della continuazione di seguito.
Continuazione di un'attività
Handoff informerà automaticamente i dispositivi iOS e OS X locali che si trovano in prossimità fisica al dispositivo di origine e hanno eseguito l'accesso allo stesso account iCloud, della disponibilità delle attività utente continuabili. Se l'utente sceglie di continuare un'attività in un nuovo dispositivo, il sistema avvierà l'app appropriata (in base all'ID team e al tipo di attività) e le informazioni AppDelegate
necessarie per la continuazione.
In primo luogo, il WillContinueUserActivityWithType
metodo viene chiamato in modo che l'app possa informare l'utente che la continuazione sta per iniziare. Nel file di AppDelegate.cs dell'app di esempio viene usato il codice seguente per gestire un'avvio di continuazione:
public NSString UserActivityTab1 = new NSString ("com.xamarin.monkeybrowser.tab1");
public NSString UserActivityTab2 = new NSString ("com.xamarin.monkeybrowser.tab2");
public NSString UserActivityTab3 = new NSString ("com.xamarin.monkeybrowser.tab3");
public NSString UserActivityTab4 = new NSString ("com.xamarin.monkeybrowser.tab4");
...
public FirstViewController Tab1 { get; set; }
public SecondViewController Tab2 { get; set;}
public ThirdViewController Tab3 { get; set; }
public FourthViewController Tab4 { get; set; }
...
public override bool WillContinueUserActivity (UIApplication application, string userActivityType)
{
// Report Activity
Console.WriteLine ("Will Continue Activity: {0}", userActivityType);
// Take action based on the user activity type
switch (userActivityType) {
case "com.xamarin.monkeybrowser.tab1":
// Inform view that it's going to be modified
Tab1.PreparingToHandoff ();
break;
case "com.xamarin.monkeybrowser.tab2":
// Inform view that it's going to be modified
Tab2.PreparingToHandoff ();
break;
case "com.xamarin.monkeybrowser.tab3":
// Inform view that it's going to be modified
Tab3.PreparingToHandoff ();
break;
case "com.xamarin.monkeybrowser.tab4":
// Inform view that it's going to be modified
Tab4.PreparingToHandoff ();
break;
}
// Inform system we handled this
return true;
}
Nell'esempio precedente ogni controller di visualizzazione viene registrato con AppDelegate
e ha un metodo pubblico PreparingToHandoff
che visualizza un indicatore attività e un messaggio che informa l'utente che l'attività sta per essere passata al dispositivo corrente. Esempio:
private void ShowBusy(string reason) {
// Display reason
BusyText.Text = reason;
//Define Animation
UIView.BeginAnimations("Show");
UIView.SetAnimationDuration(1.0f);
Handoff.Alpha = 0.5f;
//Execute Animation
UIView.CommitAnimations();
}
...
public void PreparingToHandoff() {
// Inform caller
ShowBusy ("Continuing Activity...");
}
L'oggetto ContinueUserActivity
dell'oggetto AppDelegate
verrà chiamato per continuare effettivamente l'attività specificata. Anche in questo caso, dall'app di esempio:
public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
// Report Activity
Console.WriteLine ("Continuing User Activity: {0}", userActivity.ToString());
// Get input and output streams from the Activity
userActivity.GetContinuationStreams ((NSInputStream arg1, NSOutputStream arg2, NSError arg3) => {
// Send required data via the streams
// ...
});
// Take action based on the Activity type
switch (userActivity.ActivityType) {
case "com.xamarin.monkeybrowser.tab1":
// Preform handoff
Tab1.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab1});
break;
case "com.xamarin.monkeybrowser.tab2":
// Preform handoff
Tab2.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab2});
break;
case "com.xamarin.monkeybrowser.tab3":
// Preform handoff
Tab3.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab3});
break;
case "com.xamarin.monkeybrowser.tab4":
// Preform handoff
Tab4.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab4});
break;
}
// Inform system we handled this
return true;
}
Il metodo pubblico PerformHandoff
di ogni controller di visualizzazione preforma effettivamente l'handoff e ripristina l'attività nel dispositivo corrente. Nel caso dell'esempio, viene visualizzato lo stesso URL in una determinata scheda in cui l'utente stava esplorando un dispositivo diverso. Esempio:
private void HideBusy() {
//Define Animation
UIView.BeginAnimations("Hide");
UIView.SetAnimationDuration(1.0f);
Handoff.Alpha = 0f;
//Execute Animation
UIView.CommitAnimations();
}
...
public void PerformHandoff(NSUserActivity activity) {
// Hide busy indicator
HideBusy ();
// Extract URL from dictionary
var url = activity.UserInfo ["Url"].ToString ();
// Display value
URL.Text = url;
// Display the give webpage
WebView.LoadRequest(new NSUrlRequest(NSUrl.FromString(url)));
// Save activity
UserActivity = activity;
UserActivity.BecomeCurrent ();
}
Il ContinueUserActivity
metodo include un UIApplicationRestorationHandler
oggetto che è possibile chiamare per la ripresa dell'attività basata su documento o risponditore. È necessario passare un NSArray
oggetto o ripristinabile al gestore di ripristino quando viene chiamato. Ad esempio:
completionHandler (new NSObject[]{Tab4});
Per ogni oggetto passato, verrà chiamato il relativo RestoreUserActivityState
metodo. Ogni oggetto può quindi usare i dati nel UserInfo
dizionario per ripristinare il proprio stato. Ad esempio:
public override void RestoreUserActivityState (NSUserActivity activity)
{
base.RestoreUserActivityState (activity);
// Log activity
Console.WriteLine ("Restoring Activity {0}", activity.Title);
}
Per le app basate su documenti, se non si implementa il ContinueUserActivity
metodo o restituisce false
o AppKit
UIKit
può riprendere automaticamente l'attività. Per altre informazioni, vedere la sezione Supporto delle app basate su documenti più avanti.
Errore handoff normalmente
Poiché Handoff si basa sulla trasmissione di informazioni tra una raccolta di dispositivi iOS e OS X con connessione libera, il processo di trasferimento può talvolta non riuscire. È consigliabile progettare l'app per gestire questi errori in modo normale e informare l'utente di eventuali situazioni che si verificano.
In caso di errore, verrà chiamato il DidFailToContinueUserActivitiy
metodo di AppDelegate
. Ad esempio:
public override void DidFailToContinueUserActivitiy (UIApplication application, string userActivityType, NSError error)
{
// Log information about the failure
Console.WriteLine ("User Activity {0} failed to continue. Error: {1}", userActivityType, error.LocalizedDescription);
}
È consigliabile usare l'oggetto fornito NSError
per fornire informazioni all'utente sull'errore.
Handoff da app nativa a Web browser
Un utente può voler continuare un'attività senza che nel dispositivo desiderato sia installata un'app nativa appropriata. In alcune situazioni, un'interfaccia basata sul Web può fornire la funzionalità necessaria e l'attività può comunque essere continuata. Ad esempio, l'account di posta elettronica dell'utente può fornire un'interfaccia utente di base Web per la composizione e la lettura dei messaggi.
Se l'app nativa conosce l'URL dell'interfaccia Web (e la sintassi necessaria per identificare l'elemento specificato in corso), può codificare queste informazioni nella WebpageURL
proprietà dell'istanza NSUserActivity
. Se nel dispositivo ricevente non è installata un'app nativa appropriata per gestire la continuazione, è possibile chiamare l'interfaccia Web fornita.
Handoff da Web browser a app nativa
Se l'utente usa un'interfaccia basata sul Web nel dispositivo di origine e un'app nativa nel dispositivo ricevente dichiara la parte di dominio della WebpageURL
proprietà, il sistema userà tale app per gestire la continuazione. Il nuovo dispositivo riceverà un'istanza NSUserActivity
che contrassegna il tipo di attività come BrowsingWeb
e WebpageURL
conterrà l'URL visitato dall'utente, il UserInfo
dizionario sarà vuoto.
Affinché un'app partecipi a questo tipo di handoff, deve richiedere il dominio in un com.apple.developer.associated-domains
diritto con il formato <service>:<fully qualified domain name>
(ad esempio: activity continuation:company.com
).
Se il dominio specificato corrisponde al valore di una WebpageURL
proprietà, Handoff scarica un elenco di ID app approvati dal sito Web in quel dominio. Il sito Web deve fornire un elenco di ID approvati in un file JSON firmato denominato apple-app-site-association (ad esempio, https://company.com/apple-app-site-association
).
Questo file JSON contiene un dizionario che specifica un elenco di ID app nel formato <team identifier>.<bundle identifier>
. Ad esempio:
{
"activitycontinuation": {
"apps": [ "YWBN8XTPBJ.com.company.FirstApp",
"YWBN8XTPBJ.com.company.SecondApp" ]
}
}
Per firmare il file JSON (in modo che abbia il valore corretto Content-Type
di application/pkcs7-mime
), usare l'app Terminale e un comando con un certificato e una openssl
chiave rilasciati da un'autorità di certificazione attendibile da iOS (vedere https://support.apple.com/kb/ht5012 per un elenco). Ad esempio:
echo '{"activitycontinuation":{"apps":["YWBN8XTPBJ.com.company.FirstApp",
"YWBN8XTPBJ.com.company.SecondApp"]}}' > json.txt
cat json.txt | openssl smime -sign -inkey company.com.key
-signer company.com.pem
-certfile intermediate.pem
-noattr -nodetach
-outform DER > apple-app-site-association
Il openssl
comando restituisce un file JSON firmato inserito nel sito Web all'URL apple-app-site-association . Ad esempio:
https://example.com/apple-app-site-association.
L'app riceverà qualsiasi attività il cui WebpageURL
dominio è nel suo com.apple.developer.associated-domains
diritto. Solo i http
protocolli e https
sono supportati, qualsiasi altro protocollo genererà un'eccezione.
Supporto dell'handoff nelle app basate su documenti
Come indicato in precedenza, nelle app basate su iOS e OS X, le app basate su documenti supporteranno automaticamente handoff di documenti basati su iCloud se il file Info.plist dell'app contiene una CFBundleDocumentTypes
chiave di NSUbiquitousDocumentUserActivityType
. Ad esempio:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>NSRTFDPboardType</string>
. . .
<key>LSItemContentTypes</key>
<array>
<string>com.myCompany.rtfd</string>
</array>
. . .
<key>NSUbiquitousDocumentUserActivityType</key>
<string>com.myCompany.myEditor.editing</string>
</dict>
</array>
In questo esempio la stringa è un designatore di app DNS inverso con il nome dell'attività aggiunta. Se immesso in questo modo, le voci del tipo di attività non devono essere ripetute nella NSUserActivityTypes
matrice del file Info.plist .
L'oggetto Attività utente creato automaticamente (disponibile tramite la proprietà del UserActivity
documento) può essere fatto riferimento da altri oggetti nell'app e usati per ripristinare lo stato durante la continuazione. Ad esempio, per tenere traccia della selezione degli elementi e della posizione del documento. È necessario impostare questa proprietà delle attività NeedsSave
su true
ogni volta che lo stato cambia e aggiornare il UserInfo
dizionario nel UpdateUserActivityState
metodo .
La UserActivity
proprietà può essere usata da qualsiasi thread e conforme al protocollo KVO (key-value observing), in modo che possa essere usato per mantenere un documento sincronizzato quando si sposta e fuori da iCloud. La UserActivity
proprietà verrà invalidata quando il documento viene chiuso.
Per altre informazioni, vedere la documentazione relativa al supporto delle attività utente di Apple nella documentazione delle app basate su documenti.
Supporto dell'handoff nei risponditori
È possibile associare i risponditori (ereditati da UIResponder
in iOS o NSResponder
in OS X) alle attività impostandone UserActivity
le proprietà. Il sistema salva automaticamente la UserActivity
proprietà nei momenti appropriati, chiamando il metodo del UpdateUserActivityState
risponditore per aggiungere dati correnti all'oggetto User Activity usando il AddUserInfoEntriesFromDictionary
metodo .
Supporto della Flussi di continuazione
Potrebbe essere una situazione in cui la quantità di informazioni necessarie per continuare un'attività non può essere trasferita in modo efficiente dal payload iniziale handoff. In queste situazioni, l'app ricevente può stabilire uno o più flussi tra se stesso e l'app di origine per trasferire i dati.
L'app di origine imposta la SupportsContinuationStreams
proprietà dell'istanza NSUserActivity
su true
. Ad esempio:
// Create a new user Activity to support this tab
UserActivity = new NSUserActivity (ThisApp.UserActivityTab1){
Title = "Weather Tab",
SupportsContinuationStreams = true
};
UserActivity.Delegate = new UserActivityDelegate ();
// Update the activity when the tab's URL changes
var userInfo = new NSMutableDictionary ();
userInfo.Add (new NSString ("Url"), new NSString (url));
UserActivity.AddUserInfoEntries (userInfo);
// Inform Activity that it has been updated
UserActivity.BecomeCurrent ();
L'app ricevente può quindi chiamare il GetContinuationStreams
metodo di NSUserActivity
in per AppDelegate
stabilire il flusso. Ad esempio:
public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
// Report Activity
Console.WriteLine ("Continuing User Activity: {0}", userActivity.ToString());
// Get input and output streams from the Activity
userActivity.GetContinuationStreams ((NSInputStream arg1, NSOutputStream arg2, NSError arg3) => {
// Send required data via the streams
// ...
});
// Take action based on the Activity type
switch (userActivity.ActivityType) {
case "com.xamarin.monkeybrowser.tab1":
// Preform handoff
Tab1.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab1});
break;
case "com.xamarin.monkeybrowser.tab2":
// Preform handoff
Tab2.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab2});
break;
case "com.xamarin.monkeybrowser.tab3":
// Preform handoff
Tab3.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab3});
break;
case "com.xamarin.monkeybrowser.tab4":
// Preform handoff
Tab4.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab4});
break;
}
// Inform system we handled this
return true;
}
Nel dispositivo di origine, il delegato dell'attività utente riceve i flussi chiamando il relativo DidReceiveInputStream
metodo per fornire i dati richiesti per continuare l'attività dell'utente nel dispositivo di ripresa.
Si userà un NSInputStream
oggetto per fornire l'accesso in sola lettura ai dati di flusso e un NSOutputStream
accesso di sola scrittura. I flussi devono essere usati in modo di richiesta e risposta, in cui l'app ricevente richiede più dati e l'app di origine la fornisce. In questo modo, i dati scritti nel flusso di output nel dispositivo di origine vengono letti dal flusso di input nel dispositivo continuo e viceversa.
Anche in situazioni in cui è necessario il flusso di continuazione, dovrebbe esserci una comunicazione minima tra le due app.
Per altre informazioni, vedere la documentazione relativa all'uso della continuazione di Apple Flussi.
Procedure consigliate per l'handoff
L'implementazione corretta della continuazione senza interruzioni di un'attività utente tramite Handoff richiede un'attenta progettazione a causa di tutti i vari componenti coinvolti. Apple suggerisce di adottare le procedure consigliate seguenti per le app abilitate per handoff:
- Progettare le attività utente per richiedere il payload più piccolo possibile per correlare lo stato dell'attività da continuare. Maggiore è il payload, più tempo richiede l'avvio della continuazione.
- Se è necessario trasferire grandi quantità di dati per una continuazione corretta, tenere conto dei costi correlati alla configurazione e al sovraccarico di rete.
- È comune per un'app Mac di grandi dimensioni creare attività utente gestite da diverse app più piccole e specifiche delle attività nei dispositivi iOS. Le diverse versioni dell'app e del sistema operativo devono essere progettate per funzionare bene insieme o non riuscire correttamente.
- Quando si specificano i tipi di attività, usare la notazione DNS inversa per evitare conflitti. Se un'attività è specifica di una determinata app, il nome deve essere incluso nella definizione del tipo ( ad esempio
com.myCompany.myEditor.editing
). Se l'attività può funzionare in più app, eliminare il nome dell'app dalla definizione ( ad esempiocom.myCompany.editing
). - Se l'app deve aggiornare lo stato di un'attività utente (
NSUserActivity
) impostare laNeedsSave
proprietà sutrue
. In momenti appropriati, Handoff chiamerà il metodo delUserActivityWillSave
delegato in modo da poter aggiornare ilUserInfo
dizionario in base alle esigenze. - Poiché il processo handoff potrebbe non inizializzare immediatamente sul dispositivo ricevente, è necessario implementare e
AppDelegate
WillContinueUserActivity
informare l'utente che una continuazione sta per iniziare.
Esempio di app handoff
Un esempio di uso di Handoff in un'app Xamarin.iOS è l'app di esempio MonkeyBrowser . L'app ha quattro schede che l'utente può usare per esplorare il Web, ognuna con un determinato tipo di attività: Meteo, Preferito, Pausa caffè e Lavoro.
In qualsiasi scheda, quando l'utente immette un nuovo URL e tocca il pulsante Vai , viene creato un nuovo NSUserActivity
elemento per tale scheda contenente l'URL attualmente esplorato dall'utente:
Se un altro dispositivo dell'utente ha installato l'app MonkeyBrowser , è connesso a iCloud usando lo stesso account utente, si trova nella stessa rete e in prossimità del dispositivo precedente, l'attività handoff verrà visualizzata nella schermata iniziale (nell'angolo inferiore sinistro):
Se l'utente trascina verso l'alto sull'icona Handoff, l'app verrà avviata e l'attività utente specificata in NSUserActivity
verrà continuata nel nuovo dispositivo:
Quando l'attività utente è stata inviata correttamente a un altro dispositivo Apple, il dispositivo di NSUserActivity
invio riceverà una chiamata al UserActivityWasContinued
metodo per NSUserActivityDelegate
informarlo che l'attività utente è stata trasferita correttamente a un altro dispositivo.
Riepilogo
Questo articolo ha fornito un'introduzione al framework Handoff usato per continuare un'attività utente tra più dispositivi Apple dell'utente. Successivamente, ha illustrato come abilitare e implementare Handoff in un'app Xamarin.iOS. Infine, sono stati illustrati i diversi tipi di continuazioni Handoff disponibili e le procedure consigliate per handoff.