在 macOS 上会遇到一个问题:不同进程之间共享 NSUserDefaults 的数据。
NSUserDefaults 里的数据本质上就是一个设置 .plist 文件。
通常遇到这个问题的场景是:自己家的一组应用想要共享一份儿 NSUserDefaults 数据。
解决思路利用 AppGroup 机制,如果应用在沙盒状态下需要在 project -> target -> Entitlement -> AppGroup 这里打开 AppGroup 设置,然后配置 AppGroup 的 ID.
这个解决方案是的本质其实为同一个开发 team 开发的多个 app 设置了一个 group containers,让他们共享 group containers 的数据,给这些 app 提供额外的进程间通信机制。可以在 ~/Library/Group Containers/ 这儿看到这个 Group Containers 的内容。
我们的共享 NSUserDefauts 即是基于此技术支持的(如何配置 AppGroup 看后续说明)
* NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"DZQ5YNVEU2.com.frank”];
* [userDefaults setObject:@1 forKey:@"open"];
initWithSuiteName 的使用场景
- You can use this method when developing an app suite, to share preferences or other data among the apps,
- When developing an app extension, to share preferences or other data between the extension and its containing app.
然后我们去共享的 ~/Library/Group Containers/DZQ5YNVEU2.com.frank/Library/Preferences/DZQ5YNVEU2.com.frank.plist 下看,发现已经写进去了拿到共享的 userDefaults 文件
在另外一个配置了同样的 AppGroup ID 的 application 中读取 key 值 open ,能读到刚刚的设置。说明可以进行共享 NSUserDefaults。
可以通过 NSFileManager 的 API - NSURL *url = [fileman containerURLForSecurityApplicationGroupIdentifier:@“ DZQ5YNVEU2.com.frank”]; 来获取该文件的路径。
两个 QA:
Q: 这个共享的 UserDefaults 和应用本身的 [[NSUserDefaults standardUserDefaults] 是啥关系?
A: 没啥关系,因为这两个底层的 .plist 文件位于不同的位置,你访问的时候注意一下访问的是哪个就好了。有必要和别人共享的就放到共享 UserDefaults 里,没有就放到自己的 NSUserDefaults 里。
Q: 能通过 [[NSUserDefaults alloc] initWithSuiteName:@"DZQ5YNVEU2.com.frank”]; 这种方法来获取其余你知道 Suite name 的应用的 Preference list 吗?
A: 我写了 demo 试了试发现并不能。
initWithSuiteName 的官方说明 On macOS, specifying another app’s bundle identifier will get you that app’s preferences search list, unless prevented by the App Sandbox.
Adding an App to an App Group
The com.apple.security.application-groups (available in macOS v10.7.5 and v10.8.3 and later) allows multiple apps produced by a single development team to share access to a special group container. This container is intended for content that is not user-facing, such as shared caches or databases.
In addition, this attribute allows the apps within the group to share Mach and POSIX semaphores and to use certain other IPC mechanisms among the group’s members. For additional details and naming conventions, read “Mach IPC and POSIX Semaphores and Shared Memory” in App Sandbox Design Guide.
The value for this key must be of type array, and must contain one or more string values, each of which must consist of your development team ID, followed by a period, followed by an arbitrary name chosen by your development team. For example:
<key>com.apple.security.application-groups</key>
<array>
<string>DG29478A379Q6483R9214.HolstFirstAppSuite</string>
<string>DG29478A379Q6483R9214.HolstSecondAppSuite</string>
</array>
The group containers are automatically created or added into each app’s sandbox container as determined by the existence of these keys. The group containers are stored in ~/Library/Group Containers/<application-group-id>, where <application-group-id> is one of the strings from the array. Your app can obtain the path to the group containers by calling the containerURLForSecurityApplicationGroupIdentifier: method of NSFileManager.
Demo 地址: https://github.com/fanxiushan/Demo.FRShareUserDefaults
参考链接:
- https://developer.apple.com/documentation/foundation/nsuserdefaults/1409957-initwithsuitename
- https://developer.apple.com/documentation/foundation/nsfilemanager/1412643-containerurlforsecurityapplicati?language=objc#
- https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html
- https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW19