使用应用程序组在应用程序之间通信和持久化数据


85

iOS 8昨天披露了一个与应用程序组有关的新API。在应用之间共享数据并进行通信之前,情况有点混乱,我相信这正是应用组要纠正的问题。

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

那么App Group真正打算做什么?是否有任何有关如何使用它的文档?

Answers:


81

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

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

目标C:

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

迅速:

NSUserDefaults(suiteName: "<group identifier>")

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

文档还提供了正确的示例(自Beta 3开始)。

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

[yourDefaults synchronize];

2
仅适用于模拟器(XCode 6 beta 5,iOS 8 beta 5)
iOS Dev

8
注意:如果将此功能与iOS 8扩展程序(例如键盘)一起使用,则需要确保其扩展程序的Info.plist文件中具有RequestsOpenAccess = YES。
Kiran Panesar

1
我没有执行RequestsOpenAccess = YES并按照说明进行操作,但是它在Device上对我来说不起作用,而在Emulator上也可以正常工作,对于设备而言,它有什么用吗?
MAC

我遇到了同样的问题,我在我的应用程序中集成了共享扩展,它在模拟器上工作,但在实际设备上不工作,我添加了RequestOpenAccess = YES,但它不起作用,我的问题是stackoverflow.com/questions/30489894/ …
拉维·奥贾

3
@MikeRichards不确定,但是如果我没记错的话,应用组带有团队ID的前缀
圣诞老人,

74

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

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

  1. 在项目浏览器中,单击* .xcodeproj文件(应位于顶部)。
  2. 在“项目浏览器”的右侧,找到“项目和目标”。在目标下,单击您的主要目标(应该是“目标”下的第一件事)。
  3. 在顶部,单击“功能”选项卡。
  4. 在“应用程序组”部分中,单击右侧的开关以打开“应用程序组”。
  5. 单击+按钮,然后添加一个名为group.com.company.myApp的应用程序组。
  6. 转到其他应用程序中的同一位置,现在应该可以选择该组。为每个将使用此共享数据的应用程序打开此组。

注意:如果您访问Apple Developer Portal(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)")
}

2
谢谢!花了一些时间在文档中进行搜索以弄清楚如何做到这一点,我认为其他人可能会喜欢我采取的步骤。
TenaciousJay

感谢您的详细说明...!我们是否需要从Apple Developer Portal(Apple网站显示您的所有证书,标识符,设备和供应配置文件)创建任何证书来启用该组?像推送通知一样。
Arbaz Shaikh's

当您执行第5步时,应将应用程序组添加到Apple Developer Portal,而不必直接转到Developer Portal进行添加。完成第5步后,您可以转至门户,并看到它应该已经为您创建了。
TenaciousJay

@TenaciousJay很棒的答案。只想添加如果您想从func应用程序启动应用程序(应用程序:UIApplication,openURL url:NSURL,选项:[String:AnyObject])-> Bool
Taimur Ajmal,

好答案。谢谢@TenaciousJay。我正在尝试将变量及其值从AppB检索到AppA中,该怎么办?例如,如果AppB中的“ riderCancelledRequest = true”,我将如何在AppA中检索它?
LizG

37

根据我对现有文档的解释,应用程序组主要针对扩展,尤其是窗口小部件。小部件是与应用程序共存的自己的应用程序包。由于它们是单独的应用程序,因此具有自己的沙箱,因此您需要使用应用程序组共享文件。

经过一些头文件复制后,我认为我找到了所需的API,但实际上是作为iOS 7的一部分放入的。

NSFileManager上面有一个方法containerURLForSecurityApplicationGroupIdentifier:,您可以在其中为打开应用程序的应用程序组时传入创建的标识符:

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

谢谢,我相信您在扩展性方面是对的。对于这种iOS 7方法,我有些怀疑,对我来说,这似乎很静态,iOS 8引入了应用程序之间的真实交互和通信。
streem

@Justafinger此iOS 7方法仅用于创建URL,以在共享应用程序之间写入和读取数据。这个特殊的方法仅对小部件才真正有用(从我到目前为止所看到的情况),而对其他扩展则没有帮助。
韦恩·哈特曼2014年

好吧,我相信Apple希望在iOS 8中简化此过程,而不必以编程方式创建容器并共享自定义文件。文档指出,您应该能够使用NSUserDefault共享数据。我想我缺少了一些东西,因为那对我不起作用。
streem 2014年

@Justafinger我也无法NSUserDefaults上班。我总结了Beta 1错误。
韦恩·哈特曼2014年

@WayneHartmanNSUserDefaults数据库没有解决方法。看我的答案。
圣诞老人2014年

6

我今天探讨的一个重要陷阱是:

在许多项目中,我看到了一个应用程序目标,并为该目标的每种配置设置了不同的包标识符。事情变得混乱了。开发人员打算为调试配置创建调试应用程序,为发布目标创建生产应用程序。

如果这样做,则两个应用程序在设置时将共享相同的NSUserDefaults

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

这会在许多地方引起问题:

  1. 想象一下,当向用户显示特殊的应用程序简介屏幕时,您将键设置为“是”。另一个应用现在也会显示“是”,并且不显示简介。
  2. 是的,某些应用程序还在其用户默认设置中存储了oAuth令牌。无论如何...根据实现的不同,应用程序将识别出存在令牌,并开始使用错误的令牌检索数据。这很可能会因奇怪的错误而失败。

通常,解决此问题的方法是在默认键之前添加当前构建的配置。您可以通过为配置设置不同的捆绑标识符来在运行时轻松检测配置。然后只需从中读取包标识符NSBundle.mainBundle()。如果您具有相同的包标识符,则需要设置不同的预处理器宏,例如

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

在Swift中,外观几乎相同:

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

8
存在问题是因为您将所有数据混合在一个共享的UserDefaults中。您应该使用NSUserDefaults.standardUserDefaults()不应共享的数据。
丹尼尔(Daniel)

2

储藏

let shared: NSUserDefaults = NSUserDefaults(suiteName: "group.abcapp")!
shared.setObject("abc.png", forKey: "favEmoji")
shared.synchronize()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.