Comunicación y persistencia de datos entre aplicaciones con grupos de aplicaciones

85

iOS 8 reveló ayer una nueva API sobre grupos de aplicaciones. Antes era un poco complicado compartir datos y comunicarse entre aplicaciones y creo que eso es precisamente lo que los grupos de aplicaciones intentan corregir.

En mi aplicación, habilité los grupos de aplicaciones y agregué un grupo nuevo, pero no puedo encontrar ninguna documentación sobre cómo usarlo. La documentación y las referencias de API solo indican cómo agregar un grupo.

Entonces, ¿qué es lo que realmente pretenden hacer los grupos de aplicaciones? ¿Hay alguna documentación en alguna parte sobre cómo usarlo?

streem
fuente

Respuestas:

81

Otro beneficio de los grupos de aplicaciones es la capacidad de compartir una NSUserDefaultsbase de datos. Esto también funciona para las extensiones de aplicaciones (widgets del centro de notificaciones, teclados personalizados, etc.).

Inicialice su NSUserDefaultsobjeto de esta manera en todas las aplicaciones del grupo de aplicaciones y compartirán la base de datos:

C objetivo:

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

Rápido:

NSUserDefaults(suiteName: "<group identifier>")

Tenga en cuenta que todo lo de la [NSUserDefaults standardUserDefaults]base de datos para cada aplicación no se transferirá a esta base de datos.

La documentación también ofrece un ejemplo correcto (a partir de Beta 3).

Y no olvide sincronizar la base de datos:

[yourDefaults synchronize];
Papá Noel
fuente
2
Funciona solo en el simulador (XCode 6 beta 5, iOS 8 beta 5)
iOS Dev
8
NOTA: Si está usando esto con una extensión de iOS 8 (por ejemplo, un teclado), deberá asegurarse de que su extensión tenga RequestsOpenAccess = YES en su archivo Info.plist.
Kiran Panesar
1
Hice RequestsOpenAccess = YES y sigo las instrucciones, pero todavía no me funciona en el dispositivo y funciona bien en el emulador, ¿algo específico para el dispositivo?
MAC
El mismo problema conmigo, he integrado la extensión para compartir en mi aplicación, funciona en el simulador, pero no en el dispositivo real, he agregado RequestOpenAccess = YES pero no funciona, mi pregunta es stackoverflow.com/questions/30489894/ …
Ravi Ojha
3
@MikeRichards no estoy seguro, pero si recuerdo correctamente, los grupos de aplicaciones tienen como prefijo una identificación de equipo
Santa Claus
74

Compartir datos de NSUserDefaults entre varias aplicaciones

Para tener valores predeterminados compartidos entre una aplicación y una extensión o entre 2 aplicaciones, debe agregar un Grupo de aplicaciones en su configuración mediante los siguientes pasos:

  1. En el Navegador de proyectos, haga clic en el archivo * .xcodeproj (debería estar en la parte superior).
  2. A la derecha del Navegador de proyectos, busque Proyecto y Objetivos. Debajo de los objetivos, haga clic en su objetivo principal (debería ser lo primero en Objetivos).
  3. Hacia la parte superior, haga clic en la pestaña Capacidades.
  4. En la sección Grupos de aplicaciones, haga clic en el interruptor a la derecha para activar los Grupos de aplicaciones.
  5. Haga clic en el botón + y agregue un grupo de aplicaciones llamado group.com.company.myApp .
  6. Vaya al mismo lugar en sus otras aplicaciones y este grupo ahora debería estar disponible para seleccionar. Active este grupo para cada aplicación que usará estos datos compartidos.

Nota: Si va al Portal de desarrolladores de Apple (el sitio web de Apple que muestra todos sus Certificados, Identificadores, Dispositivos y Perfiles de aprovisionamiento) y va a Identificadores> Grupos de aplicaciones, debería ver este nuevo Grupo de aplicaciones.

Para almacenar datos:

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

Para recuperar datos:

var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")
if let testUserId = userDefaults?.objectForKey("userId") as? String {
  print("User Id: \(testUserId)")
}
TenaciousJay
fuente
2
¡Gracias! Me tomó un poco de búsqueda en la documentación para descubrir cómo hacer esto y pensé que otros podrían apreciar los pasos que tomé.
TenaciousJay
¡Gracias por la descripción detallada ...! ¿Necesitamos crear algún certificado desde Apple Developer Portal (el sitio web de Apple que muestra todos sus Certificados, Identificadores, Dispositivos y Perfiles de Aprovisionamiento) para habilitar este grupo? igual que la notificación Push.?
Arbaz Shaikh
Cuando realice el paso 5, debería agregar el Grupo de aplicaciones al Portal de desarrolladores de Apple, no debería tener que ir directamente al Portal de desarrolladores para agregarlo. Después de realizar el paso 5, puede ir al portal y ver que debería haberlo creado para usted.
TenaciousJay
@TenaciousJay Excelente respuesta. Solo quiero agregar Si desea iniciar la aplicación desde la aplicación func (aplicación: UIApplication, url openURL: NSURL, opciones: [String: AnyObject]) -> Bool
Taimur Ajmal
gran respuesta. gracias @TenaciousJay. Estoy tratando de recuperar una variable y su valor de AppB en AppA, ¿cómo haría esto? Por ejemplo, si "riderCancelledRequest = true" en AppB, ¿cómo puedo recuperarlo en AppA?
LizG
37

Los grupos de aplicaciones, según mi interpretación de la documentación existente, están destinados principalmente a extensiones, más específicamente, a widgets. Los widgets son su propio paquete de aplicaciones que coexisten con su aplicación. Dado que son una aplicación separada y, por lo tanto, tienen su propia caja de arena, deberá usar Grupos de aplicaciones para compartir archivos.

Después de algunas grep'ing de encabezados, creo que encontré la API necesaria, pero en realidad se instaló como parte de iOS 7.

NSFileManagertiene un método en el que containerURLForSecurityApplicationGroupIdentifier:puede pasar el identificador que creó al activar Grupos de aplicaciones para sus aplicaciones:

NSURL *containerURL = [[NSFileManager defaultManager] 
           containerURLForSecurityApplicationGroupIdentifier:@"group.com.company.app"];
Wayne Hartman
fuente
Gracias, creo que tienes razón sobre la extensibilidad. Tengo un poco más de dudas acerca de este método de iOS 7, me parece bastante estático, iOS 8 introdujo interacciones reales y comunicación entre aplicaciones.
Calle
@Justafinger Este método de iOS 7 es solo para crear una URL para escribir y leer datos entre las aplicaciones compartidas. Este método en particular solo es realmente útil (por lo que veo hasta ahora) para widgets, pero no para otras extensiones.
Wayne Hartman
Bueno, creo que Apple quería hacer esto más fácil en iOS 8 sin tener que crear un contenedor mediante programación y compartir archivos personalizados. La documentación indica que debería poder compartir datos mediante NSUserDefault. Supongo que me falta algo, porque eso no me funciona.
streem
@Justafinger Yo tampoco he podido ir NSUserDefaultsa trabajar. Me refiero al error Beta 1.
Wayne Hartman
@WayneHartman Hay una solución para la NSUserDefaultsbase de datos. Mira mi respuesta.
Santa Claus
6

Una trampa importante que aproveché hoy es la siguiente:

En muchos proyectos vi un solo objetivo de aplicación y con diferentes identificadores de paquete establecidos para cada configuración de ese objetivo. Aquí las cosas se complican. Lo que pretendían los desarrolladores era crear una aplicación de depuración para la configuración de depuración y una aplicación de producción para el objetivo de lanzamiento.

Si lo hace, ambas aplicaciones compartirán los mismos NSUserDefaults cuando estén configuradas así

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

Esto causa problemas en muchos lugares:

  1. Imagine que establece SÍ para una tecla cuando se le muestra al usuario una pantalla de introducción de la aplicación especial. La otra aplicación ahora también leerá SÍ y no mostrará la introducción.
  2. Sí, algunas aplicaciones también almacenan tokens de oAuth en sus valores predeterminados de usuario. De todos modos ... Dependiendo de la implementación, la aplicación reconocerá que hay un token y comenzará a recuperar datos usando el token incorrecto. Es muy probable que esto falle con errores extraños.

La solución a este problema en general es prefijar las claves predeterminadas con la configuración actual construida. Puede detectar la configuración fácilmente en tiempo de ejecución estableciendo diferentes identificadores de paquete para sus configuraciones. Luego, lea el identificador de paquete de NSBundle.mainBundle(). Si tiene los mismos identificadores de paquete, debe configurar diferentes macros de preprocesador como

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

En Swift se verá casi igual:

#if DEBUG
  let configuration = "debug"
#elseif RELEASE
  let configuration = "release"
#endif
blackjacx
fuente
8
Sus problemas existen porque mezcla todos sus datos en un UserDefaults compartido. Debe usar NSUserDefaults.standardUserDefaults()para datos que no deben compartirse.
Daniel
2

Para almacenar

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