【问题标题】:Communicating and persisting data between apps with App Groups使用应用组在应用之间通信和保存数据
【发布时间】:2014-07-23 19:24:48
【问题描述】:

iOS 8 昨天发布了一个关于 App Groups 的新 API。以前在应用程序之间共享数据和通信有点混乱,我相信这正是应用程序组想要纠正的。

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

那么应用组的真正意图是什么?有没有关于如何使用它的文档?

【问题讨论】:

    标签: ios objective-c ios8 ios-app-extension


    【解决方案1】:

    App Groups 的另一个好处是能够共享NSUserDefaults 数据库。这也适用于应用扩展(通知中心小部件、自定义键盘等)。

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

    目标-C:

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

    斯威夫特:

    NSUserDefaults(suiteName: "<group identifier>")
    

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

    documentation 也提供了一个正确的示例(从 Beta 3 开始)。

    别忘了同步数据库:

    [yourDefaults synchronize];
    

    【讨论】:

    • 仅适用于模拟器(XCode 6 beta 5,iOS 8 beta 5)
    • 注意:如果您将其与 iOS 8 扩展程序(例如键盘)一起使用,您需要确保您的扩展程序在其 Info.plist 文件中有 RequestsOpenAccess=YES。
    • 我做了 RequestsOpenAccess=YES 并按照说明进行操作,但它在设备上对我不起作用,在模拟器上工作正常,任何特定于设备的东西?
    • 和我一样的问题,我在我的应用程序中集成了共享扩展,它可以在模拟器上运行,但不能在真实设备上运行,我添加了 RequestOpenAccess =YES 但它不起作用,我的问题是stackoverflow.com/questions/30489894/…
    • @MikeRichards 不确定,但如果我没记错的话,应用程序组的前缀是团队 ID
    【解决方案2】:

    在多个应用之间共享 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)")
    }
    

    【讨论】:

    • 谢谢!花了一些时间搜索文档来弄清楚如何做到这一点,我认为其他人可能会欣赏我采取的步骤。
    • 感谢您的详细描述...!我们是否需要从 Apple Developer Portal(显示您的所有证书、标识符、设备和配置文件的 Apple 网站)创建任何证书才能启用该组?和推送通知一样吗?
    • 当您执行第 5 步时,它应该将 App Group 添加到 Apple Developer Portal,您不必直接前往 Developer Portal 添加它。完成第 5 步后,您可以转到门户并查看它应该已经为您创建了它。
    • @TenaciousJay 出色的答案。只想添加如果你想从func应用程序启动应用程序(app:UIApplication,openURL url:NSURL,options:[String:AnyObject])-> Bool
    • 很好的答案。谢谢@TenaciousJay。我正在尝试将变量及其值从 AppB 检索到 AppA 中,我该怎么做?例如,如果 AppB 中的“riderCancelledRequest = true”,我将如何在 AppA 中检索它?
    【解决方案3】:

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

    经过一些标头 grep'ing,我想我找到了所需的 API,但实际上是作为 iOS 7 的一部分放入的。

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

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

    【讨论】:

    • 谢谢,我相信您对可扩展性的看法是正确的。我对 iOS 7 的这种方法有点怀疑,对我来说它似乎很静态,iOS 8 引入了应用程序之间的真实交互和通信。
    • @Justafinger 这个 iOS 7 方法仅用于创建 URL 以在共享应用程序之间写入和读取数据。这种特殊方法仅对小部件真正有用(从我目前所见),而不是其他扩展。
    • 嗯,我相信 Apple 希望在 iOS 8 中让这更容易,而无需以编程方式创建容器并共享自定义文件。 Documentation 声明您应该能够使用 NSUserDefault 共享数据。我想我错过了一些东西,因为那对我不起作用。
    • @Justafinger 我也无法让NSUserDefaults 工作。我认为最多是 Beta 1 错误。
    • @WayneHartman NSUserDefaults 数据库有一个解决方法。看我的回答。
    【解决方案4】:

    我今天发现的一个重要陷阱如下:

    在许多项目中,我看到了一个应用程序目标,并为该目标的每个配置设置了不同的包标识符。这里事情变得一团糟。开发人员的意图是为调试配置创建一个调试应用程序,为发布目标创建一个生产应用程序。

    如果您这样做,两个应用程序将在这样设置时共享相同的 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
    

    【讨论】:

    • 您的问题存在是因为您将所有数据混合在一个共享的 UserDefaults 中。对于不应共享的数据,您应该使用 NSUserDefaults.standardUserDefaults()
    【解决方案5】:

    存储

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

    【讨论】:

      【解决方案6】:

      App Group 允许您在来自同一开发团队(帐户)的不同进程(应用程序、扩展...)之间共享数据(用户默认值、文件、CoreData(管理模型图)、POSIX 锁)。它创建了一个shared container whit id,它应该从group. 开始,用于保存/缓存数据,您可以访问思想 url 和 IPC

      App Group 与 UserDefaults 一起使用

      1. 为您将获得访问权限的所有目标(应用程序、扩展程序...)添加具有相同 ID 的 App Group 功能

      创建后,您可以在Apple Developer 上查看它。证书、ID 和配置文件 -> 标识符 -> 所有组

      1. 从 Application1 写入
      let defaults = UserDefaults(suiteName: "group.goforit")
      defaults?.setValue("Hello World!", forKey: "key1")
      
      1. 从 Application2 读取
      let defaults = UserDefaults(suiteName: "group.goforit")
      let result = defaults?.value(forKey: "key1") //Hello World!
      

      shared container 根位置单个 URL。

      let rootURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.goforit")
      
      //file:///Users/alex/Library/Developer/CoreSimulator/Devices/1AF41817-FE2E-485A-A592-12C39C0B0141/data/Containers/Shared/AppGroup/DC14D43F-2C2C-4771-83BE-64A9F54BD2E1/
      

      【讨论】:

      • 关于如何使用应用程序组和用户默认设置的简短但非常有用的解释@yoAlex5
      猜你喜欢
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      • 2018-09-13
      • 2022-11-06
      • 2012-11-10
      • 2019-10-30
      • 2018-03-29
      • 1970-01-01
      相关资源
      最近更新 更多