Comunicar e manter dados entre aplicativos com grupos de aplicativos

87

O iOS 8 revelou uma nova API ontem em relação aos grupos de aplicativos. Antes era meio confuso compartilhar dados e se comunicar entre aplicativos e acredito que é exatamente isso que o App Groups pretende corrigir.

Em meu aplicativo, habilitei os grupos de aplicativos e adicionei um novo grupo, mas simplesmente não consigo encontrar nenhuma documentação sobre como usá-lo. Referências de documentação e API apenas indicam como adicionar um grupo.

Então, o que os Grupos de aplicativos realmente pretendem fazer? Existe alguma documentação em algum lugar sobre como usá-lo?

Streem
fonte

Respostas:

83

Outro benefício dos grupos de aplicativos é a capacidade de compartilhar um NSUserDefaultsbanco de dados. Isso também funciona para extensões de aplicativo (widgets da central de notificação, teclados personalizados, etc).

Inicialize seu NSUserDefaultsobjeto assim em todos os aplicativos do grupo de aplicativos e eles compartilharão o banco de dados:

Objective-C:

[[NSUserDefaults alloc] initWithSuiteName:@"<group identifier>"];

Rápido:

NSUserDefaults(suiteName: "<group identifier>")

Lembre-se de que tudo do [NSUserDefaults standardUserDefaults]banco de dados para cada aplicativo não será transportado para esse banco de dados.

A documentação também fornece um exemplo correto (a partir do Beta 3).

E não se esqueça de sincronizar o banco de dados:

[yourDefaults synchronize];
Papai Noel
fonte
2
Funciona apenas no simulador (XCode 6 beta 5, iOS 8 beta 5)
iOS Dev
8
NOTA: Se você estiver usando isso com uma extensão iOS 8 (por exemplo, teclado), você precisará garantir que sua extensão tenha RequestsOpenAccess = YES em seu arquivo Info.plist.
Kiran Panesar
1
Eu fiz RequestsOpenAccess = YES e siga as instruções ainda não vai funcionar para mim no dispositivo e funciona bem no emulador, algo específico para o dispositivo?
MAC
O mesmo problema comigo, integrei a extensão de compartilhamento em meu aplicativo, ela funciona no simulador, mas não funciona no dispositivo real, adicionei o RequestOpenAccess = YES, mas não funciona, minha pergunta é stackoverflow.com/questions/30489894/ …
Ravi Ojha
3
@MikeRichards não tenho certeza, mas se bem me lembro, os grupos de aplicativos são prefixados com um id de equipe
Papai Noel
74

Compartilhamento de dados NSUserDefaults entre vários aplicativos

Para ter padrões compartilhados entre um aplicativo e uma extensão ou entre 2 aplicativos, você deve adicionar um Grupo de aplicativos em suas configurações usando as seguintes etapas:

  1. No Navegador do Projeto, clique no arquivo * .xcodeproj (deve estar no topo).
  2. À direita do Navegador do Projeto, procure Projeto e Alvos. Abaixo dos alvos, clique no seu alvo principal (deve ser a primeira coisa em Alvos).
  3. Na parte superior, clique na guia Capacidades.
  4. Na seção Grupos de aplicativos, clique no botão à direita para LIGAR os Grupos de aplicativos.
  5. Clique no botão + e adicione um Grupo de aplicativos denominado group.com.company.myApp .
  6. Vá para o mesmo local em seus outros aplicativos e este grupo deve estar disponível para seleção. Ative esse grupo para cada aplicativo que usará esses dados compartilhados.

Observação: se você for ao Portal do desenvolvedor da Apple (o site da Apple que mostra todos os seus certificados, identificadores, dispositivos e perfis de provisionamento) e acessar Identificadores> Grupos de aplicativos, deverá ver este novo grupo de aplicativos.

Para armazenar dados:

var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")!
userDefaults.setObject("user12345", forKey: "userId")
userDefaults.synchronize()

Para recuperar dados:

var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")
if let testUserId = userDefaults?.objectForKey("userId") as? String {
  print("User Id: \(testUserId)")
}
TenaciousJay
fonte
2
Obrigado! Demorou um pouco para pesquisar a documentação para descobrir como fazer isso e achei que outros gostariam de saber as etapas que tomei.
TenaciousJay
Obrigado pela descrição detalhada ...! precisamos criar algum certificado do Apple Developer Portal (o site da Apple que mostra todos os seus certificados, identificadores, dispositivos e perfis de provisionamento) para habilitar este grupo? mesmo como notificação push.?
Arbaz Shaikh
Quando você executa a etapa 5, deve adicionar o Grupo de aplicativos ao Portal do desenvolvedor da Apple, você não deve ir diretamente ao Portal do desenvolvedor para adicioná-lo. Depois de fazer a etapa 5, você pode ir ao portal e ver se ele deveria ter criado para você.
TenaciousJay
@TenaciousJay Excelente resposta. Apenas quero adicionar Se você deseja iniciar o aplicativo a partir do aplicativo func (aplicativo: UIApplication, openURL url: NSURL, opções: [String: AnyObject]) -> Bool
Taimur Ajmal
Ótima resposta. obrigado @TenaciousJay. Estou tentando recuperar uma variável e seu valor do AppB para o AppA, como faria isso? Por exemplo, se "riderCancelledRequest = true" no AppB, como eu recuperaria isso no AppA?
LizG
37

Grupos de aplicativos, de acordo com minha interpretação da documentação existente, são direcionados principalmente para extensões, mais especificamente, para widgets. Os widgets são seus próprios pacotes de aplicativos que coexistem com o seu aplicativo. Como eles são um aplicativo separado e, portanto, têm sua própria sandbox, você precisará usar grupos de aplicativos para compartilhar arquivos.

Depois de alguns greping de cabeçalho, acho que achei a API necessária, mas na verdade foi colocada como parte do iOS 7.

NSFileManagertem um método containerURLForSecurityApplicationGroupIdentifier:onde você pode passar o identificador que você criou ao ativar Grupos de aplicativos para seus aplicativos:

NSURL *containerURL = [[NSFileManager defaultManager] 
           containerURLForSecurityApplicationGroupIdentifier:@"group.com.company.app"];
Wayne Hartman
fonte
Obrigado, acredito que você esteja certo sobre extensibilidade. Estou um pouco mais duvidoso sobre este método iOS 7, parece muito estático para mim, o iOS 8 introduziu interações reais e comunicação entre aplicativos.
streem
@Justafinger Este método iOS 7 serve apenas para criar uma URL para gravar e ler dados entre os aplicativos compartilhados. Este método específico só é realmente útil (pelo que vejo até agora) para widgets, mas não para outras extensões.
Wayne Hartman
Bem, eu acredito que a Apple queria tornar isso mais fácil no iOS 8 sem ter que criar um contêiner programaticamente e compartilhar arquivos personalizados. A documentação afirma que você deve ser capaz de compartilhar dados usando NSUserDefault. Acho que estou perdendo alguma coisa, porque isso não está funcionando para mim.
streem
@Justafinger Eu também não consegui NSUserDefaultstrabalhar. Eu atribuo a bug até Beta 1.
Wayne Hartman
@WayneHartman Existe uma solução alternativa para o NSUserDefaultsbanco de dados. Veja minha resposta.
Papai Noel
6

Uma armadilha importante que descobri hoje é a seguinte:

Em muitos projetos, vi um único destino de aplicativo e com diferentes identificadores de pacote definidos para cada configuração desse destino. Aqui as coisas ficam complicadas. O que os desenvolvedores pretendiam era criar um aplicativo de depuração para a configuração de depuração e um aplicativo de produção para o destino de lançamento.

Se você fizer isso, os dois aplicativos compartilharão os mesmos NSUserDefaults quando forem configurados dessa forma

var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")
userDefaults!.setObject("user12345", forKey: "userId")
userDefaults!.synchronize()

Isso causa problemas em muitos lugares:

  1. Imagine que você definiu SIM para uma tecla quando uma tela de introdução de aplicativo especial foi mostrada ao usuário. O outro aplicativo agora também lerá SIM e não mostrará a introdução.
  2. Sim, alguns aplicativos também armazenam tokens oAuth em seus padrões de usuário. De qualquer forma ... Dependendo da implementação, o aplicativo reconhecerá que há um token e começará a recuperar os dados usando o token errado. A chance é alta de que isso falhe com erros estranhos.

A solução para este problema em geral é prefixar as chaves padrão com a configuração atual construída. Você pode detectar a configuração facilmente em tempo de execução, definindo diferentes identificadores de pacote para suas configurações. Em seguida, basta ler o identificador do pacote de NSBundle.mainBundle(). Se você tiver os mesmos identificadores de pacote, você precisa definir diferentes macros de pré-processador, como

#ifdef DEBUG
  NSString* configuration = @"debug";
#elif RELEASE
  NSString* configuration = @"release";
#endif

Em Swift será quase o mesmo:

#if DEBUG
  let configuration = "debug"
#elseif RELEASE
  let configuration = "release"
#endif
Blackjacx
fonte
8
Seus problemas existem porque você mistura todos os seus dados em UserDefaults compartilhados. Você deve usar NSUserDefaults.standardUserDefaults()para dados que não devem ser compartilhados.
Daniel
2

Armazenar

let shared: NSUserDefaults = NSUserDefaults(suiteName: "group.abcapp")!
shared.setObject("abc.png", forKey: "favEmoji")
shared.synchronize()
Hardik Thakkar
fonte