A Tutorial sobre iOS 8 App Extensions

Few tinha tentado antes (veja isto), mas foi a Apple com o primeiro iPhone que definiu como um Smartphone e um SO móvel deveriam ser. A Apple fez um incrível avanço no hardware e na experiência do usuário. No entanto, muitas vezes esquecemos que eles também definem padrões de como um SO móvel deve funcionar, e como um aplicativo Smartphone deve ser feito.

Construir paredes de concreto entre as aplicações, tornando-as completamente isoladas e desconhecidas umas das outras, foi o melhor método para mantê-las seguras e proteger seus dados. Todas as atividades foram monitoradas de perto pelo iOS, e havia apenas um punhado de ações que uma aplicação poderia ter feito fora do seu escopo.

“A abstinência é a melhor proteção”! – mas onde está a diversão nisso?

Demorou um pouco; muito tempo se você me perguntar, mas com o iOS 8 a Apple decidiu se divertir um pouco. O iOS 8 introduziu um novo conceito chamado Extensões de Aplicações. Esta nova funcionalidade não derrubou as paredes entre as aplicações, mas abriu algumas portas proporcionando um contacto suave mas tangível entre algumas aplicações. A última atualização deu aos desenvolvedores do iOS uma opção para personalizar o ecossistema iOS, e estamos ansiosos para ver este caminho abrindo também.

O que são as Extensões App do iOS 8 e como elas funcionam?

Em termos simples, as Extensões App do iOS 8 fornecem um novo método de interagir com sua aplicação, sem iniciá-la ou mostrá-la na tela.

Como esperado, a Apple se certificou de que elas permanecessem em cima de tudo, então há apenas um punhado de novos pontos de entrada que sua aplicação pode fornecer:

  • Today (também chamado de widget) – uma extensão exibida na visão Today do Centro de Notificação mostra informações breves e permite a execução de tarefas rápidas.
  • Share – uma extensão que permite que seu aplicativo compartilhe conteúdo com usuários em redes sociais e outros serviços de compartilhamento.
  • Action – uma extensão que permite criar botões de ação personalizados na folha Action para permitir que os usuários visualizem ou transformem conteúdo originado em um aplicativo hospedeiro.
  • Edição de fotos – uma extensão que permite aos usuários editar uma foto ou um vídeo dentro do aplicativo Photos.
  • Provedor de documentos – uma extensão usada para permitir que outros aplicativos acessem os documentos gerenciados pelo seu aplicativo.
  • Teclado personalizado – uma extensão que substitui o teclado do sistema.

As extensões do aplicativo não são aplicativos autônomos. Elas estão fornecendo funcionalidades estendidas do aplicativo (que podem ser acessadas de outros aplicativos, chamados de aplicativos host) que se destinam a ser eficientes e focadas em uma única tarefa. Elas têm seu próprio binário, assinatura de código própria e conjunto próprio de elementos, mas são entregues através da App Store como parte do binário do aplicativo que contém o aplicativo. Um (contendo) aplicativo pode ter mais de uma extensão. Uma vez que o usuário instale um aplicativo que tenha extensões, elas estarão disponíveis em iOS.

Vejamos um exemplo: Um usuário encontra uma imagem usando o Safari, clica no botão compartilhar e escolhe sua extensão de aplicativo para compartilhar. O Safari “fala” com o framework iOS Social, que carrega e apresenta a extensão. O código da extensão roda, passa os dados usando os canais de comunicação instanciados do sistema e, uma vez terminada a tarefa, o Safari derruba a visualização da extensão. Logo após, o sistema encerra o processo, e sua aplicação nunca foi exibida na tela. Mesmo assim completou uma função de compartilhamento de imagens.

iOS, usando comunicação entre processos, é o responsável por garantir que a aplicação host e uma extensão da aplicação possam trabalhar em conjunto. Os desenvolvedores usam APIs de alto nível fornecidas pelo ponto de extensão e pelo sistema, assim eles nunca precisam se preocupar com os mecanismos de comunicação subjacentes.

Life Cycle

>

App Extensions têm um ciclo de vida diferente dos aplicativos iOS. O aplicativo host inicia o ciclo de vida da extensão como uma resposta à ação de um usuário. Então o sistema instancia a extensão da aplicação e estabelece um canal de comunicação entre elas. A visão da extensão é exibida dentro do contexto do aplicativo host usando os itens recebidos no pedido do aplicativo host. Uma vez que a visão da extensão é exibida, o usuário pode interagir com ela. Em resposta à ação do usuário, a extensão completa a solicitação da aplicação do host executando/cancelando imediatamente a tarefa ou, se necessário, iniciando um processo em background para executá-la. Logo em seguida, a aplicação do host destrói a visão da extensão e o usuário retorna ao seu contexto anterior dentro da aplicação do host. Os resultados da execução deste processo podem ser retornados para a aplicação do host assim que o processo for concluído. A extensão normalmente é encerrada logo após completar a solicitação recebida da aplicação do host (ou inicia um processo em background para executá-la).

O sistema abre a extensão da ação de um usuário da aplicação do host, a extensão exibe a IU, executa algum trabalho e retorna os dados para a aplicação do host (se isso for apropriado para o tipo da extensão). O aplicativo que contém o aplicativo não está nem rodando enquanto sua extensão está rodando.

Criando uma Extensão do aplicativo – Exemplo de uso da Extensão Today

As extensões Today, também chamadas widgets, estão localizadas na visão Today do centro de Notificação. Elas são uma ótima maneira de apresentar um conteúdo atualizado para o usuário (como mostrar as condições climáticas) ou realizar tarefas rápidas (como marcar as coisas feitas em um widget de lista de tarefas). Eu tenho que apontar aqui que a entrada do teclado não é suportada.

Vamos criar uma extensão Today que exibirá as informações mais atualizadas do nosso aplicativo (código no GitHub). Para executar este código, certifique-se de que você (re)configurou o App Group para o projeto (selecione sua Equipe de Desenvolvimento, tenha em mente que o nome do App Group tem que ser único e siga as instruções do Xcode).

Criando um Novo Widget

Como dissemos anteriormente, as extensões do aplicativo não são aplicativos isolados. Precisamos de uma aplicação contendo a extensão da aplicação sobre a qual vamos construir a extensão da aplicação. Uma vez que tenhamos nosso aplicativo contendo, escolhemos adicionar um novo alvo navegando para File -> New -> Target into Xcode. A partir daqui escolhemos o template para o nosso novo target para adicionar uma extensão Today Extension.

No próximo passo podemos escolher o nosso nome de produto. Esse é o nome que aparecerá na visualização do Centro de Notificação de Hoje. Há uma opção para escolher o idioma entre Swift e Objective-C também neste passo. Ao finalizar estes passos, o Xcode cria um modelo Today, que fornece o cabeçalho padrão e arquivos de implementação para a classe principal (chamado TodayViewController) com Info.plist arquivo e um arquivo de interface (um storyboard ou arquivo .xib). O arquivo Info.plist, por padrão, se parece com isto:

Se você não quiser usar a storyboard fornecida pelo modelo, remova a tecla NSExtensionMainStoryboard e adicione a tecla NSExtensionPrincipalClass com o nome do seu controlador de visualização como um valor.

Um widget Today deve:

  • seguir que o conteúdo esteja sempre actualizado
  • responder adequadamente às interacções do utilizador
  • performar bem (os widgets iOS devem usar a memória sabiamente ou serão terminados pelo sistema)

Partilhar dados e um contentor partilhado

A extensão da aplicação e a sua aplicação contendo ambos têm acesso aos dados partilhados no seu contentor partilhado privado definido – que é uma forma de comunicação indirecta entre o aplicativo que contém e a extensão.

Não adora como a Apple torna estas coisas tão “simples”? 🙂

Partilhar dados através de NSUserDefaults é simples e um caso de uso comum. Por padrão, a extensão e o aplicativo que a contém usam conjuntos de dados separados NSUserDefaults, e não podem acessar os containers um do outro. Para alterar este comportamento, o iOS introduziu Grupos de Aplicativos. Após habilitar os grupos de aplicativos no aplicativo que contém a extensão, em vez de usar use initWithSuiteName:@"group.yourAppGroupName"] para acessar o mesmo container compartilhado.

Updating the Widget

Para garantir que o conteúdo esteja sempre atualizado, a extensão Today fornece uma API para gerenciar o estado de um widget e lidar com atualizações de conteúdo. O sistema ocasionalmente captura instantâneos da visualização do widget, assim quando o widget se torna visível, o instantâneo mais recente é exibido até que seja substituído por uma versão ao vivo da visualização. Uma conformação com o protocolo NCWidgetProviding é importante para atualizar o estado de um widget antes que uma snapshot seja tirada. Uma vez que o widget recebe a chamada widgetPerformUpdateWithCompletionHandler:, a vista do widget deve ser atualizada com o conteúdo mais recente e o completador deve ser chamado com uma das seguintes constantes para descrever o resultado da atualização:

  • NCUpdateResultNewData – O novo conteúdo requer o redesenho da view
  • NCUpdateResultNoDate – O widget não requer atualização
  • NCUpdateResultFailed – Ocorreu um erro durante o processo de atualização

Controlar Quando o Widget É Visualizável

Para controlar quando um widget é exibido, use o método setHasContent:forWidgetWithBundleIdentifier: de NCWidgetController classe. Este método permitirá que você especifique o estado do conteúdo do widget. Ele pode ser chamado a partir do widget ou do aplicativo que o contém (se ele estiver ativo). Você pode passar uma bandeira NO ou YES para este método, definindo que o conteúdo do widget está pronto ou não. Se o conteúdo não estiver pronto, o iOS não exibirá seu widget quando a visualização Today for aberta.

Abrir a aplicação contendo o widget

O widget Today é a única extensão que pode solicitar a abertura da sua aplicação contendo, chamando o método openURL:completionHandler:. Para garantir que a aplicação contendo se abra de uma forma que faça sentido no contexto da tarefa atual do usuário, um esquema URL personalizado (que tanto o widget quanto a aplicação contendo podem usar) deve ser definido.

 completionHandler:nil];

UI Considerations

Ao projetar seu widget, aproveite a classe UIVisualEffectView, tendo em mente que as vistas que devem ser borradas/vibrantes devem ser adicionadas ao contentView e não diretamente ao UIVisualEffectView. Widgets (de acordo com o protocolo NCWidgetProviding) devem carregar os estados em cache em viewWillAppear: a fim de combinar o estado da vista do último viewWillDisappear: e então transitar suavemente para os novos dados quando eles chegarem, o que não é um caso com um controlador de vista normal (UI é configurado em viewDidLoad e lida com animações e carregamento de dados em viewWillAppear). Widgets devem ser projetados para executar uma tarefa, ou abrir o aplicativo que os contém com um único toque. A entrada do teclado não está disponível dentro de um widget. Isto significa que não deve ser usada qualquer IU que necessite de entrada de texto.

Adicionar scrolls em um widget, tanto vertical como horizontal, não é possível. Ou, mais precisamente, adicionar uma vista de rolagem é possível, mas a rolagem não funciona. O gesto de rolagem horizontal em uma vista de rolagem na extensão Today será interceptado pelo centro de notificação o que causará a rolagem de Today para o centro de notificação. Rolando verticalmente uma vista de rolagem dentro de uma extensão de Hoje será interrompida rolando a vista de Hoje.

Notações Técnicas

Aqui vou apontar algumas coisas importantes a ter em mente ao criar uma Extensão App.

Faatures Common to All Extensions

Os seguintes itens são verdadeiros para todas as extensões:

  • O objeto Application está fora dos limites: Extensões App não podem acessar um objeto App compartilhado, ou usar qualquer um dos métodos relacionados a esse objeto.

  • Câmera e microfone estão fora dos limites: As extensões App não podem acessar a câmera ou microfone no dispositivo (mas este não é um caso para todos os elementos de hardware). Isto é um resultado da indisponibilidade de algumas APIs. Para acessar alguns elementos de hardware na extensão da aplicação, você terá que verificar se sua API está disponível para extensões de aplicação ou não (com a verificação de disponibilidade da API descrita acima).

  • As tarefas de fundo estão off limits: Extensões de aplicativos não podem executar tarefas em segundo plano de longa duração, exceto iniciar uploads ou downloads, que é discutido abaixo.

  • AirDrop está fora dos limites: As extensões de aplicação não podem receber (mas podem enviar) dados usando AirDrop.

Upload/Downloading in the Background

A única tarefa que pode ser executada em segundo plano é o upload/download, usando o arquivo NSURLSession object.

Após a tarefa de upload/download ser iniciada, a extensão pode completar o pedido da aplicação host e ser finalizada sem qualquer efeito no resultado da tarefa. Se a extensão não estiver sendo executada no momento em que a tarefa em segundo plano for concluída, o sistema iniciará o aplicativo contendo em segundo plano e o método de delegado do aplicativo application:handleEventsForBackgroundURLSession:completionHandler: será chamado.

O aplicativo cuja extensão inicia um plano de fundo NSURLSession tarefa deve ter um container compartilhado configurado que tanto o aplicativo contendo quanto sua extensão possam acessar.

Cria sessões de fundo diferentes para o aplicativo contendo e cada uma de suas extensões de aplicativo (cada sessão de fundo deve ter um identificador único). Isto é importante porque apenas um processo pode usar uma sessão em segundo plano de cada vez.

Action vs. Share

As diferenças entre as extensões Action e Share não são completamente claras do ponto de vista de um codificador, porque na prática elas são muito semelhantes. O modelo do Xcode para o alvo da extensão Share usa SLComposeServiceViewController, que fornece uma IU de visualização padrão de composição que você pode usar para compartilhamento social, mas não é necessário. Uma extensão de compartilhamento também pode herdar diretamente do UIViewController para um design totalmente personalizado, da mesma forma que uma extensão Action pode herdar de SLComposeServiceViewController.

As diferenças entre esses dois tipos de extensões está em como elas devem ser usadas. Com a extensão Action, você pode construir uma extensão sem uma IU própria (por exemplo, uma extensão usada para traduzir o texto selecionado e retornar a tradução para o aplicativo hospedeiro). A extensão Share permite compartilhar comentários, fotos, vídeos, áudio, links e muito mais diretamente do aplicativo hospedeiro. A extensão UIActivityViewController conduz ambas as extensões Action e Share, onde as extensões Share são apresentadas como ícones coloridos na linha superior e as extensões action são apresentadas como ícones monocromáticos na linha inferior (Imagem 2.1).

Forbidden APIs

APIs marcados nos arquivos de cabeçalho com a macro NS_EXTENSION_UNAVAILABLE, ou macro similar para indisponibilidade, não podem ser usados (por exemplo: HealthKit e EventKit UI frameworks no iOS 8 não estão disponíveis para uso em nenhuma extensão de aplicativo).

Se você estiver compartilhando código entre um aplicativo e uma extensão, você tem que ter em mente que mesmo referenciando uma API que não é permitida para a extensão do aplicativo levará à rejeição do seu aplicativo a partir da App Store. Você pode optar por lidar com isso refazendo as classes compartilhadas em hierarquias, com um pai comum e subclasses diferentes para alvos diferentes. Outra maneira é usar o pré-processador por #ifdef verificações. Como ainda não há um target condicional incorporado, você tem que criar o seu próprio.

Outra maneira agradável de fazer isso é criando o seu próprio framework incorporado. Apenas certifique-se de que ele não conterá nenhuma API indisponível para extensões. Para configurar uma extensão de aplicativo para usar um framework embarcado, navegue até as configurações de compilação do target e defina a configuração “Require Only App-Extension-Safe API” para Sim. Ao configurar o projeto Xcode, na fase de compilação Copy Files, “Frameworks” deve ser escolhido como o destino para o framework embarcado. Se você escolher o destino “SharedFrameworks”, sua submissão será rejeitada pela App Store.

A Note on Backwards Compatibility

Although app extensions have only been available since iOS 8, you can make your containing app available to the prior iOS versions.

Apple Human Interface Compliance

Keeps mind Apple’s iOS Human Interface Guidelines when designing an app extension. Você deve assegurar que sua extensão de aplicativo seja universal, não importando qual dispositivo seu aplicativo contenha suporte. Para garantir que a extensão de aplicativo seja universal, use a configuração de construção da família de dispositivos alvo no Xcode especificando o valor “iPhone/iPad” (às vezes chamado de universal).

Conclusion

As extensões de aplicativo definitivamente têm o impacto mais visível no iOS 8. Como 79% dos dispositivos já estão usando o iOS 8 (conforme medido pela App Store em 13 de abril de 2015), as extensões de aplicativos são recursos incríveis dos quais os aplicativos devem tirar proveito. Com a combinação das restrições da API e a forma de partilhar dados entre as extensões e a aplicação que as contém, parece que a Apple conseguiu resolver uma das maiores reclamações sobre a plataforma sem comprometer o seu modelo de segurança. Ainda não há como os aplicativos de terceiros compartilharem seus dados diretamente uns com os outros. Embora este seja um conceito muito novo, ele parece muito promissor.

Deixe uma resposta

O seu endereço de email não será publicado.