Tudo o que você precisa saber sobre as extensões de aplicativos para iOS



As extensões de aplicativo apareceram no iOS 8 e tornaram o sistema mais flexível, poderoso e acessível para os usuários. Os aplicativos podem ser exibidos como um widget na Central de Notificações, oferecer seus filtros para fotos em Fotos, exibir um novo teclado do sistema e muito mais. Ao mesmo tempo, a segurança dos dados do usuário e do sistema foi preservada. Os recursos do trabalho das extensões de aplicativo serão discutidos abaixo.

A Apple sempre procurou isolar cuidadosamente os aplicativos um do outro. Essa é a melhor maneira de garantir a segurança dos usuários e proteger seus dados. Cada aplicativo recebe um local separado no sistema de arquivos com acesso limitado. As extensões de aplicativo tornaram possível interagir com o aplicativo sem iniciá-lo ou exibi-lo na tela. Assim, parte de sua funcionalidade estará disponível para os usuários quando eles interagirem com outros aplicativos ou o sistema.

As extensões de aplicativo são arquivos executáveis ​​executados independentemente do aplicativo que contém - aplicativo que contém . Sozinhos, eles não podem ser publicados na App Store, apenas com o aplicativo que contém. Todas as extensões de aplicativo executam uma tarefa específica e estão vinculadas a apenas uma área do iOS, dependendo do tipo. Por exemplo: as extensões de teclado personalizadas destinam-se a substituir o teclado padrão e as extensões de edição de fotos são para editar fotos em fotos. Atualmente, existem 25 tipos de extensões de aplicativo.

Life Extension App Extension


O aplicativo que o usuário usa para iniciar a extensão de aplicativo é chamado de aplicativo host . O aplicativo host inicia o ciclo de vida da extensão de aplicativo, enviando uma solicitação em resposta a uma ação do usuário:



  • O usuário seleciona a extensão de aplicativo por meio do aplicativo host.
  • O aplicativo host envia uma solicitação de extensão de aplicativo.
  • O iOS inicia a extensão de aplicativo no contexto do aplicativo host e estabelece um canal de comunicação entre eles.
  • O usuário executa uma ação na extensão de aplicativo.
  • A extensão de aplicativo conclui a solicitação do aplicativo host, executando uma tarefa ou inicia um processo em segundo plano para concluí-la; após a conclusão da tarefa, o resultado pode ser retornado ao aplicativo host.
  • Depois que a extensão de aplicativo executa seu código, o sistema encerra essa extensão de aplicativo.

Por exemplo, ao compartilhar uma foto do Fotos usando a Extensão de compartilhamento do Facebook, o Facebook é o aplicativo que contém e o Fotos é o aplicativo host. Nesse caso, o Fotos inicia o ciclo de vida da extensão de compartilhamento do Facebook quando o usuário o seleciona no menu Compartilhar:



Interação com a extensão de aplicativo




  • Contendo App - App Host
    Não interajam um com o outro.
  • Extensão de aplicativo - aplicativo host
    Interaja usando o IPC .
  • Extensão de aplicativo - contendo aplicativo
    Interação indireta. Os grupos de aplicativos são usados ​​para troca de dados e o Embedded Frameworks é usado para código geral. Você pode iniciar o aplicativo que contém a extensão de aplicativo usando os esquemas de URL .

Código genérico: estruturas dinâmicas


Se o aplicativo que contém e extensão de aplicativo usar o mesmo código, ele deverá ser colocado em uma estrutura dinâmica.

Por exemplo, uma extensão de edição de fotos pode estar associada a um aplicativo de edição de fotos personalizado que usa alguns filtros do aplicativo que contém. Uma boa solução seria criar uma estrutura dinâmica para esses filtros.

Para fazer isso, adicione um novo destino e selecione o Cocoa Touch Framework :



Especifique um nome (por exemplo, ImageFilters ) e, no painel do navegador, você pode ver uma nova pasta com o nome da estrutura criada:

Você precisa garantir que a estrutura não use APIs que não estão disponíveis para as extensões de aplicativo:

  • Compartilhado do UIApplication.
  • APIs marcadas com macros de inacessibilidade.
  • Câmera e microfone (exceto o iMessage Extension).
  • Execução de longas tarefas em segundo plano (os recursos desta restrição variam dependendo do tipo de extensão de aplicativo).
  • Receba dados usando o AirDrop.

O uso de qualquer uma dessas listas nas Extensões de Aplicativo leva à sua rejeição quando publicado na App Store.

Nas configurações da estrutura em Geral, marque a caixa ao lado de "Permitir apenas a API de extensão de aplicativo" :



No código da estrutura, todas as classes, métodos e propriedades usadas no Containing App e App Extensions devem ser public . Onde quer que você precise usar a estrutura, import :

 import ImageFilters 

Troca de dados: grupos de aplicativos


O aplicativo que contém e a extensão do aplicativo têm suas próprias seções limitadas do sistema de arquivos e somente eles têm acesso a eles. Para que o aplicativo que contém o aplicativo e a extensão do aplicativo tenha um contêiner comum com acesso de leitura e gravação, você precisa criar um grupo de aplicativos para eles.

O Grupo de aplicativos é criado no Apple Developer Portal :



No canto superior direito, clique em "+", na janela exibida, insira os dados necessários:



Próximo Continuar -> Registrar -> Concluído .

Nas configurações do aplicativo que contém, vá para a guia Recursos , ative Grupos de aplicativos e selecione o grupo criado:



Da mesma forma para a extensão de aplicativo:



Agora, o aplicativo que contém e a extensão de aplicativo compartilham um contêiner. Em seguida, falaremos sobre como ler e escrever nele.

UserDefaults


Para trocar uma pequena quantidade de dados, é conveniente usar UserDefaults , basta especificar o nome do Grupo de Aplicativos:

 let sharedDefaults = UserDefaults(suiteName: "group.com.maxial.onemoreapp") 

NSFileCoordinator e NSFilePresenter


Para big data, o NSFileCoordinator é mais adequado para garantir consistência de leitura / gravação. Isso evitará a corrupção de dados, pois existe a possibilidade de que vários processos possam acessá-los simultaneamente.

A URL do contêiner compartilhado é obtida da seguinte maneira:

 let sharedUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.maxial.onemoreapp") 

Registro:

 fileCoordinator.coordinate(writingItemAt: sharedUrl, options: [], error: nil) { [unowned self] newUrl in do { let data = try NSKeyedArchiver.archivedData(withRootObject: self.object, requiringSecureCoding: false) try data.write(to: newUrl, options: .atomic) } catch { print(error) } } 

Leitura:

 fileCoordinator.coordinate(readingItemAt: sharedUrl, options: [], error: nil) { newUrl in do { let data = try Data(contentsOf: newUrl) if let object = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSString.self, from: data) as String? { self.object = object } } catch { print(error) } } 

Vale a pena considerar que o NSFileCoordinator funciona de forma síncrona. Enquanto alguns arquivos serão ocupados por algum processo, outros terão que esperar a liberação.

Se você deseja que a extensão de aplicativo saiba quando o aplicativo que contém o aplicativo altera o estado dos dados, o NSFilePresenter usado. Este é um protocolo cuja implementação pode ser assim:

 extension TodayViewController: NSFilePresenter { var presentedItemURL: URL? { let sharedUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.maxial.onemoreapp") return sharedUrl?.appendingPathComponent("Items") } var presentedItemOperationQueue: OperationQueue { return .main } func presentedItemDidChange() { } } 

A propriedade presentedItemOperationQueue retorna uma fila que é usada para retornos de chamada ao alterar arquivos. O método presentedItemDidChange() é chamado quando um processo, neste caso, o aplicativo que contém, altera o conteúdo dos dados. Se as alterações tiverem sido feitas diretamente usando chamadas de gravação de baixo nível, o presentedItemDidChange() não presentedItemDidChange() chamado. Somente as alterações usando o NSFileCoordinator .

Ao inicializar um objeto NSFileCoordinator , NSFileCoordinator recomendável que você transmita o objeto NSFilePresenter , especialmente se ele iniciar qualquer operação de arquivo:

 let fileCoordinator = NSFileCoordinator(filePresenter: self) 

Caso contrário, o objeto NSFilePresenter receberá notificações sobre essas operações, o que pode levar a um conflito ao trabalhar no mesmo encadeamento.

Para começar a monitorar o estado dos dados, você precisa chamar o addFilePresenter(_:) com o objeto correspondente:

 NSFileCoordinator.addFilePresenter(self) 

Quaisquer objetos NSFileCoordinator criados posteriormente NSFileCoordinator automaticamente sobre esse objeto NSFilePresenter e notificarão sobre alterações em seu diretório.

Para parar de monitorar o status dos dados, use removeFilePresenter(_:) :

 NSFileCoordinator.removeFilePresenter(self) 

Dados principais


Para compartilhamento de dados, você pode usar SQLite e, consequentemente, Core Data. Eles podem gerenciar processos que funcionam com dados compartilhados. Para configurar os Dados Principais para serem compartilhados entre o Aplicativo Contendo e a Extensão do Aplicativo, crie uma subclasse de NSPersistentContainer e substitua o método defaultDirectoryURL , que deve retornar o endereço do armazenamento de dados:

 class SharedPersistentContainer: NSPersistentContainer { override open class func defaultDirectoryURL() -> URL { var storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.maxial.onemoreapp") storeURL = storeURL?.appendingPathComponent("OneMoreApp.sqlite") return storeURL! } } 

No AppDelegate altere a propriedade persistentContainer . Ele é criado automaticamente se, ao criar um projeto, marque a caixa de seleção Usar dados principais . Agora retornaremos um objeto da classe SharedPersistentContainer :

 lazy var persistentContainer: NSPersistentContainer = { let container = SharedPersistentContainer(name: "OneMoreApp") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }() 

Tudo o que resta é adicionar .xcdatamodeld à extensão de aplicativo. Selecione o arquivo .xcdatamodeld no painel do navegador. No Inspetor de arquivos , na seção Associação de destino , marque a caixa ao lado de Extensão de aplicativo:



Portanto, o aplicativo que contém e a extensão de aplicativo poderão ler e gravar dados no mesmo armazenamento e usar o mesmo modelo.

Iniciando o aplicativo que contém a extensão de aplicativo


Quando o aplicativo host envia uma solicitação de extensão de aplicativo, ele fornece um extensionContext . Este objeto possui um método open(_:completionHandler:) , com o qual você pode abrir o aplicativo que contém. No entanto, esse método não está disponível para todos os tipos de extensão de aplicativo. No iOS, ele é suportado pelo Today Extension e pelo iMessage Extension. A extensão iMessage só pode usá-lo para abrir o aplicativo que contém. Se o Today Extension abrir outro aplicativo, uma verificação adicional pode ser necessária para o envio à App Store.

Para abrir o aplicativo a partir da extensão de aplicativo, você precisa definir o esquema de URL no aplicativo que contém:



Em seguida, chame o método open(_:completionHandler:) com este diagrama na extensão de aplicativo:

 guard let url = URL(string: "OneMoreAppUrl://") else { return } extensionContext?.open(url, completionHandler: nil) 

Para os tipos de extensões de aplicativo que chamam o método open(_:completionHandler:) não está disponível, também existe uma maneira. Mas existe a possibilidade de o aplicativo ser rejeitado ao fazer check-in na App Store. A essência do método é UIResponder a cadeia de objetos UIResponder até que haja um UIApplication que aceite a chamada openURL :

 guard let url = URL(string: "OneMoreAppUrl://") else { return } let selectorOpenURL = sel_registerName("openURL:") var responder: UIResponder? = self while responder != nil { if responder?.responds(to: selectorOpenURL) == true { responder?.perform(selectorOpenURL, with: url) } responder = responder?.next } 

Extensões futuras de aplicativos


As extensões de aplicativo trouxeram muito para o desenvolvimento do iOS. Gradualmente, mais tipos de extensões de aplicativo aparecem e seus recursos estão se desenvolvendo. Por exemplo, com o lançamento do iOS 12 SDK, agora você pode interagir com a área de conteúdo nas notificações, que estão ausentes há tanto tempo.

Assim, a Apple continua a desenvolver essa ferramenta, que inspira otimismo em relação ao seu futuro.

Links úteis:

Documentação oficial
Compartilhando dados entre aplicativos iOS e extensões de aplicativo
Dicas de desenvolvimento de extensão de aplicativo para iOS 8

Source: https://habr.com/ru/post/pt441890/


All Articles