macOS : Accessing UserDefaults when App Group is enabled

I am developing a macOS app, with an embedded Finder Extension and I want the app and the extension to share UserDefaults

The App is Sandboxed for future distribution on the app store.

I followed instructions here : https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW1
  1. Both targets are part of the same app group, as it can be seen in the Entitlements:

Code Block xml
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>$(TeamIdentifierPrefix)com.stormacq.mac.MyApp</string>
</array>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>


2. I am accessing the UserDefaults by the suiteName :

Code Block swift
let defaults = UserDefaults.init(suiteName: "TEAM_ID.com.stormacq.mac.MyApp")
//where TEAM_ID is the actual team id used to sign the app (something like 123AB45CDE)


However, when trying to read or write the defaults at App startup time, I receive this error message :

[User Defaults] Couldn't read values in
CFPrefsPlistSource<0x600002c4d200> (Domain:
TEAM_ID.com.stormacq.mac.MyApp, User: kCFPreferencesAnyUser, ByHost:
Yes, Container: (null), Contents Need Refresh: Yes): Using
kCFPreferencesAnyUser with a container is only allowed for System
Containers, detaching from cfprefsd

I found weird that the error message says Container: (null),.

The group container and the shared Preference file is created (and contains the correct default values set by my code) :

Code Block
➜ ~ ls -al ~/Library/Group\ Containers/TEAM_ID.com.stormacq.mac.MyApp/Library/Preferences/
total 8
drwx------ 3 stormacq 1896053708 96 Sep 6 19:58 .
drwx------ 5 stormacq 1896053708 160 Sep 6 19:58 ..
-rw-------@ 1 stormacq 1896053708 103 Sep 6 19:58 TEAM_ID.com.stormacq.mac.MyApp.plist
# I edited TEAM_ID to post this message


I am using Xcode 11.7 (Swift 5) and macOS 10.15.6. What did I miss ?


Answered by DTS Engineer in 631165022

The group container and the shared Preference file is created (and
contains the correct default values set by my code) :

So that means things are working, right? So you’re only concern is the weird log message?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Accepted Answer

The group container and the shared Preference file is created (and
contains the correct default values set by my code) :

So that means things are working, right? So you’re only concern is the weird log message?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Looks like you are right :-) It works and I can ignore the warning. My original issue was that items were never saved, but it was another problem with @State in a SwiftUI view. It was not related to UserDefaults.

Thanks for the highlight :-)

One more thing :

The shared preferences file is corrected created in ~/Library/Group Containers directory, but the defaults command line does not see it.

Code Block zsh
➜ ~ defaults read com.stormacq.mac.MyApp
2020-09-07 10:25:53.188 defaults[82827:947786]
Domain com.stormacq.mac.MyApp does not exist
➜ ~ defaults read TEAM_ID.com.stormacq.mac.MyApp
2020-09-07 10:26:05.088 defaults[82857:947925]
Domain TEAM_ID.com.stormacq.mac.MyApp does not exist


The same with non-shared preferences works correctly. Can defaults read Group Containers ?


Can defaults read Group Containers?

You can probably still do this by passing it the path. See the defaults man page for an example.

ps Given the discussion in that man page, it would make sense for you to file an enhancement request for an explicit syntax to target a group container.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"

Was there a way to edit the group container using Defaults? I tried using the filepath option, but it always failed saying the domain doesn't exist. It seems to be treating it as a domain instead of a filepath.

Also the man page for Defaults on 10.15.7 has the below text, so it seems like support for the paths to a plist will be removed.

"WARNING: The defaults command will be changed in an upcoming major release to only operate on preferences domains. General plist manipulation utilities will be folded into a different command-line program."

The only working way I have found to edit the UserDefaults for a group container is to manually edit the plist, then restart cfprefsd, as it doesn't pick up changes to the plist.

Was there a way to edit the group container using defaults?

No, hence my suggestion earlier that sebsto file an ER for this (which they did — thanks sebsto!).

The only working way I have found …

You could write a tiny tool to do the editing you need. The most common reason that folks use defaults during app development is to reset a setting or read a setting, both of which would be pretty simple to support.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

macOS : Accessing UserDefaults when App Group is enabled
 
 
Q