通过应用程序组在应用程序之间传递和保持数据

iOS 8昨天透露了一个关于应用程序组的新API。 之前分享数据和应用程序之间的通信是一种混乱,我相信这正是应用程序组旨在纠正的。

在我的应用程序中,我启用了应用程序组,并添加了一个新的组,但是我找不到任何有关如何使用它的文档。 文档和API参考仅说明如何添加组。

那么应用程序组真正打算做什么? 是否有任何文件的地方如何使用它?

应用程序组的另一个好处是可以共享一个NSUserDefaults数据库。 这也适用于扩展(通知中心小部件,自定义键盘等)。

在应用程序组的所有应用程序中像这样初始化你的NSUserDefaults对象,它们将共享数据库:

Objective-C的:

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

迅速:

 NSUserDefaults(suiteName: "<group identifier>") 

请记住,每个应用程序的[NSUserDefaults standardUserDefaults]数据库中的所有内容都不会传递到此数据库中。

文档也给出了一个正确的例子(从Beta 3开始)。

并且不要忘记同步数据库:

 [yourDefaults synchronize]; 

在多个应用程序之间共享NSUserDefaults数据

为了在应用程序和扩展程序之间或两个应用程序之间共享默认值,您必须使用以下步骤在设置中添加应用程序组:

  1. 在Project Navigator中点击* .xcodeproj文件(应该在顶部)。
  2. 在项目导航器的右侧查找项目和目标。 在目标下点击你的主要目标(应该是目标下的第一个目标)。
  3. 朝上方,点击能力标签。
  4. 在“应用程序组”部分中,单击右侧的开关将“应用程序组”打开。
  5. 点击+button,添加一个名为group.com.company.myApp的应用程序组。
  6. 转到其他应用程序中的相同位置,现在可以select此组。 为每个将使用此共享数据的应用启用此组。

注意:如果您转到Apple Developer Portal(显示所有证书,标识符,设备和configuration文件的Apple网站)并转到标识符>应用程序组,您应该看到这个新的应用程序组。

存储数据:

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

要检索数据:

 var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp") if let testUserId = userDefaults?.objectForKey("userId") as? String { print("User Id: \(testUserId)") } 

根据我对现有文档的解释,应用程序组主要针对扩展,更具体地说,针对小部件。 小部件是他们自己的应用程序包,与您的应用程序共存。 由于它们是独立的应用程序,因此拥有自己的沙箱,因此您需要使用应用程序组来共享文件。

在一些标题grep'ing后,我想我find了所需的API,但实际上是作为iOS 7的一部分。

NSFileManager在其上有一个方法containerURLForSecurityApplicationGroupIdentifier:在开启应用程序的App Groups时,你可以在其中传入你创build的标识符:

 NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.company.app"]; 

我今天采用的一个重要陷阱如下:

在许多项目中,我看到了一个应用程序目标,并为该目标的每个configuration设置了不同的包标识符。 这里事情变得混乱。 开发人员的目的是为debuggingconfiguration创builddebugging应用程序,并为发布目标创build一个生产应用程序。

如果你这样做,两个应用程序将分享相同的NSUserDefaults,如此设置

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

这在许多地方引起问题:

  1. 想象一下,当一个特殊的app-intro屏幕已经显示给用户时,你为一个按键设置了YES。 另一个应用程序现在也读取YES,不显示介绍。
  2. 是的,某些应用程序还会将oAuth令牌存储在其用户默认值中。 无论如何…根据实施,应用程序将认识到有一个令牌,并开始使用错误的令牌检索数据。 机会很高,这将失败,奇怪的错误。

一般来说,解决这个问题的方法是在默认键的前面加上当前的configuration。 您可以在运行时通过为您的configuration设置不同的包标识符来轻松检测到configuration。 然后,只需从NSBundle.mainBundle()读取包标识符。 如果你有相同的包标识符,你需要设置不同的预处理器macros

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

在Swift中,它看起来几乎是一样的:

 #if DEBUG let configuration = "debug" #elseif RELEASE let configuration = "release" #endif 

储藏

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