Entrega en Xamarin.iOS
En este artículo se explica cómo trabajar con Handoff en una aplicación de Xamarin.iOS para transferir actividades de usuario entre aplicaciones que se ejecutan en otros dispositivos del usuario.
Apple introdujo Handoff en iOS 8 y OS X Yosemite (10.10) para proporcionar un mecanismo común para que el usuario transfiera actividades iniciadas en uno de sus dispositivos, a otro dispositivo que ejecuta la misma aplicación u otra aplicación que admita la misma actividad.
En este artículo se examinará rápidamente la habilitación del uso compartido de actividades en una aplicación de Xamarin.iOS y se tratará el marco handoff en detalle:
Acerca de la entrega
Apple introdujo Handoff (también conocido como Continuidad) en iOS 8 y OS X Yosemite (10.10) como una manera de que el usuario inicie una actividad en uno de sus dispositivos (ya sea iOS o Mac) y continúe con esa misma actividad en otro de sus dispositivos (según la identificación por la cuenta de iCloud del usuario).
Handoff se ha expandido en iOS 9 para admitir también nuevas funcionalidades de búsqueda mejoradas. Para más información, vea la documentación sobre Mejoras de búsqueda.
Por ejemplo, el usuario puede iniciar un correo electrónico en su i Teléfono y continuar sin problemas el correo electrónico en su Mac, con toda la misma información de mensaje rellenada y el cursor en la misma ubicación que la dejó en iOS.
Cualquiera de las aplicaciones que comparten el mismo identificador de equipo es apta para usar Handoff para continuar las actividades de usuario en las aplicaciones siempre que estas aplicaciones se entreguen a través de iTunes App Store o estén firmadas por un desarrollador registrado (para aplicaciones Mac, Enterprise o Ad Hoc).
Las NSDocument
aplicaciones basadas o UIDocument
basadas automáticamente tienen compatibilidad integrada con Handoff y requieren cambios mínimos para admitir Handoff.
Actividades continuas del usuario
La NSUserActivity
clase (junto con algunos pequeños cambios UIKit
en y AppKit
) proporciona compatibilidad para definir la actividad de un usuario que puede continuar en otro de los dispositivos del usuario.
Para que una actividad se pase a otro de los dispositivos del usuario, debe encapsularse en una instancia NSUserActivity
de , marcada como actividad actual, tener establecido la carga útil (los datos usados para realizar la continuación) y la actividad debe transmitirse a ese dispositivo.
La entrega pasa el mínimo mínimo de información para definir la actividad que se va a continuar, con paquetes de datos más grandes que se sincronizan a través de iCloud.
En el dispositivo receptor, el usuario recibirá una notificación de que una actividad está disponible para la continuación. Si el usuario decide continuar con la actividad en el nuevo dispositivo, se inicia la aplicación especificada (si aún no se está ejecutando) y la carga de NSUserActivity
se usa para reiniciar la actividad.
Solo las aplicaciones que comparten el mismo identificador de equipo de desarrollador y responden a un tipo de actividad determinado son aptas para la continuación. Una aplicación define los tipos de actividad que admite en la NSUserActivityTypes
clave de su archivo Info.plist . Dado esto, un dispositivo continuo elige la aplicación para realizar la continuación en función del identificador de equipo, el tipo de actividad y, opcionalmente, el título de la actividad.
La aplicación receptora usa información del NSUserActivity
diccionario del UserInfo
para configurar su interfaz de usuario y restaurar el estado de la actividad dada para que la transición aparezca sin problemas al usuario final.
Si la continuación requiere más información de la que se puede enviar de forma eficaz a través de , NSUserActivity
la aplicación de reanudación puede enviar una llamada a la aplicación de origen y establecer uno o más flujos para transmitir los datos necesarios. Por ejemplo, si la actividad editaba un documento de texto grande con varias imágenes, el streaming sería necesario para transferir la información necesaria para continuar la actividad en el dispositivo receptor. Para obtener más información, consulte la sección De continuación auxiliar Secuencias siguiente.
Como se indicó anteriormente, NSDocument
o UIDocument
las aplicaciones basadas automáticamente tienen compatibilidad integrada con Handoff. Para obtener más información, consulte la sección Compatibilidad con entrega en aplicaciones basadas en documentos a continuación.
La clase NSUserActivity
La NSUserActivity
clase es el objeto principal de un intercambio de entrega y se usa para encapsular el estado de una actividad de usuario que está disponible para la continuación. Una aplicación creará una instancia de una copia de NSUserActivity
para cualquier actividad que admita y desea continuar en otro dispositivo. Por ejemplo, el editor de documentos crearía una actividad para cada documento abierto actualmente. Sin embargo, solo el documento más frontal (que se muestra en la ventana o la pestaña) es la actividad actual y está disponible para la continuación.
Una instancia de NSUserActivity
se identifica mediante sus ActivityType
propiedades y Title
. La UserInfo
propiedad dictionary se usa para llevar información sobre el estado de la actividad. Establezca la NeedsSave
propiedad true
en si desea cargar la información de estado diferida a través NSUserActivity
del delegado de . Use el AddUserInfoEntries
método para combinar nuevos datos de otros clientes en el UserInfo
diccionario según sea necesario para conservar el estado de la actividad.
La clase NSUserActivityDelegate
NSUserActivityDelegate
se usa para mantener la información en un NSUserActivity
UserInfo
diccionario actualizado y sincronizado con el estado actual de la actividad. Cuando el sistema necesita que se actualice la información de la actividad (por ejemplo, antes de la continuación en otro dispositivo), llama al UserActivityWillSave
método del delegado.
Tendrá que implementar el UserActivityWillSave
método y realizar cualquier cambio en NSUserActivity
(como UserInfo
, Title
, etc.) para asegurarse de que sigue reflejando el estado de la actividad actual. Cuando el sistema llama al UserActivityWillSave
método , se borrará la NeedsSave
marca. Si modifica cualquiera de las propiedades de datos de la actividad, tendrá que establecer en NeedsSave
true
de nuevo.
En lugar de usar el UserActivityWillSave
método presentado anteriormente, puede tener UIKit
o AppKit
administrar automáticamente la actividad del usuario. Para ello, establezca la propiedad del UserActivity
objeto respondedor e implemente el UpdateUserActivityState
método . Para obtener más información, consulte la sección Entrega de soporte técnico en respondedor.
Compatibilidad con App Framework
Tanto UIKit
(iOS) como AppKit
(OS X) proporcionan compatibilidad integrada con Handoff en las NSDocument
clases , Responder (NSResponder
UIResponder
/) y .AppDelegate
Aunque cada sistema operativo implementa Handoff ligeramente diferente, el mecanismo básico y las API son los mismos.
Actividades de usuario en aplicaciones basadas en documentos
Las aplicaciones iOS y OS X basadas en documentos tienen automáticamente compatibilidad integrada con handoff. Para activar esta compatibilidad, deberá agregar una clave y un NSUbiquitousDocumentUserActivityType
valor para cada CFBundleDocumentTypes
entrada en el archivo Info.plist de la aplicación.
Si esta clave está presente, tanto NSDocument
como UIDocument
crea NSUserActivity
automáticamente instancias para documentos basados en iCloud del tipo especificado. Deberá proporcionar un tipo de actividad para cada tipo de documento que admita la aplicación y varios tipos de documento puedan usar el mismo tipo de actividad. Tanto como NSDocument
UIDocument
rellenan automáticamente la UserInfo
propiedad de NSUserActivity
con el valor de su FileURL
propiedad.
En OS X, los NSUserActivity
administrados por AppKit
y asociados a los respondedores se convierten automáticamente en la actividad actual cuando la ventana del documento se convierte en la ventana principal. En iOS, para NSUserActivity
los objetos administrados por UIKit
, debe llamar explícitamente al BecomeCurrent
método o hacer que la propiedad del UserActivity
documento esté establecida en un UIViewController
cuando la aplicación llegue al primer plano.
AppKit
restaurará automáticamente cualquier UserActivity
propiedad creada de esta manera en OS X. Esto ocurre si el ContinueUserActivity
método devuelve false
o si no se implementa. En esta situación, el documento se abre con el OpenDocument
método de NSDocumentController
y, a continuación, recibirá una RestoreUserActivityState
llamada al método .
Consulte la sección Compatibilidad con entrega en aplicaciones basadas en documentos a continuación para obtener más información.
Actividades y respondedores de usuario
Tanto UIKit
como AppKit
pueden administrar automáticamente una actividad de usuario si la establece como propiedad de UserActivity
un objeto de respondedor. Si se ha modificado el estado, deberá establecer la NeedsSave
propiedad del respondedor UserActivity
true
en . El sistema guardará automáticamente cuando UserActivity
sea necesario, después de proporcionar el tiempo del respondedor para actualizar el estado llamando a su UpdateUserActivityState
método.
Si varios respondedores comparten una sola NSUserActivity
instancia, reciben una UpdateUserActivityState
devolución de llamada cuando el sistema actualiza el objeto de actividad de usuario. El respondedor debe llamar al AddUserInfoEntries
método para actualizar el NSUserActivity
diccionario del UserInfo
objeto para reflejar el estado de actividad actual en este momento. El UserInfo
diccionario se borra antes de cada UpdateUserActivityState
llamada.
Para desasociarse de una actividad, un respondedor puede establecer su UserActivity
propiedad en null
. Cuando una instancia administrada NSUserActivity
de app Framework no tiene más respondedor o documentos asociados, se invalida automáticamente.
Para obtener más información, consulte la sección Entrega de soporte técnico en respondedor.
Actividades de usuario y AppDelegate
El de la AppDelegate
aplicación es su punto de entrada principal al controlar una continuación de entrega. Cuando el usuario responde a una notificación de entrega, se inicia la aplicación adecuada (si aún no se está ejecutando) y se llama al WillContinueUserActivityWithType
método de .AppDelegate
En este momento, la aplicación debe informar al usuario de que se está iniciando la continuación.
La NSUserActivity
instancia se entrega cuando se llama al AppDelegate
método de ContinueUserActivity
. En este momento, debes configurar la interfaz de usuario de la aplicación y continuar con la actividad especificada.
Consulte la sección Implementación de entrega a continuación para obtener más información.
Habilitación de la entrega en una aplicación de Xamarin
Debido a los requisitos de seguridad impuestos por Handoff, una aplicación de Xamarin.iOS que usa el marco Handoff debe configurarse correctamente en el Portal para desarrolladores de Apple y en el archivo de proyecto de Xamarin.iOS.
Haga lo siguiente:
Inicie sesión en el Portal para desarrolladores de Apple.
Haga clic en Certificados, Identificadores y Perfiles.
Si aún no lo ha hecho, haga clic en Identificadores y cree un identificador para la aplicación (por ejemplo
com.company.appname
, ), edite el identificador existente.Asegúrese de que el servicio iCloud se ha comprobado para el identificador especificado:
Guarde los cambios.
Haga clic en Desarrollo de perfiles>de aprovisionamiento y cree un nuevo perfil de aprovisionamiento de desarrollo para su aplicación:
Descargue e instale el nuevo perfil de aprovisionamiento o use Xcode para descargar e instalar el perfil.
Edite las opciones del proyecto de Xamarin.iOS y asegúrese de que usa el perfil de aprovisionamiento que acaba de crear:
A continuación, edite el archivo Info.plist y asegúrese de que usa el identificador de aplicación que se usó para crear el perfil de aprovisionamiento:
Desplácese hasta la sección Modos de fondo y compruebe los siguientes elementos:
Guarde los cambios en todos los archivos.
Con esta configuración en su lugar, la aplicación ya está lista para acceder a las API de Handoff Framework. Para obtener información detallada sobre el aprovisionamiento, consulte nuestras guías de aprovisionamiento y aprovisionamiento de dispositivos.
Implementación de la entrega
Las actividades de usuario se pueden continuar entre las aplicaciones que están firmadas con el mismo identificador de equipo de desarrollador y admiten el mismo tipo de actividad. La implementación de Handoff en una aplicación de Xamarin.iOS requiere que cree un objeto de actividad de usuario (ya sea en UIKit
o AppKit
), actualice el estado del objeto para realizar el seguimiento de la actividad y continuar con la actividad en un dispositivo receptor.
Identificación de actividades de usuario
El primer paso para implementar Handoff es identificar los tipos de actividades de usuario que admite la aplicación y ver cuáles de esas actividades son buenos candidatos para la continuación en otro dispositivo. Por ejemplo: una aplicación ToDo podría admitir la edición de elementos como un tipo de actividad de usuario y admitir la exploración de la lista de elementos disponibles como otra.
Una aplicación puede crear tantos tipos de actividad de usuario como sea necesario, uno para cualquier función que proporcione la aplicación. Para cada tipo de actividad de usuario, la aplicación tendrá que realizar un seguimiento de cuándo comienza y finaliza una actividad del tipo, y debe mantener la información de estado actualizada para continuar esa tarea en otro dispositivo.
Las actividades de usuario se pueden continuar en cualquier aplicación firmada con el mismo identificador de equipo sin ninguna asignación uno a uno entre las aplicaciones de envío y recepción. Por ejemplo, una aplicación determinada puede crear cuatro tipos diferentes de actividades, que se consumen por diferentes aplicaciones individuales en otro dispositivo. Se trata de una aparición común entre una versión mac de la aplicación (que puede tener muchas características y funciones) y aplicaciones de iOS, donde cada aplicación es más pequeña y se centra en una tarea específica.
Creación de identificadores de tipo de actividad
El identificador de tipo de actividad es una cadena corta agregada a la NSUserActivityTypes
matriz del archivo Info.plist de la aplicación que se usa para identificar de forma única un tipo de actividad de usuario determinado. Habrá una entrada en la matriz para cada actividad que admita la aplicación. Apple sugiere usar una notación de estilo DNS inverso para el identificador de tipo de actividad para evitar colisiones. Por ejemplo: com.company-name.appname.activity
para actividades específicas basadas en aplicaciones o com.company-name.activity
para actividades que se pueden ejecutar en varias aplicaciones.
El identificador de tipo de actividad se usa al crear una NSUserActivity
instancia para identificar el tipo de actividad. Cuando una actividad continúa en otro dispositivo, el tipo de actividad (junto con el identificador de equipo de la aplicación) determina qué aplicación se iniciará para continuar con la actividad.
Por ejemplo, vamos a crear una aplicación de ejemplo denominada MonkeyBrowser (descargar aquí). Esta aplicación presentará cuatro pestañas, cada una con una dirección URL diferente abierta en una vista del explorador web. El usuario podrá continuar con cualquier pestaña de un dispositivo iOS diferente que ejecute la aplicación.
Para crear los identificadores de tipo de actividad necesarios para admitir este comportamiento, edite el archivo Info.plist y cambie a la vista Origen . Agregue una NSUserActivityTypes
clave y cree los siguientes identificadores:
Hemos creado cuatro nuevos identificadores de tipo de actividad, uno para cada una de las pestañas de la aplicación MonkeyBrowser de ejemplo. Al crear sus propias aplicaciones, reemplace el contenido de la NSUserActivityTypes
matriz por los identificadores de tipo de actividad específicos de las actividades que admite la aplicación.
Seguimiento de cambios en la actividad del usuario
Al crear una nueva instancia de la NSUserActivity
clase , especificaremos una instancia para realizar un NSUserActivityDelegate
seguimiento de los cambios en el estado de la actividad. Por ejemplo, el código siguiente se puede usar para realizar un seguimiento de los cambios de estado:
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
}
}
Se llama al UserActivityReceivedData
método cuando un flujo de continuación ha recibido datos de un dispositivo de envío. Para obtener más información, consulte la sección De continuación auxiliar Secuencias siguiente.
Se llama al UserActivityWasContinued
método cuando otro dispositivo ha tomado control de una actividad del dispositivo actual. Según el tipo de actividad, como agregar un nuevo elemento a una lista ToDo, es posible que la aplicación necesite anular la actividad en el dispositivo de envío.
Se UserActivityWillSave
llama al método antes de que los cambios realizados en la actividad se guarden y sincronicen entre dispositivos disponibles localmente. Puede usar este método para realizar cualquier cambio de última hora en la UserInfo
propiedad de la NSUserActivity
instancia antes de enviarlo.
Creación de una instancia de NSUserActivity
Cada actividad que la aplicación desee proporcionar la posibilidad de continuar en otro dispositivo debe estar encapsulada en una NSUserActivity
instancia de . La aplicación puede crear tantas actividades como sea necesario y la naturaleza de esas actividades depende de la funcionalidad y las características de la aplicación en cuestión. Por ejemplo, una aplicación de correo electrónico podría crear una actividad para crear un nuevo mensaje y otra para leer un mensaje.
Para nuestra aplicación de ejemplo, se crea una nueva NSUserActivity
cada vez que el usuario escribe una nueva dirección URL en una de las vistas del explorador web con pestañas. El código siguiente almacena el estado de una pestaña determinada:
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 nuevo NSUserActivity
con uno de los tipos de actividad de usuario creados anteriormente y proporciona un título legible para la actividad. Se asocia a una instancia de la NSUserActivityDelegate
creada anteriormente para ver los cambios de estado e informa a iOS de que esta actividad de usuario es la actividad actual.
Rellenar el diccionario UserInfo
Como hemos visto anteriormente, la UserInfo
propiedad de la NSUserActivity
clase es un NSDictionary
de pares clave-valor usados para definir el estado de una actividad determinada. Los valores almacenados en UserInfo
deben ser uno de los siguientes tipos: NSArray
, NSData
, NSDictionary
NSDate
NSNumber
NSNull
, , NSSet
, NSString
o .NSURL
NSURL
los valores de datos que apuntan a documentos de iCloud se ajustarán automáticamente para que apunten a los mismos documentos en un dispositivo receptor.
En el ejemplo anterior, creamos un NSMutableDictionary
objeto y lo rellenamos con una sola clave que proporcionaba la dirección URL que el usuario estaba viendo actualmente en la pestaña especificada. El AddUserInfoEntries
método de la actividad de usuario se usó para actualizar la actividad con los datos que se usarán para restaurar la actividad en el dispositivo receptor:
// 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 sugiere mantener la información enviada al mínimo más bar para asegurarse de que la actividad se envía de forma oportuna al dispositivo receptor. Si se requiere información más grande, como es necesario enviar una imagen adjunta a un documento, debe usar La continuación Secuencias. Consulte la sección De continuación auxiliar Secuencias a continuación para obtener más información.
Continuar con una actividad
Handoff informará automáticamente a los dispositivos iOS y OS X locales que están en proximidad física al dispositivo de origen e iniciaron sesión en la misma cuenta de iCloud, de la disponibilidad de actividades de usuario continuas. Si el usuario decide continuar una actividad en un nuevo dispositivo, el sistema iniciará la aplicación adecuada (en función del identificador de equipo y el tipo de actividad) e información sobre su AppDelegate
continuación debe producirse.
En primer lugar, se llama al WillContinueUserActivityWithType
método para que la aplicación pueda informar al usuario de que la continuación está a punto de comenzar. Usamos el código siguiente en el archivo AppDelegate.cs de nuestra aplicación de ejemplo para controlar un inicio de continuación:
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;
}
En el ejemplo anterior, cada controlador de vista se registra con AppDelegate
y tiene un método público PreparingToHandoff
que muestra un indicador de actividad y un mensaje que indica al usuario que la actividad está a punto de entregarse al dispositivo actual. Ejemplo:
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...");
}
se ContinueUserActivity
llamará a de AppDelegate
para continuar realmente con la actividad especificada. De nuevo, desde nuestra aplicación de ejemplo:
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;
}
El método público PerformHandoff
de cada controlador de vista preforma realmente la entrega y restaura la actividad en el dispositivo actual. En el caso del ejemplo, muestra la misma dirección URL en una pestaña determinada que el usuario estaba navegando en un dispositivo diferente. Ejemplo:
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 ();
}
El ContinueUserActivity
método incluye un UIApplicationRestorationHandler
que se puede llamar para reanudar la actividad basada en documentos o respondedor. Deberá pasar objetos NSArray
restaurables o al controlador de restauración cuando se llame a . Por ejemplo:
completionHandler (new NSObject[]{Tab4});
Para cada objeto pasado, se llamará a su RestoreUserActivityState
método . Después, cada objeto puede usar los datos del UserInfo
diccionario para restaurar su propio estado. Por ejemplo:
public override void RestoreUserActivityState (NSUserActivity activity)
{
base.RestoreUserActivityState (activity);
// Log activity
Console.WriteLine ("Restoring Activity {0}", activity.Title);
}
En el caso de las aplicaciones basadas en documentos, si no implementa el ContinueUserActivity
método o devuelve false
, UIKit
o AppKit
puede reanudar automáticamente la actividad. Consulte la sección Compatibilidad con entrega en aplicaciones basadas en documentos a continuación para obtener más información.
Error de entrega correctamente
Dado que Handoff se basa en la transmisión de información entre una colección conectada de forma flexible de dispositivos iOS y OS X, el proceso de transferencia a veces puede producir un error. Debes diseñar la aplicación para controlar estos errores correctamente e informar al usuario de las situaciones que surjan.
En caso de error, se llamará al DidFailToContinueUserActivitiy
método de .AppDelegate
Por ejemplo:
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);
}
Debe usar el proporcionado NSError
para proporcionar información al usuario sobre el error.
Entrega de aplicación nativa al explorador web
Es posible que un usuario quiera continuar una actividad sin tener instalada una aplicación nativa adecuada en el dispositivo deseado. En algunas situaciones, una interfaz basada en web puede proporcionar la funcionalidad necesaria y la actividad todavía se puede continuar. Por ejemplo, la cuenta de correo electrónico del usuario puede proporcionar una interfaz de usuario base web para redactar y leer mensajes.
Si se origina, la aplicación nativa conoce la dirección URL de la interfaz web (y la sintaxis necesaria para identificar el elemento dado que continúa), puede codificar esta información en la WebpageURL
propiedad de la NSUserActivity
instancia. Si el dispositivo receptor no tiene instalada una aplicación nativa adecuada para controlar la continuación, se puede llamar a la interfaz web proporcionada.
Entrega del explorador web a la aplicación nativa
Si el usuario usaba una interfaz basada en web en el dispositivo de origen y una aplicación nativa en el dispositivo receptor reclama la parte de dominio de la WebpageURL
propiedad, el sistema usará esa aplicación para controlar la continuación. El nuevo dispositivo recibirá una NSUserActivity
instancia que marca el tipo de actividad como BrowsingWeb
y WebpageURL
contendrá la dirección URL que el usuario estaba visitando, el UserInfo
diccionario estará vacío.
Para que una aplicación participe en este tipo de Handoff, debe reclamar el dominio en un com.apple.developer.associated-domains
derecho con el formato <service>:<fully qualified domain name>
(por ejemplo: activity continuation:company.com
).
Si el dominio especificado coincide con el valor de una WebpageURL
propiedad, Handoff descarga una lista de identificadores de aplicación aprobados del sitio web en ese dominio. El sitio web debe proporcionar una lista de identificadores aprobados en un archivo JSON firmado denominado apple-app-site-association (por ejemplo, https://company.com/apple-app-site-association
).
Este archivo JSON contiene un diccionario que especifica una lista de identificadores de aplicación con el formato <team identifier>.<bundle identifier>
. Por ejemplo:
{
"activitycontinuation": {
"apps": [ "YWBN8XTPBJ.com.company.FirstApp",
"YWBN8XTPBJ.com.company.SecondApp" ]
}
}
Para firmar el archivo JSON (de modo que tenga el valor correcto Content-Type
de application/pkcs7-mime
), use la aplicación Terminal y un comando con un openssl
certificado y una clave emitidos por una entidad de certificación de confianza para iOS (consulte https://support.apple.com/kb/ht5012 para obtener una lista). Por ejemplo:
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
El openssl
comando genera un archivo JSON firmado que coloca en el sitio web en la dirección URL de apple-app-site-association . Por ejemplo:
https://example.com/apple-app-site-association.
La aplicación recibirá cualquier actividad cuyo WebpageURL
dominio esté en su com.apple.developer.associated-domains
derecho. Solo se admiten los http
protocolos y https
, cualquier otro protocolo generará una excepción.
Compatibilidad con la entrega en aplicaciones basadas en documentos
Como se indicó anteriormente, en iOS y OS X, las aplicaciones basadas en documentos admitirán automáticamente la entrega de documentos basados en iCloud si el archivo Info.plist de la aplicación contiene una CFBundleDocumentTypes
clave de NSUbiquitousDocumentUserActivityType
. Por ejemplo:
<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>
En este ejemplo, la cadena es un designador de aplicación DNS inverso con el nombre de la actividad anexada. Si se especifica de esta manera, no es necesario repetir las entradas del tipo de actividad en la NSUserActivityTypes
matriz del archivo Info.plist .
Otros objetos de la aplicación pueden hacer referencia al objeto Actividad de usuario creado automáticamente (disponible a través de la propiedad del UserActivity
documento) y se usan para restaurar el estado en la continuación. Por ejemplo, para realizar un seguimiento de la selección de elementos y la posición del documento. Debe establecer esta propiedad true
activities NeedsSave
en cada vez que el estado cambie y actualice el UserInfo
diccionario en el UpdateUserActivityState
método .
La UserActivity
propiedad se puede usar desde cualquier subproceso y se ajusta al protocolo de observación de clave-valor (KVO), por lo que se puede usar para mantener un documento sincronizado a medida que se mueve hacia y fuera de iCloud. La UserActivity
propiedad se invalidará cuando se cierre el documento.
Para obtener más información, consulte La compatibilidad con la actividad de usuario de Apple en la documentación de aplicaciones basadas en documentos.
Apoyo de entrega en respondedor
Puede asociar respondedores (heredados de UIResponder
en iOS o NSResponder
en OS X) a actividades estableciendo sus UserActivity
propiedades. El sistema guarda automáticamente la UserActivity
propiedad en los momentos adecuados, llamando al método del UpdateUserActivityState
respondedor para agregar datos actuales al objeto Actividad del usuario mediante el AddUserInfoEntriesFromDictionary
método .
Compatibilidad con Secuencias de continuación
Puede ser situaciones en las que la cantidad de información necesaria para continuar con una actividad no se puede transferir eficazmente mediante la carga de entrega inicial. En estas situaciones, la aplicación receptora puede establecer una o varias secuencias entre sí y la aplicación de origen para transferir los datos.
La aplicación de origen establecerá la SupportsContinuationStreams
propiedad de la NSUserActivity
instancia true
en . Por ejemplo:
// 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 ();
A continuación, la aplicación receptora puede llamar al GetContinuationStreams
método de NSUserActivity
en para AppDelegate
establecer la secuencia. Por ejemplo:
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;
}
En el dispositivo de origen, el delegado de actividad de usuario recibe las secuencias llamando a su DidReceiveInputStream
método para proporcionar los datos solicitados para continuar la actividad del usuario en el dispositivo de reanudación.
Usará para NSInputStream
proporcionar acceso de solo lectura a los datos de flujo y proporcionar NSOutputStream
acceso de solo escritura. Las secuencias deben usarse de forma de solicitud y respuesta, donde la aplicación receptora solicita más datos y la aplicación de origen la proporciona. Por lo tanto, los datos escritos en el flujo de salida en el dispositivo de origen se leen desde el flujo de entrada en el dispositivo continuo y viceversa.
Incluso en situaciones en las que se requiera el flujo de continuación, debe haber una comunicación mínima entre las dos aplicaciones.
Para obtener más información, consulte la documentación sobre el uso de continuación de Apple Secuencias.
Procedimientos recomendados de entrega
La implementación correcta de la continuación sin problemas de una actividad de usuario a través de Handoff requiere un diseño cuidadoso debido a todos los distintos componentes implicados. Apple sugiere adoptar los procedimientos recomendados siguientes para las aplicaciones habilitadas para handoff:
- Diseñe las actividades de usuario para requerir la carga más pequeña posible para relacionar el estado de la actividad que se va a continuar. Cuanto mayor sea la carga, más tiempo tardará la continuación en iniciarse.
- Si debe transferir grandes cantidades de datos para una continuación correcta, tenga en cuenta los costos implicados en la configuración y la sobrecarga de red.
- Es habitual que una aplicación mac grande cree actividades de usuario que se controlan mediante varias aplicaciones más pequeñas y específicas de tareas en dispositivos iOS. Las distintas versiones de la aplicación y del sistema operativo deben diseñarse para funcionar bien juntas o con errores correctamente.
- Al especificar los tipos de actividad, use la notación de DNS inverso para evitar colisiones. Si una actividad es específica de una aplicación determinada, su nombre debe incluirse en la definición de tipo (por ejemplo
com.myCompany.myEditor.editing
). Si la actividad puede funcionar en varias aplicaciones, quite el nombre de la aplicación de la definición (por ejemplocom.myCompany.editing
, ). - Si la aplicación necesita actualizar el estado de una actividad de usuario (
NSUserActivity
) establezca laNeedsSave
propiedadtrue
en . En los momentos adecuados, Handoff llamará al método delUserActivityWillSave
delegado para que pueda actualizar elUserInfo
diccionario según sea necesario. - Dado que es posible que el proceso de entrega no se inicialice al instante en el dispositivo receptor, debe implementar los
AppDelegate
"sWillContinueUserActivity
" e informar al usuario de que una continuación está a punto de iniciarse.
Aplicación de entrega de ejemplo
Como ejemplo de uso de Handoff en una aplicación de Xamarin.iOS, hemos incluido la aplicación de ejemplo MonkeyBrowser con esta guía. La aplicación tiene cuatro pestañas que el usuario puede usar para examinar la web, cada una con un tipo de actividad determinado: Weather, Favorite, Coffee Break y Work.
En cualquier pestaña, cuando el usuario escribe una nueva dirección URL y pulsa el botón Ir , se crea una nueva NSUserActivity
pestaña para esa pestaña que contiene la dirección URL que el usuario está explorando actualmente:
Si otro de los dispositivos del usuario tiene instalada la aplicación MonkeyBrowser , inicia sesión en iCloud con la misma cuenta de usuario, está en la misma red y está cerca del dispositivo anterior, la actividad de entrega se mostrará en la pantalla principal (en la esquina inferior izquierda):
Si el usuario se arrastra hacia arriba en el icono De entrega, se iniciará la aplicación y la actividad de usuario especificada en el NSUserActivity
se continuará en el nuevo dispositivo:
Cuando la actividad de usuario se ha enviado correctamente a otro dispositivo Apple, el dispositivo NSUserActivity
de envío recibirá una llamada al UserActivityWasContinued
método en su NSUserActivityDelegate
para informarle de que la actividad del usuario se ha transferido correctamente a otro dispositivo.
Resumen
En este artículo se ha proporcionado una introducción al marco handoff usado para continuar una actividad de usuario entre varios de los dispositivos Apple del usuario. A continuación, se mostró cómo habilitar e implementar Handoff en una aplicación de Xamarin.iOS. Por último, se trataron los diferentes tipos de continuaciones de entrega disponibles y los procedimientos recomendados de entrega.