Transfert dans Xamarin.iOS

Cet article traite de l’utilisation de Handoff dans une application Xamarin.iOS pour transférer des activités utilisateur entre des applications s’exécutant sur les autres appareils de l’utilisateur.

Apple a introduit handoff dans iOS 8 et OS X Yosemite (10.10) afin de fournir un mécanisme commun pour que l’utilisateur transfère les activités démarrées sur l’un de ses appareils, vers un autre appareil exécutant la même application ou une autre application qui prend en charge la même activité.

An example of performing a Handoff operation

Cet article examine rapidement l’activation du partage d’activités dans une application Xamarin.iOS et couvre en détail l’infrastructure handoff :

À propos du transfert

Le transfert (également appelé Continuité) a été introduit par Apple dans iOS 8 et OS X Yosemite (10.10) comme moyen pour l’utilisateur de démarrer une activité sur l’un de ses appareils (iOS ou Mac) et poursuivre cette même activité sur un autre de ses appareils (comme identifié par le compte iCloud de l’utilisateur).

Le transfert a été développé dans iOS 9 pour prendre également en charge de nouvelles fonctionnalités de recherche améliorées. Pour plus d’informations, consultez notre documentation améliorations de recherche.

Par exemple, l’utilisateur peut démarrer un e-mail sur son i Téléphone et poursuivre en toute transparence l’e-mail sur son Mac, avec toutes les mêmes informations de message renseignées et le curseur dans le même emplacement qu’il l’a laissé dans iOS.

Toutes vos applications qui partagent le même ID d’équipe sont éligibles à l’utilisation de Handoff pour poursuivre les activités des utilisateurs entre les applications tant que ces applications sont livrées via l’App Store iTunes ou signées par un développeur inscrit (pour Mac, Entreprise ou Applications Ad Hoc).

Toutes NSDocument les applications basées ont UIDocument automatiquement la prise en charge intégrée de Handoff et nécessitent des modifications minimales pour prendre en charge handoff.

Activités utilisateur continues

La NSUserActivity classe (ainsi que quelques modifications mineures apportées à UIKit et AppKit) prend en charge la définition de l’activité d’un utilisateur qui peut potentiellement être poursuivie sur un autre des appareils de l’utilisateur.

Pour qu’une activité soit transmise à un autre des appareils de l’utilisateur, elle doit être encapsulée dans une instanceNSUserActivity, marquée comme l’activité actuelle, avoir son jeu de charge utile (les données utilisées pour effectuer la continuation) et l’activité doit ensuite être transmise à cet appareil.

Le transfert passe le minimum d’informations pour définir l’activité à poursuivre, avec des paquets de données plus volumineux synchronisés via iCloud.

Sur l’appareil de réception, l’utilisateur reçoit une notification indiquant qu’une activité est disponible pour la continuation. Si l’utilisateur choisit de poursuivre l’activité sur le nouvel appareil, l’application spécifiée est lancée (si elle n’est pas déjà en cours d’exécution) et la charge utile à partir de celle-ci NSUserActivity est utilisée pour redémarrer l’activité.

An overview of Continuing User Activities

Seules les applications qui partagent le même ID d’équipe de développeur et répondent à un type d’activité donné sont éligibles pour la continuation. Une application définit les types d’activité qu’il prend en charge sous la NSUserActivityTypes clé de son fichier Info.plist . Étant donné cela, un appareil continu choisit l’application pour effectuer la continuation en fonction de l’ID d’équipe, du type d’activité et éventuellement du titre de l’activité.

L’application de réception utilise des informations du NSUserActivitydictionnaire pour UserInfo configurer son interface utilisateur et restaurer l’état de l’activité donnée afin que la transition apparaisse en toute transparence pour l’utilisateur final.

Si la continuation nécessite plus d’informations que celles qui peuvent être envoyées efficacement par le biais d’un NSUserActivity, l’application de reprise peut envoyer un appel à l’application d’origine et établir un ou plusieurs flux pour transmettre les données requises. Par exemple, si l’activité a modifié un document de texte volumineux avec plusieurs images, la diffusion en continu serait nécessaire pour transférer les informations nécessaires pour poursuivre l’activité sur l’appareil récepteur. Pour plus d’informations, consultez la section Flux de continuation de prise en charge ci-dessous.

Comme indiqué ci-dessus, NSDocument ou UIDocument les applications basées ont automatiquement la prise en charge intégrée de Handoff. Pour plus d’informations, consultez la section Prise en charge des applications basées sur des documents ci-dessous.

Classe NSUserActivity

La NSUserActivity classe est l’objet principal d’un échange de transfert et est utilisé pour encapsuler l’état d’une activité utilisateur disponible pour la continuation. Une application instancie une copie de NSUserActivity toute activité prise en charge et souhaite continuer sur un autre appareil. Par exemple, l’éditeur de document crée une activité pour chaque document actuellement ouvert. Toutefois, seul le document frontal (affiché dans la fenêtre ou l’onglet le plus haut) est l’activité actuelle et est disponible pour la continuation.

Une instance de NSUserActivity est identifiée à la fois par ses propriétés et Title ses ActivityType propriétés. La UserInfo propriété dictionnaire est utilisée pour transmettre des informations sur l’état de l’activité. Définissez la NeedsSave propriété true sur si vous souhaitez charger les informations d’état par le biais du NSUserActivitydélégué. Utilisez la AddUserInfoEntries méthode pour fusionner de nouvelles données d’autres clients dans le UserInfo dictionnaire selon les besoins pour préserver l’état de l’activité.

La classe NSUserActivityDelegate

Il NSUserActivityDelegate est utilisé pour conserver les informations dans un NSUserActivityUserInfo dictionnaire à jour et synchronisées avec l’état actuel de l’activité. Lorsque le système a besoin des informations de l’activité à mettre à jour (par exemple, avant la continuation sur un autre appareil), il appelle la UserActivityWillSave méthode du délégué.

Vous devez implémenter la UserActivityWillSave méthode et apporter des modifications à l’objet NSUserActivity (par UserInfoexemple, , Titleetc.) pour vous assurer qu’elle reflète toujours l’état de l’activité actuelle. Lorsque le système appelle la UserActivityWillSave méthode, l’indicateur NeedsSave est effacé. Si vous modifiez l’une des propriétés de données de l’activité, vous devez la définir NeedsSave à true nouveau.

Au lieu d’utiliser la UserActivityWillSave méthode présentée ci-dessus, vous pouvez éventuellement avoir UIKit ou AppKit gérer automatiquement l’activité de l’utilisateur. Pour ce faire, définissez la propriété de l’objet UserActivity répondeur et implémentez la UpdateUserActivityState méthode. Pour plus d’informations, consultez la section Prise en charge du transfert dans les répondeurs ci-dessous.

Prise en charge d’App Framework

Les deux UIKit (iOS) et AppKit (OS X) fournissent une prise en charge intégrée de handoff dans les NSDocumentclasses , répondeur (NSResponderUIResponder/) et AppDelegate les classes. Bien que chaque système d’exploitation implémente le transfert légèrement différemment, le mécanisme de base et les API sont identiques.

Activités des utilisateurs dans les applications basées sur des documents

Les applications iOS et OS X basées sur des documents prennent automatiquement en charge la prise en charge intégrée des documents. Pour activer cette prise en charge, vous devez ajouter une clé et une NSUbiquitousDocumentUserActivityType valeur pour chaque CFBundleDocumentTypes entrée dans le fichier Info.plist de l’application.

Si cette clé est présente, créez NSDocument automatiquement NSUserActivity des UIDocument instances pour les documents iCloud du type spécifié. Vous devez fournir un type d’activité pour chaque type de document pris en charge par l’application et plusieurs types de documents peuvent utiliser le même type d’activité. Les deux NSDocument et UIDocument remplissent automatiquement la UserInfo propriété de la NSUserActivity propriété avec la valeur de leur FileURL propriété.

Sur OS X, la NSUserActivity gestion par AppKit et associée aux répondeurs devient automatiquement l’activité actuelle lorsque la fenêtre du document devient la fenêtre principale. Sur iOS, pour NSUserActivity les objets gérés par UIKit, vous devez appeler BecomeCurrent une méthode explicitement ou avoir la propriété du UserActivity document définie sur un UIViewController moment où l’application vient au premier plan.

AppKit restaure automatiquement toutes les UserActivity propriétés créées de cette façon sur OS X. Cela se produit si la ContinueUserActivity méthode retourne false ou si elle est non implémentée. Dans ce cas, le document est ouvert avec la OpenDocument méthode du NSDocumentController document et reçoit ensuite un RestoreUserActivityState appel de méthode.

Pour plus d’informations, consultez la section Prise en charge des applications basées sur des documents ci-dessous.

Activités et répondeurs des utilisateurs

Les deux UIKit et AppKit peuvent gérer automatiquement une activité utilisateur si vous la définissez comme propriété d’un UserActivity objet répondeur. Si l’état a été modifié, vous devez définir la NeedsSave propriété du répondeur UserActivitytruesur . Le système enregistre automatiquement le UserActivity cas échéant, après avoir donné au répondeur le temps de mettre à jour l’état en appelant sa UpdateUserActivityState méthode.

Si plusieurs répondeurs partagent une seule NSUserActivity instance, ils reçoivent un UpdateUserActivityState rappel lorsque le système met à jour l’objet d’activité utilisateur. Le répondeur doit appeler la AddUserInfoEntries méthode pour mettre à jour le NSUserActivitydictionnaire pour refléter l’état actuel de UserInfo l’activité à ce stade. Le UserInfo dictionnaire est effacé avant chaque UpdateUserActivityState appel.

Pour dissocier d’une activité, un répondeur peut définir sa UserActivity propriété nullsur . Lorsqu’une instance managée NSUserActivity de l’infrastructure d’application n’a plus de répondeurs ou de documents associés, elle est automatiquement invalidée.

Pour plus d’informations, consultez la section Prise en charge du transfert dans les répondeurs ci-dessous.

Activités utilisateur et AppDelegate

Votre application est son point d’entrée principal lors de la gestion d’une AppDelegate continuation de transfert. Lorsque l’utilisateur répond à une notification de transfert, l’application appropriée est lancée (si elle n’est pas déjà en cours d’exécution) et la WillContinueUserActivityWithType méthode du AppDelegate fichier sera appelée. À ce stade, l’application doit informer l’utilisateur que la continuation démarre.

L’instance NSUserActivity est remise lorsque la AppDelegateméthode 's ContinueUserActivity est appelée. À ce stade, vous devez configurer l’interface utilisateur de l’application et poursuivre l’activité donnée.

Pour plus d’informations, consultez la section Implémentation du transfert ci-dessous.

Activation du transfert dans une application Xamarin

En raison des exigences de sécurité imposées par Handoff, une application Xamarin.iOS qui utilise l’infrastructure Handoff doit être correctement configurée dans le portail des développeurs Apple et dans le fichier projet Xamarin.iOS.

Effectuez les actions suivantes :

  1. Connectez-vous au portail des développeurs Apple.

  2. Cliquez sur Certificats, identificateurs et profils.

  3. Si vous ne l’avez pas encore fait, cliquez sur Identificateurs et créez un ID pour votre application (par exemple com.company.appname), sinon modifiez votre ID existant.

  4. Vérifiez que le service iCloud a été case activée ed pour l’ID donné :

    Enable the iCloud service for the given ID

  5. Enregistrez vos modifications.

  6. Cliquez sur Le développement des profils>d’approvisionnement et créez un profil d’approvisionnement de développement pour votre application :

    Create a new development provisioning profile for the app

  7. Téléchargez et installez le nouveau profil d’approvisionnement ou utilisez Xcode pour télécharger et installer le profil.

  8. Modifiez vos options de projet Xamarin.iOS et vérifiez que vous utilisez le profil d’approvisionnement que vous venez de créer :

    Select the provisioning profile just created

  9. Ensuite, modifiez votre fichier Info.plist et vérifiez que vous utilisez l’ID d’application utilisé pour créer le profil d’approvisionnement :

    Set App ID

  10. Faites défiler jusqu’à la section Modes d’arrière-plan et case activée les éléments suivants :

    Enable the required background modes

  11. Enregistrez les modifications apportées à tous les fichiers.

Avec ces paramètres en place, l’application est maintenant prête à accéder aux API Handoff Framework. Pour plus d’informations sur l’approvisionnement, consultez nos guides d’approvisionnement et d’approvisionnement de votre application .

Implémentation du transfert

Les activités utilisateur peuvent être poursuivies entre les applications signées avec le même ID d’équipe de développeur et prendre en charge le même type d’activité. L’implémentation du transfert dans une application Xamarin.iOS vous oblige à créer un objet d’activité utilisateur (dans UIKit ou AppKit), à mettre à jour l’état de l’objet pour suivre l’activité et poursuivre l’activité sur un appareil récepteur.

Identification des activités utilisateur

La première étape de l’implémentation de Handoff consiste à identifier les types d’activités utilisateur prises en charge par votre application et à voir quelles activités sont de bons candidats à la continuation sur un autre appareil. Par exemple : une application ToDo peut prendre en charge la modification d’éléments en tant que type d’activité utilisateur et la navigation dans la liste des éléments disponibles en tant qu’autre.

Une application peut créer autant de types d’activités utilisateur que nécessaire, une pour n’importe quelle fonction que l’application fournit. Pour chaque type d’activité utilisateur, l’application doit suivre quand une activité du type commence et se termine, et doit conserver les informations d’état à jour pour continuer cette tâche sur un autre appareil.

Les activités utilisateur peuvent être poursuivies sur n’importe quelle application signée avec le même ID d’équipe sans mappage un-à-un entre les applications d’envoi et de réception. Par exemple, une application donnée peut créer quatre types d’activités différents, qui sont consommés par différentes applications individuelles sur un autre appareil. Il s’agit d’une occurrence courante entre une version Mac de l’application (qui peut avoir de nombreuses fonctionnalités et fonctions) et des applications iOS, où chaque application est plus petite et axée sur une tâche spécifique.

Création d’identificateurs de type d’activité

L’identificateur de type d’activité est une chaîne courte ajoutée au NSUserActivityTypes tableau du fichier Info.plist de l’application utilisé pour identifier de manière unique un type d’activité utilisateur donné. Il y aura une entrée dans le tableau pour chaque activité prise en charge par l’application. Apple suggère d’utiliser une notation de style DNS inversée pour l’identificateur de type d’activité afin d’éviter les collisions. Par exemple : com.company-name.appname.activity pour des activités spécifiques basées sur des applications ou com.company-name.activity pour des activités qui peuvent s’exécuter sur plusieurs applications.

L’identificateur de type d’activité est utilisé lors de la création d’une NSUserActivity instance pour identifier le type d’activité. Lorsqu’une activité se poursuit sur un autre appareil, le type d’activité (ainsi que l’ID d’équipe de l’application) détermine l’application à lancer pour poursuivre l’activité.

Par exemple, nous allons créer un exemple d’application appelé MonkeyBrowser (télécharger ici). Cette application présente quatre onglets, chacun avec une URL différente ouverte dans un affichage de navigateur web. L’utilisateur pourra continuer n’importe quel onglet sur un autre appareil iOS exécutant l’application.

Pour créer les identificateurs de type d’activité requis pour prendre en charge ce comportement, modifiez le fichier Info.plist et basculez vers la vue Source . Ajoutez une NSUserActivityTypes clé et créez les identificateurs suivants :

The NSUserActivityTypes key and required identifiers in the plist editor

Nous avons créé quatre nouveaux identificateurs de type d’activité, un pour chacun des onglets de l’exemple d’application MonkeyBrowser . Lorsque vous créez vos propres applications, remplacez le contenu du tableau par les identificateurs de NSUserActivityTypes type d’activité spécifiques aux activités prises en charge par votre application.

Suivi des modifications apportées à l’activité des utilisateurs

Lorsque nous créons une instance de la NSUserActivity classe, nous allons spécifier une NSUserActivityDelegate instance pour suivre les modifications apportées à l’état de l’activité. Par exemple, le code suivant peut être utilisé pour suivre les modifications d’état :

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

La UserActivityReceivedData méthode est appelée lorsqu’un flux de continuation a reçu des données d’un appareil d’envoi. Pour plus d’informations, consultez la section Flux de continuation de prise en charge ci-dessous.

La UserActivityWasContinued méthode est appelée lorsqu’un autre appareil a pris le contrôle d’une activité à partir de l’appareil actuel. Selon le type d’activité, comme l’ajout d’un nouvel élément à une liste ToDo, l’application peut avoir besoin d’abandonner l’activité sur l’appareil d’envoi.

La UserActivityWillSave méthode est appelée avant que les modifications apportées à l’activité soient enregistrées et synchronisées sur les appareils disponibles localement. Vous pouvez utiliser cette méthode pour apporter des modifications de dernière minute à la UserInfo propriété de l’instance NSUserActivity avant son envoi.

Création d’une instance NSUserActivity

Chaque activité que votre application souhaite fournir la possibilité de poursuivre sur un autre appareil doit être encapsulée dans une NSUserActivity instance. L’application peut créer autant d’activités que nécessaire et la nature de ces activités dépend des fonctionnalités et fonctionnalités de l’application en question. Par exemple, une application de messagerie peut créer une activité pour créer un message et une autre pour lire un message.

Pour notre exemple d’application, un nouveau NSUserActivity est créé chaque fois que l’utilisateur entre une nouvelle URL dans l’une des vues de navigateur web à onglets. Le code suivant stocke l’état d’un onglet donné :

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

Il crée un NSUserActivity nouveau type d’activité utilisateur créé ci-dessus et fournit un titre lisible par l’utilisateur pour l’activité. Il s’attache à une instance du NSUserActivityDelegate fichier créé ci-dessus pour surveiller les modifications d’état et informe iOS que cette activité utilisateur est l’activité actuelle.

Remplissage du dictionnaire UserInfo

Comme nous l’avons vu ci-dessus, la UserInfo propriété de la NSUserActivity classe est une NSDictionary paire clé-valeur utilisée pour définir l’état d’une activité donnée. Les valeurs stockées dans UserInfo doivent être l’un des types suivants : NSArray, , NSDateNSData, NSDictionary, NSNull, NSNumber, , , NSSet, , NSString, ou NSURL. NSURL les valeurs de données qui pointent vers des documents iCloud sont automatiquement ajustées afin qu’elles pointent vers les mêmes documents sur un appareil récepteur.

Dans l’exemple ci-dessus, nous avons créé un NSMutableDictionary objet et l’avons rempli avec une seule clé fournissant l’URL que l’utilisateur a actuellement affichée sous l’onglet donné. La AddUserInfoEntries méthode de l’activité utilisateur a été utilisée pour mettre à jour l’activité avec les données qui seront utilisées pour restaurer l’activité sur l’appareil récepteur :

// 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 suggère de conserver les informations envoyées au minimum pour s’assurer que l’activité est envoyée en temps voulu à l’appareil de réception. Si des informations plus volumineuses sont requises, comme une image attachée à un document à modifier, vous devez utiliser la continuation Flux. Pour plus d’informations, consultez la section Flux de prise en charge de la continuation ci-dessous.

Poursuite d’une activité

Le transfert informe automatiquement les appareils iOS et OS X locaux qui sont à proximité physique de l’appareil d’origine et connectés au même compte iCloud, de la disponibilité des activités utilisateur continuables. Si l’utilisateur choisit de poursuivre une activité sur un nouvel appareil, le système lance l’application appropriée (en fonction de l’ID d’équipe et du type d’activité) et les informations dont la AppDelegate continuation doit se produire.

Tout d’abord, la WillContinueUserActivityWithType méthode est appelée afin que l’application puisse informer l’utilisateur que la continuation est sur le point de commencer. Nous utilisons le code suivant dans le fichier AppDelegate.cs de notre exemple d’application pour gérer un démarrage de continuation :

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

Dans l’exemple ci-dessus, chaque contrôleur de vue s’inscrit auprès de la AppDelegate méthode publique PreparingToHandoff qui affiche un indicateur d’activité et un message indiquant à l’utilisateur que l’activité est sur le point d’être transmise à l’appareil actuel. Exemple :

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

AppDelegate Le ContinueUserActivity projet sera appelé pour poursuivre l’activité donnée. Là encore, à partir de notre exemple d’application :

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

La méthode publique PerformHandoff de chaque contrôleur de vue préforme réellement le transfert et restaure l’activité sur l’appareil actuel. Dans le cas de l’exemple, il affiche la même URL dans un onglet donné que l’utilisateur parcourait sur un autre appareil. Exemple :

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

}

La ContinueUserActivity méthode inclut un UIApplicationRestorationHandler appel à l’activité basée sur le document ou le répondeur. Vous devez passer un NSArray ou plusieurs objets restaurables au gestionnaire de restauration lors de l’appel. Par exemple :

completionHandler (new NSObject[]{Tab4});

Pour chaque objet passé, sa RestoreUserActivityState méthode est appelée. Chaque objet peut ensuite utiliser les données du UserInfo dictionnaire pour restaurer son propre état. Par exemple :

public override void RestoreUserActivityState (NSUserActivity activity)
{
    base.RestoreUserActivityState (activity);

    // Log activity
    Console.WriteLine ("Restoring Activity {0}", activity.Title);
}

Pour les applications basées sur des documents, si vous n’implémentez pas la ContinueUserActivity méthode ou qu’elle retourne false, UIKit ou AppKit que vous pouvez reprendre automatiquement l’activité. Pour plus d’informations, consultez la section Prise en charge des applications basées sur des documents ci-dessous.

Échec du transfert avec grâce

Étant donné que le transfert s’appuie sur la transmission d’informations entre un regroupement d’appareils iOS et OS X faiblement connectés, le processus de transfert peut parfois échouer. Vous devez concevoir votre application pour gérer ces défaillances correctement et informer l’utilisateur des situations qui surviennent.

En cas d’échec, la DidFailToContinueUserActivitiy méthode de l’objet AppDelegate sera appelée. Par exemple :

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

Vous devez utiliser l’élément fourni NSError pour fournir des informations à l’utilisateur sur l’échec.

Application native vers le transfert du navigateur web

Un utilisateur peut souhaiter poursuivre une activité sans avoir installé une application native appropriée sur l’appareil souhaité. Dans certains cas, une interface web peut fournir les fonctionnalités requises et l’activité peut continuer. Par exemple, le compte de messagerie de l’utilisateur peut fournir une interface utilisateur de base web pour la composition et la lecture de messages.

Si l’application native connaît l’URL de l’interface web (et la syntaxe requise pour identifier l’élément donné en cours de poursuite), elle peut encoder ces informations dans la WebpageURL propriété de l’instance NSUserActivity . Si l’appareil de réception n’a pas d’application native appropriée installée pour gérer la continuation, l’interface web fournie peut être appelée.

Transfert du navigateur web vers une application native

Si l’utilisateur utilisait une interface web sur l’appareil d’origine et qu’une application native sur l’appareil récepteur revendique la partie domaine de la WebpageURL propriété, le système utilisera cette application pour gérer la continuation. Le nouvel appareil reçoit une NSUserActivity instance qui marque le type d’activité comme BrowsingWeb et l’URL WebpageURL que l’utilisateur a visité, le UserInfo dictionnaire sera vide.

Pour qu’une application participe à ce type de transfert, elle doit revendiquer le domaine dans un com.apple.developer.associated-domains droit au format <service>:<fully qualified domain name> (par exemple : activity continuation:company.com).

Si le domaine spécifié correspond à la valeur d’une WebpageURL propriété, Handoff télécharge une liste d’ID d’application approuvés à partir du site web sur ce domaine. Le site web doit fournir la liste des ID approuvés dans un fichier JSON signé nommé apple-app-site-association (par exemple). https://company.com/apple-app-site-association

Ce fichier JSON contient un dictionnaire qui spécifie une liste d’ID d’application dans le formulaire <team identifier>.<bundle identifier>. Par exemple :

{
    "activitycontinuation": {
        "apps": [    "YWBN8XTPBJ.com.company.FirstApp",
            "YWBN8XTPBJ.com.company.SecondApp" ]
    }
}

Pour signer le fichier JSON (afin qu’il ait le bon Content-Type ), application/pkcs7-mimeutilisez l’application Terminal et une openssl commande avec un certificat et une clé émis par une autorité de certification approuvée par iOS (voir https://support.apple.com/kb/ht5012 pour obtenir une liste). Par exemple :

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

La openssl commande génère un fichier JSON signé que vous placez sur votre site web à l’URL apple-app-site-association . Par exemple :

https://example.com/apple-app-site-association.

L’application reçoit toute activité dont WebpageURL le domaine est dans son com.apple.developer.associated-domains droit d’utilisation. Seuls les protocoles et https les http protocoles sont pris en charge, tout autre protocole génère une exception.

Prise en charge du transfert dans les applications basées sur des documents

Comme indiqué ci-dessus, sur iOS et OS X, les applications basées sur des documents prennent automatiquement en charge le transfert de documents basés sur iCloud si le fichier Info.plist de l’application contient une CFBundleDocumentTypes clé de NSUbiquitousDocumentUserActivityType. Par exemple :

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

Dans cet exemple, la chaîne est un concepteur d’application DNS inversé avec le nom de l’activité ajoutée. Si elles sont entrées de cette façon, les entrées de type d’activité n’ont pas besoin d’être répétées dans le NSUserActivityTypes tableau du fichier Info.plist .

L’objet Activité utilisateur créé automatiquement (disponible via la propriété du document) peut être référencé par d’autres objets de l’application et utilisé pour restaurer l’état lors de UserActivity la continuation. Par exemple, pour suivre la sélection d’éléments et la position du document. Vous devez définir cette propriété d’activités NeedsSave chaque fois que l’état change et met à jour le UserInfo dictionnaire dans la UpdateUserActivityState méthode.true

La UserActivity propriété peut être utilisée à partir de n’importe quel thread et est conforme au protocole KVO (Key-Value Observing), afin qu’elle puisse être utilisée pour conserver un document synchronisé lors de son déplacement et de son sortie d’iCloud. La UserActivity propriété est invalidée lorsque le document est fermé.

Pour plus d’informations, consultez la documentation relative à l’activité utilisateur d’Apple dans la documentation sur les applications basées sur des documents.

Prise en charge du transfert dans les répondeurs

Vous pouvez associer des répondeurs (hérités d’iOS UIResponder ou NSResponder sur OS X) aux activités en définissant leurs UserActivity propriétés. Le système enregistre automatiquement la UserActivity propriété à l’heure appropriée, en appelant la méthode du UpdateUserActivityState répondeur pour ajouter des données actuelles à l’objet Activité utilisateur à l’aide de la AddUserInfoEntriesFromDictionary méthode.

Prise en charge des Flux de continuation

Il peut s’agir de situations où la quantité d’informations requises pour poursuivre une activité ne peut pas être transférée efficacement par la charge utile de transfert initiale. Dans ces situations, l’application de réception peut établir un ou plusieurs flux entre lui-même et l’application d’origine pour transférer les données.

L’application d’origine définit la SupportsContinuationStreams propriété de l’instance NSUserActivity sur true. Par exemple :

// 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’application de réception peut ensuite appeler la GetContinuationStreams méthode de l’application NSUserActivity dans celle-ci AppDelegate pour établir le flux. Par exemple :

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

Sur l’appareil d’origine, le délégué d’activité utilisateur reçoit les flux en appelant sa DidReceiveInputStream méthode pour fournir les données demandées pour poursuivre l’activité de l’utilisateur sur l’appareil de reprise.

Vous utiliserez un NSInputStream pour fournir un accès en lecture seule aux données de flux et un NSOutputStream accès en écriture seule. Les flux doivent être utilisés de manière de demande et de réponse, où l’application de réception demande plus de données et l’application d’origine la fournit. Ainsi, les données écrites dans le flux de sortie sur l’appareil d’origine sont lues à partir du flux d’entrée sur l’appareil continu, et vice versa.

Même dans les situations où le flux de continuation est requis, il doit y avoir un minimum de communication arrière et arrière entre les deux applications.

Pour plus d’informations, consultez la documentation d’Apple Using Continuation Flux.

Meilleures pratiques de transfert

L’implémentation réussie de la continuation transparente d’une activité utilisateur via handoff nécessite une conception minutieuse en raison de tous les différents composants impliqués. Apple suggère d’adopter les bonnes pratiques suivantes pour vos applications compatibles Handoff :

  • Concevez vos activités utilisateur pour exiger la plus petite charge utile possible pour lier l’état de l’activité à poursuivre. Plus la charge utile est grande, plus la continuation est longue.
  • Si vous devez transférer de grandes quantités de données pour une continuation réussie, prenez en compte les coûts liés à la configuration et à la surcharge réseau.
  • Il est courant pour une grande application Mac de créer des activités utilisateur gérées par plusieurs applications spécifiques aux tâches plus petites sur les appareils iOS. Les différentes versions d’application et de système d’exploitation doivent être conçues pour fonctionner correctement ensemble ou échouer correctement.
  • Lorsque vous spécifiez vos types d’activité, utilisez la notation DNS inversée pour éviter les collisions. Si une activité est spécifique à une application donnée, son nom doit être inclus dans la définition de type (par exemple com.myCompany.myEditor.editing). Si l’activité peut fonctionner sur plusieurs applications, supprimez le nom de l’application de la définition (par exemple com.myCompany.editing).
  • Si votre application doit mettre à jour l’état d’une activité utilisateur (NSUserActivity) définissez la NeedsSave propriété truesur . À des moments appropriés, handoff appelle la méthode du délégué afin de pouvoir mettre à jour le UserInfo dictionnaire en fonction des UserActivityWillSave besoins.
  • Étant donné que le processus de transfert peut ne pas initialiser instantanément sur l’appareil de réception, vous devez implémenter les AppDelegate« s WillContinueUserActivity » et informer l’utilisateur qu’une continuation est sur le point de commencer.

Exemple d’application de transfert

Par exemple, nous avons inclus l’exemple d’application MonkeyBrowser dans une application Xamarin.iOS avec ce guide. L’application comporte quatre onglets que l’utilisateur peut utiliser pour parcourir le web, chacun avec un type d’activité donné : Météo, Favoris, Pause café et Travail.

Sous n’importe quel onglet, lorsque l’utilisateur entre une nouvelle URL et appuie sur le bouton Go , un nouvel NSUserActivity onglet est créé pour cet onglet qui contient l’URL que l’utilisateur navigue actuellement :

Example Handoff App

Si une autre des appareils de l’utilisateur a installé l’application MonkeyBrowser , est connectée à iCloud à l’aide du même compte d’utilisateur, se trouve sur le même réseau et à proximité de l’appareil ci-dessus, l’activité de transfert s’affiche sur l’écran d’accueil (dans le coin inférieur gauche) :

The Handoff Activity displayed on the home screen in the lower left hand corner

Si l’utilisateur fait glisser vers le haut sur l’icône De transfert, l’application est lancée et l’activité utilisateur spécifiée dans celle-ci NSUserActivity est poursuivie sur le nouvel appareil :

The User Activity continued on the new device

Lorsque l’activité utilisateur a été correctement envoyée à un autre appareil Apple, l’appareil d’envoi NSUserActivity reçoit un appel à la UserActivityWasContinued méthode sur celui-ci NSUserActivityDelegate pour lui indiquer que l’activité de l’utilisateur a été transférée avec succès vers un autre appareil.

Résumé

Cet article a donné une présentation de l’infrastructure Handoff utilisée pour poursuivre une activité utilisateur entre plusieurs appareils Apple de l’utilisateur. Ensuite, il a montré comment activer et implémenter handoff dans une application Xamarin.iOS. Enfin, il a abordé les différents types de continuations de transfert disponibles et les meilleures pratiques de transfert.