Transferência no Xamarin.iOS
Este artigo aborda o trabalho com o Handoff em um aplicativo Xamarin.iOS para transferir atividades do usuário entre aplicativos em execução em outros dispositivos do usuário.
A Apple introduziu o Handoff no iOS 8 e no OS X Yosemite (10.10) para fornecer um mecanismo comum para o usuário transferir atividades iniciadas em um de seus dispositivos, para outro dispositivo executando o mesmo aplicativo ou outro aplicativo que suporte a mesma atividade.
Este artigo dará uma olhada rápida na habilitação do compartilhamento de atividades em um aplicativo Xamarin.iOS e abordará a estrutura Handoff em detalhes:
Sobre o Handoff
O Handoff (também conhecido como Continuity) foi introduzido pela Apple no iOS 8 e OS X Yosemite (10.10) como uma forma de o usuário iniciar uma atividade em um de seus dispositivos (iOS ou Mac) e continuar essa mesma atividade em outro de seus dispositivos (conforme identificado pela Conta do iCloud do usuário).
O Handoff foi expandido no iOS 9 para também oferecer suporte a novos recursos de pesquisa aprimorados. Para obter mais informações, consulte nossa documentação de aprimoramentos de pesquisa.
Por exemplo, o usuário pode iniciar um e-mail em seu iPhone e continuar perfeitamente o e-mail em seu Mac, com todas as mesmas informações de mensagem preenchidas e o cursor no mesmo local que ele deixou no iOS.
Qualquer um dos seus aplicativos que compartilham o mesmo ID de Equipe está qualificado para usar o Handoff para continuar as atividades do usuário em todos os aplicativos, desde que esses aplicativos sejam entregues por meio da iTunes App Store ou assinados por um desenvolvedor registrado (para aplicativos Mac, Enterprise ou Ad Hoc).
Todos os NSDocument
aplicativos baseados UIDocument
automaticamente têm suporte a Handoff integrado e exigem alterações mínimas para oferecer suporte a Handoff.
Atividades contínuas do usuário
A NSUserActivity
classe (juntamente com algumas pequenas alterações em UIKit
e AppKit
) fornece suporte para definir a atividade de um usuário que pode ser potencialmente continuada em outro dispositivo do usuário.
Para que uma atividade seja passada para outro dispositivo do usuário, ela deve ser encapsulada em uma instância NSUserActivity
, marcada como Atividade Atual, ter sua carga útil definida (os dados usados para executar a continuação) e a atividade deve ser transmitida para esse dispositivo.
O Handoff passa o mínimo de informações para definir a atividade a ser continuada, com pacotes de dados maiores sendo sincronizados via iCloud.
No dispositivo receptor, o usuário receberá uma notificação de que uma atividade está disponível para continuação. Se o usuário optar por continuar a atividade no novo dispositivo, o aplicativo especificado será iniciado (se ainda não estiver em execução) e a carga útil do NSUserActivity
será usada para reiniciar a atividade.
Somente os aplicativos que compartilham a mesma ID da equipe do desenvolvedor e respondem a um determinado Tipo de Atividade são qualificados para continuação. Um aplicativo define os tipos de atividade que ele oferece suporte sob a NSUserActivityTypes
chave de seu arquivo Info.plist . Diante disso, um dispositivo contínuo escolhe o aplicativo para executar a continuação com base na ID da Equipe, no Tipo de Atividade e, opcionalmente, no Título da Atividade.
O aplicativo de recebimento usa informações do NSUserActivity
dicionário do UserInfo
para configurar sua interface do usuário e restaurar o estado da atividade especificada para que a transição pareça perfeita para o usuário final.
Se a continuação exigir mais informações do que podem ser enviadas de forma eficiente por meio de um NSUserActivity
, o aplicativo de retomada pode enviar uma chamada para o aplicativo de origem e estabelecer um ou mais fluxos para transmitir os dados necessários. Por exemplo, se a atividade estivesse editando um documento de texto grande com várias imagens, o streaming seria necessário para transferir as informações necessárias para continuar a atividade no dispositivo receptor. Para obter mais informações, consulte a seção Suportando fluxos de continuação abaixo.
Como dito acima, NSDocument
os UIDocument
aplicativos baseados automaticamente têm suporte a Handoff integrado. Para obter mais informações, consulte a seção Transferência de suporte em aplicativos baseados em documentos abaixo.
A classe NSUserActivity
A NSUserActivity
classe é o objeto principal em uma troca Handoff e é usada para encapsular o estado de uma atividade do usuário que está disponível para continuação. Um aplicativo instanciará uma cópia de NSUserActivity
qualquer atividade que ele ofereça suporte e deseje continuar em outro dispositivo. Por exemplo, o editor de documentos criaria uma atividade para cada documento atualmente aberto. No entanto, apenas o documento mais frontal (exibido na Janela ou Guia mais à frente) é a Atividade Atual e, portanto, está disponível para continuação.
Uma instância de é identificada NSUserActivity
por suas ActivityType
propriedades e Title
. A UserInfo
propriedade dictionary é usada para transportar informações sobre o estado da atividade. Defina a NeedsSave
propriedade como true
se você quiser carregar preguiçosamente as informações de estado por meio do NSUserActivity
representante do . Use o AddUserInfoEntries
método para mesclar novos dados de outros clientes no dicionário, UserInfo
conforme necessário para preservar o estado da atividade.
A classe NSUserActivityDelegate
O NSUserActivityDelegate
é usado para manter as informações em um NSUserActivity
dicionário do atualizadas UserInfo
e em sincronia com o estado atual da atividade. Quando o sistema precisa que as informações da atividade sejam atualizadas (como antes da continuação em outro dispositivo), ele chama o UserActivityWillSave
método do delegado.
Você precisará implementar o UserActivityWillSave
método e fazer quaisquer alterações no NSUserActivity
(como UserInfo
, Title
, etc.) para garantir que ele ainda reflita o estado da Atividade Atual. Quando o sistema chamar o UserActivityWillSave
método, o NeedsSave
sinalizador será limpo. Se você modificar qualquer uma das propriedades de dados da atividade, precisará definir NeedsSave
como true
novamente.
Em vez de usar o UserActivityWillSave
método apresentado acima, você pode opcionalmente ter UIKit
ou AppKit
gerenciar a atividade do usuário automaticamente. Para fazer isso, defina a propriedade do UserActivity
objeto respondente e implemente o UpdateUserActivityState
método. Consulte a seção Transferência de suporte nos respondentes abaixo para obter mais informações.
Suporte ao App Framework
Tanto UIKit
(iOS) quanto AppKit
(OS X) fornecem suporte interno para Handoff no NSDocument
, Responder (NSResponder
UIResponder
/) e AppDelegate
classes. Embora cada sistema operacional implemente Handoff ligeiramente diferente, o mecanismo básico e as APIs são os mesmos.
Atividades do usuário em aplicativos baseados em documentos
Os aplicativos iOS e OS X baseados em documentos têm automaticamente o suporte a Handoff integrado. Para ativar esse suporte, você precisará adicionar uma chave e um NSUbiquitousDocumentUserActivityType
valor para cada CFBundleDocumentTypes
entrada no arquivo Info.plist do aplicativo.
Se essa chave estiver presente, crie NSDocument
instâncias automaticamente NSUserActivity
para UIDocument
documentos baseados no iCloud do tipo especificado. Você precisará fornecer um tipo de atividade para cada tipo de documento que o aplicativo oferece suporte e vários tipos de documento podem usar o mesmo tipo de atividade. Ambos NSDocument
e preencham UIDocument
automaticamente a UserInfo
propriedade do com o NSUserActivity
valor de sua FileURL
propriedade.
No OS X, o NSUserActivity
gerenciado por AppKit
e associado aos respondentes se torna automaticamente a Atividade Atual quando a janela do documento se torna a janela principal. No iOS, para NSUserActivity
objetos gerenciados pelo UIKit
, você deve chamar BecomeCurrent
o método explicitamente ou ter a propriedade do UserActivity
documento definida em um UIViewController
quando o aplicativo estiver em primeiro plano.
AppKit
irá restaurar automaticamente qualquer UserActivity
propriedade criada desta forma no OS X. Isso ocorre se o ContinueUserActivity
método retorna false
ou se ele não é implementado. Nessa situação, o documento é aberto com o OpenDocument
método do e, em seguida, receberá uma RestoreUserActivityState
chamada de NSDocumentController
método.
Consulte a seção Transferência de suporte em aplicativos baseados em documentos abaixo para obter mais informações.
Atividades do usuário e respondentes
Ambos UIKit
e podem gerenciar automaticamente uma atividade do usuário se você defini-la como propriedade de UserActivity
um objeto de respondenteAppKit
. Se o estado tiver sido modificado, você precisará definir a NeedsSave
propriedade do respondente UserActivity
como true
. O sistema salvará automaticamente o UserActivity
quando necessário, depois de dar ao respondente tempo para atualizar o estado chamando seu UpdateUserActivityState
método.
Se vários respondentes compartilharem uma única NSUserActivity
instância, eles receberão um retorno de UpdateUserActivityState
chamada quando o sistema atualizar o objeto de atividade do usuário. O respondente precisa chamar o AddUserInfoEntries
método para atualizar o NSUserActivity
dicionário do para refletir o estado de UserInfo
atividade atual neste ponto. O UserInfo
dicionário é limpo antes de cada UpdateUserActivityState
chamada.
Para se desassociar de uma atividade, um respondente pode definir sua UserActivity
propriedade como null
. Quando uma instância gerenciada NSUserActivity
da estrutura do aplicativo não tem mais respondentes ou documentos associados, ela é automaticamente invalidada.
Consulte a seção Transferência de suporte nos respondentes abaixo para obter mais informações.
Atividades do usuário e o AppDelegate
O do AppDelegate
aplicativo é o ponto de entrada principal ao lidar com uma continuação de Handoff. Quando o usuário responde a uma notificação de Handoff, o aplicativo apropriado é iniciado (se ainda não estiver em execução) e o WillContinueUserActivityWithType
método do AppDelegate
será chamado. Neste momento, o aplicativo deve informar ao usuário que a continuação está começando.
A NSUserActivity
instância é entregue quando o AppDelegate
método 's ContinueUserActivity
é chamado. Neste ponto, você deve configurar a interface do usuário do aplicativo e continuar a atividade fornecida.
Consulte a seção Implementando Handoff abaixo para obter mais informações.
Ativando o Handoff em um aplicativo Xamarin
Devido aos requisitos de segurança impostos pelo Handoff, um aplicativo Xamarin.iOS que usa a estrutura Handoff deve ser configurado corretamente no Apple Developer Portal e no arquivo de projeto Xamarin.iOS.
Faça o seguinte:
Faça login no Apple Developer Portal.
Clique em Certificados, Identificadores e Perfis.
Se você ainda não tiver feito isso, clique em Identificadores e crie uma ID para seu aplicativo (por exemplo
com.company.appname
, ), caso contrário, edite sua ID existente.Certifique-se de que o serviço do iCloud foi verificado para o ID fornecido:
Salve suas alterações.
Clique em Desenvolvimento de perfis> de provisionamento e crie um novo perfil de provisionamento de desenvolvimento para seu aplicativo:
Baixe e instale o novo perfil de provisionamento ou use o Xcode para baixar e instalar o perfil.
Edite suas opções de projeto Xamarin.iOS e verifique se você está usando o perfil de provisionamento que acabou de criar:
Em seguida, edite o arquivo Info.plist e verifique se você está usando a ID do aplicativo que foi usada para criar o perfil de provisionamento:
Role até a seção Modos de plano de fundo e verifique os seguintes itens:
Salve as alterações em todos os arquivos.
Com essas configurações em vigor, o aplicativo agora está pronto para acessar as APIs do Handoff Framework. Para obter informações detalhadas sobre o provisionamento, consulte nossos guias de provisionamento de dispositivos e provisionamento de seu aplicativo .
Implementando Handoff
As atividades do usuário podem ser continuadas entre aplicativos assinados com a mesma ID da equipe do desenvolvedor e oferecem suporte ao mesmo Tipo de atividade. A implementação do Handoff em um aplicativo Xamarin.iOS requer que você crie um Objeto de Atividade do Usuário (em UIKit
ou em ou AppKit
), atualize o estado do objeto para rastrear a atividade e continue a atividade em um dispositivo receptor.
Identificando atividades do usuário
A primeira etapa na implementação do Handoff é identificar os tipos de atividades do usuário que seu aplicativo oferece suporte e ver quais dessas atividades são boas candidatas para continuação em outro dispositivo. Por exemplo: um aplicativo ToDo pode oferecer suporte à edição de itens como um Tipo de Atividade do Usuário e oferecer suporte à navegação na lista de itens disponíveis como outro.
Um aplicativo pode criar quantos Tipos de Atividade de Usuário forem necessários, um para qualquer função que o aplicativo fornecer. Para cada Tipo de Atividade do Usuário, o aplicativo precisará controlar quando uma atividade do tipo começa e termina e precisa manter as informações de estado atualizadas para continuar essa tarefa em outro dispositivo.
As Atividades do Usuário podem ser continuadas em qualquer aplicativo assinado com a mesma ID de Equipe sem qualquer mapeamento um-para-um entre os aplicativos de envio e recebimento. Por exemplo, um determinado aplicativo pode criar quatro tipos diferentes de atividades, que são consumidas por aplicativos diferentes e individuais em outro dispositivo. Essa é uma ocorrência comum entre uma versão Mac do aplicativo (que pode ter muitos recursos e funções) e aplicativos iOS, onde cada aplicativo é menor e focado em uma tarefa específica.
Criando identificadores de tipo de atividade
O Identificador de Tipo de Atividade é uma cadeia de caracteres curta adicionada à NSUserActivityTypes
matriz do arquivo Info.plist do aplicativo usada para identificar exclusivamente um determinado Tipo de Atividade do Usuário. Haverá uma entrada na matriz para cada atividade que o aplicativo suporta. A Apple sugere o uso de uma notação no estilo DNS reverso para o Identificador de Tipo de Atividade para evitar colisões. Por exemplo: com.company-name.appname.activity
para atividades específicas baseadas em aplicativos ou com.company-name.activity
para atividades que podem ser executadas em vários aplicativos.
O Identificador de Tipo de Atividade é usado ao criar uma NSUserActivity
instância para identificar o tipo de atividade. Quando uma atividade é continuada em outro dispositivo, o Tipo de Atividade (junto com a ID da Equipe do aplicativo) determina qual aplicativo iniciar para continuar a atividade.
Como exemplo, vamos criar um aplicativo de exemplo chamado MonkeyBrowser. Este aplicativo apresentará quatro guias, cada uma com uma URL diferente aberta em uma exibição do navegador da Web. O usuário poderá continuar qualquer guia em um dispositivo iOS diferente executando o aplicativo.
Para criar os identificadores de tipo de atividade necessários para oferecer suporte a esse comportamento, edite o arquivo Info.plist e alterne para o modo de exibição Origem . Adicione uma NSUserActivityTypes
chave e crie os seguintes identificadores:
Criamos quatro novos Identificadores de Tipo de Atividade, um para cada uma das guias no aplicativo MonkeyBrowser de exemplo. Ao criar seus próprios aplicativos, substitua o conteúdo da matriz pelos Identificadores de Tipo de NSUserActivityTypes
Atividade específicos para as atividades que seu aplicativo suporta.
Acompanhando alterações na atividade do usuário
Quando criamos uma nova instância da NSUserActivity
classe, especificamos uma NSUserActivityDelegate
instância para controlar as alterações no estado da atividade. Por exemplo, o código a seguir pode ser usado para controlar alterações 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
}
}
O UserActivityReceivedData
método é chamado quando um fluxo de continuação recebeu dados de um dispositivo de envio. Para obter mais informações, consulte a seção Suportando fluxos de continuação abaixo.
O UserActivityWasContinued
método é chamado quando outro dispositivo assumiu uma atividade do dispositivo atual. Dependendo do tipo de atividade, como adicionar um novo item a uma lista de tarefas pendentes, o aplicativo pode precisar interromper a atividade no dispositivo de envio.
O UserActivityWillSave
método é chamado antes que quaisquer alterações na atividade sejam salvas e sincronizadas entre dispositivos disponíveis localmente. Você pode usar esse método para fazer alterações de última hora na UserInfo
propriedade da instância antes que NSUserActivity
ela seja enviada.
Criando uma instância NSUserActivity
Cada atividade que seu aplicativo deseja fornecer a possibilidade de continuar em outro dispositivo deve ser encapsulada em uma NSUserActivity
instância. O aplicativo pode criar quantas atividades forem necessárias e a natureza dessas atividades depende da funcionalidade e dos recursos do aplicativo em questão. Por exemplo, um aplicativo de email pode criar uma atividade para criar uma nova mensagem e outra para ler uma mensagem.
Para nosso aplicativo de exemplo, um novo NSUserActivity
é criado sempre que o usuário insere uma nova URL em uma das exibições do navegador da Web com guias. O código a seguir armazena o estado de uma determinada guia:
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 ();
Ele cria um novo NSUserActivity
usando um dos tipos de atividade de usuário criados acima e fornece um título legível por humanos para a atividade. Ele anexa a uma instância do NSUserActivityDelegate
criado acima para observar as alterações de estado e informa ao iOS que essa Atividade do Usuário é a Atividade Atual.
Preenchendo o dicionário UserInfo
Como vimos acima, a UserInfo
NSUserActivity
propriedade da classe é um NSDictionary
dos pares chave-valor usados para definir o estado de uma determinada atividade. Os valores armazenados em UserInfo
devem ser de um dos seguintes tipos: NSArray
, NSData
, NSDate
, NSDictionary
, NSNull
, , NSNumber
, NSSet
, ou NSString
NSURL
. NSURL
Os valores de dados que apontam para documentos do iCloud serão ajustados automaticamente para que apontem para os mesmos documentos em um dispositivo receptor.
No exemplo acima, criamos um NSMutableDictionary
objeto e o preenchemos com uma única chave fornecendo a URL que o usuário estava visualizando atualmente na guia fornecida. O AddUserInfoEntries
método da Atividade do Usuário foi usado para atualizar a atividade com os dados que serão usados para restaurar a atividade no 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);
A Apple sugere manter as informações enviadas ao mínimo para garantir que a atividade seja enviada em tempo hábil para o dispositivo receptor. Se forem necessárias informações maiores, como uma imagem anexada a um documento a ser editado, você deve usar Fluxos de Continuação. Consulte a seção Suportes de Fluxos de Continuação abaixo para obter mais detalhes.
Continuando uma atividade
O Handoff informará automaticamente os dispositivos iOS e OS X locais que estão em proximidade física com o dispositivo de origem e conectados à mesma conta do iCloud, sobre a disponibilidade de Atividades de Usuário contínuas. Se o usuário optar por continuar uma atividade em um novo dispositivo, o sistema iniciará o aplicativo apropriado (com base na ID da Equipe e no Tipo de Atividade) e informará AppDelegate
que a continuação precisa ocorrer.
Primeiro, o WillContinueUserActivityWithType
método é chamado para que o aplicativo possa informar ao usuário que a continuação está prestes a começar. Usamos o seguinte código no arquivo de AppDelegate.cs de nosso aplicativo de exemplo para lidar com uma continuação iniciando:
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;
}
No exemplo acima, cada View Controller se registra com o AppDelegate
e tem um método público PreparingToHandoff
que exibe um indicador de atividade e uma mensagem informando ao usuário que a atividade está prestes a ser entregue ao dispositivo atual. Exemplo:
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...");
}
O ContinueUserActivity
do AppDelegate
será chamado para realmente continuar a atividade dada. Novamente, a partir do nosso aplicativo de exemplo:
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;
}
O método público PerformHandoff
de cada View Controller realmente preforma a transferência e restaura a atividade no dispositivo atual. No caso do exemplo, ele exibe a mesma URL em uma determinada guia que o usuário estava navegando em um dispositivo diferente. Exemplo:
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 ();
}
O ContinueUserActivity
método inclui um UIApplicationRestorationHandler
que você pode chamar para a retomada da atividade baseada em documento ou respondente. Você precisará passar um NSArray
ou objetos restauráveis para o manipulador de restauração quando chamado. Por exemplo:
completionHandler (new NSObject[]{Tab4});
Para cada objeto passado, seu RestoreUserActivityState
método será chamado. Cada objeto pode usar os dados no UserInfo
dicionário para restaurar seu próprio estado. Por exemplo:
public override void RestoreUserActivityState (NSUserActivity activity)
{
base.RestoreUserActivityState (activity);
// Log activity
Console.WriteLine ("Restoring Activity {0}", activity.Title);
}
Para aplicativos baseados em documentos, se você não implementar o ContinueUserActivity
método ou ele retornar false
, UIKit
ou AppKit
puder retomar automaticamente a atividade. Consulte a seção Transferência de suporte em aplicativos baseados em documentos abaixo para obter mais informações.
Falha na transferência graciosa
Como o Handoff depende da transmissão de informações entre uma coleção de dispositivos iOS e OS X conectados de forma frouxa, o processo de transferência às vezes pode falhar. Você deve projetar seu aplicativo para lidar com essas falhas normalmente e informar o usuário sobre quaisquer situações que surjam.
Em caso de falha, o DidFailToContinueUserActivitiy
método do AppDelegate
será chamado. Por exemplo:
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);
}
Você deve usar o fornecido NSError
para fornecer informações ao usuário sobre a falha.
Transferência de aplicativo nativo para navegador da Web
Um usuário pode querer continuar uma atividade sem ter um aplicativo nativo apropriado instalado no dispositivo desejado. Em algumas situações, uma interface baseada na Web pode fornecer a funcionalidade necessária e a atividade ainda pode ser continuada. Por exemplo, a conta de email do usuário pode fornecer uma interface do usuário baseada na Web para compor e ler mensagens.
Se o aplicativo nativo de origem souber a URL da interface da Web (e a sintaxe necessária para identificar o determinado item que está sendo continuado), ele poderá codificar essas informações na WebpageURL
propriedade da NSUserActivity
instância. Se o dispositivo de recebimento não tiver um aplicativo nativo apropriado instalado para lidar com a continuação, a interface da Web fornecida poderá ser chamada.
Transferência do navegador da Web para o aplicativo nativo
Se o usuário estava usando uma interface baseada na Web no dispositivo de origem e um aplicativo nativo no dispositivo de recebimento reivindica a parte de domínio da WebpageURL
propriedade, o sistema usará esse aplicativo para manipular a continuação. O novo dispositivo receberá uma NSUserActivity
instância que marca o Tipo de Atividade como BrowsingWeb
e o WebpageURL
conterá a URL que o usuário estava visitando, o UserInfo
dicionário estará vazio.
Para que um aplicativo participe desse tipo de Handoff, ele deve reivindicar o domínio em um com.apple.developer.associated-domains
direito com o formato <service>:<fully qualified domain name>
(por exemplo: activity continuation:company.com
).
Se o domínio especificado corresponder ao valor de uma WebpageURL
propriedade, o Handoff baixará uma lista de IDs de aplicativo aprovados do site nesse domínio. O site deve fornecer uma lista de IDs aprovados em um arquivo JSON assinado chamado apple-app-site-association (por exemplo, https://company.com/apple-app-site-association
).
Esse arquivo JSON contém um dicionário que especifica uma lista de IDs de aplicativo no formato <team identifier>.<bundle identifier>
. Por exemplo:
{
"activitycontinuation": {
"apps": [ "YWBN8XTPBJ.com.company.FirstApp",
"YWBN8XTPBJ.com.company.SecondApp" ]
}
}
Para assinar o arquivo JSON (para que ele tenha o correto Content-Type
de ), use o aplicativo Terminal e um comando com um certificado e uma openssl
chave emitidos por uma autoridade de application/pkcs7-mime
certificação confiável pelo iOS (consulte https://support.apple.com/kb/ht5012 para obter uma lista). Por exemplo:
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
O openssl
comando gera um arquivo JSON assinado que você coloca em seu site na URL apple-app-site-association . Por exemplo:
https://example.com/apple-app-site-association.
O aplicativo receberá qualquer atividade cujo WebpageURL
domínio esteja em seu com.apple.developer.associated-domains
direito. Apenas os protocolos e https
são suportadoshttp
, qualquer outro protocolo levantará uma exceção.
Suporte a transferência em aplicativos baseados em documentos
Como dito acima, no iOS e no OS X, os aplicativos baseados em documentos suportarão automaticamente a transferência de documentos baseados no iCloud se o arquivo Info.plist do aplicativo contiver uma CFBundleDocumentTypes
chave de NSUbiquitousDocumentUserActivityType
. Por exemplo:
<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>
Neste exemplo, a cadeia de caracteres é um designador de aplicativo DNS reverso com o nome da atividade anexado. Se inseridas dessa forma, as entradas de tipo de atividade não precisam ser repetidas NSUserActivityTypes
na matriz do arquivo Info.plist .
O objeto User Activity criado automaticamente (disponível por meio da propriedade do UserActivity
documento) pode ser referenciado por outros objetos no aplicativo e usado para restaurar o estado na continuação. Por exemplo, para controlar a seleção de itens e a posição do documento. Você precisa definir essa propriedade activities NeedsSave
para true
sempre que o estado for alterado e atualizar o UserInfo
dicionário no UpdateUserActivityState
método.
A UserActivity
propriedade pode ser usada a partir de qualquer thread e está em conformidade com o protocolo KVO (key-value observando), para que possa ser usada para manter um documento sincronizado à medida que entra e sai do iCloud. A UserActivity
propriedade será invalidada quando o documento for fechado.
Para obter mais informações, consulte a documentação Suporte à atividade do usuário da Apple em Aplicativos baseados em documentos.
Suporte à transferência em respondentes
Você pode associar respondentes (herdados do UIResponder
iOS ou NSResponder
do OS X) a atividades definindo suas UserActivity
propriedades. O sistema salva automaticamente a UserActivity
propriedade nos momentos apropriados, chamando o método do UpdateUserActivityState
respondente para adicionar dados atuais ao objeto User Activity usando o AddUserInfoEntriesFromDictionary
método.
Suporte a fluxos de continuação
Podem ser situações em que a quantidade de informações necessárias para continuar uma atividade não pode ser transferida de forma eficiente pela carga inicial de Handoff. Nessas situações, o aplicativo de recebimento pode estabelecer um ou mais fluxos entre ele e o aplicativo de origem para transferir os dados.
O aplicativo de origem definirá a SupportsContinuationStreams
NSUserActivity
propriedade da instância como true
. Por exemplo:
// 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 ();
O aplicativo de recebimento pode então chamar o GetContinuationStreams
NSUserActivity
método do em seu AppDelegate
para estabelecer o fluxo. Por exemplo:
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;
}
No dispositivo de origem, o Delegado de Atividade do Usuário recebe os fluxos chamando seu DidReceiveInputStream
método para fornecer os dados solicitados para continuar a atividade do usuário no dispositivo de retomada.
Você usará um NSInputStream
para fornecer acesso somente leitura a dados de fluxo e um NSOutputStream
fornecer acesso somente gravação. Os fluxos devem ser usados de forma de solicitação e resposta, em que o aplicativo de recebimento solicita mais dados e o aplicativo de origem os fornece. Para que, os dados gravados no fluxo de saída no dispositivo de origem sejam lidos a partir do fluxo de entrada no dispositivo contínuo e vice-versa.
Mesmo em situações em que o Fluxo de Continuação é necessário, deve haver um mínimo de comunicação de ida e volta entre os dois aplicativos.
Para obter mais informações, consulte a documentação Usando fluxos de continuação da Apple.
Práticas recomendadas de transferência
A implementação bem-sucedida da continuação contínua de uma atividade do usuário via Handoff requer um design cuidadoso devido a todos os vários componentes envolvidos. A Apple sugere adotar as seguintes práticas recomendadas para seus aplicativos habilitados para Handoff:
- Projete suas Atividades de Usuário para exigir a menor carga útil possível para relacionar o estado da atividade a ser continuada. Quanto maior a carga útil, mais tempo leva para iniciar a continuação.
- Se você precisar transferir grandes quantidades de dados para uma continuidade bem-sucedida, leve em consideração os custos envolvidos na configuração e na sobrecarga de rede.
- É comum que um aplicativo Mac grande crie Atividades do Usuário que são manipuladas por vários, menores e específicos de tarefas em dispositivos iOS. As diferentes versões do aplicativo e do sistema operacional devem ser projetadas para funcionar bem juntas ou falhar normalmente.
- Ao especificar seus tipos de atividade, use a notação DNS reverso para evitar colisões. Se uma atividade for específica de um determinado aplicativo, seu nome deverá ser incluído na definição de tipo (por exemplo
com.myCompany.myEditor.editing
). Se a atividade puder funcionar em vários aplicativos, remova o nome do aplicativo da definição (por exemplocom.myCompany.editing
, ). - Se seu aplicativo precisar atualizar o estado de uma Atividade do Usuário (
NSUserActivity
), defina aNeedsSave
propriedade comotrue
. Em momentos apropriados, o Handoff chamará o método doUserActivityWillSave
delegado para que você possa atualizar oUserInfo
dicionário conforme necessário. - Como o processo de Handoff pode não inicializar instantaneamente no dispositivo receptor, você deve implementar o
AppDelegate
sWillContinueUserActivity
e informar ao usuário que uma continuação está prestes a começar.
Exemplo de aplicativo de transferência
Um exemplo de uso do Handoff em um aplicativo Xamarin.iOS é o aplicativo de exemplo MonkeyBrowser . O aplicativo tem quatro abas que o usuário pode usar para navegar na web, cada uma com um determinado tipo de atividade: Clima, Favorito, Coffee Break e Trabalho.
Em qualquer guia, quando o usuário insere uma nova URL e toca no botão Ir , uma nova NSUserActivity
é criada para essa guia que contém a URL que o usuário está navegando no momento:
Se outro dos dispositivos do usuário tiver o aplicativo MonkeyBrowser instalado, estiver conectado ao iCloud usando a mesma conta de usuário, estiver na mesma rede e próximo ao dispositivo acima, a Atividade de transferência será exibida na tela inicial (no canto inferior esquerdo):
Se o usuário arrastar para cima no ícone Handoff, o aplicativo será iniciado e a Atividade do Usuário especificada no NSUserActivity
será continuada no novo dispositivo:
Quando a Atividade do Usuário tiver sido enviada com êxito para outro dispositivo Apple, o dispositivo remetente NSUserActivity
receberá uma chamada para o UserActivityWasContinued
método nele NSUserActivityDelegate
para informá-lo de que a Atividade do Usuário foi transferida com êxito para outro dispositivo.
Resumo
Este artigo deu uma introdução à estrutura Handoff usada para continuar uma atividade do usuário entre vários dispositivos Apple do usuário. Em seguida, ele mostrou como habilitar e implementar o Handoff em um aplicativo Xamarin.iOS. Finalmente, discutiu os diferentes tipos de continuações de Handoff disponíveis e as melhores práticas de Handoff.