Hi,
I’m writing a network extension for macOS using the following pattern:
- Network extension with ID com.company.app.extension
- XPC Service with ID com.company.app.controller
- Container app with ID com.company.app.container
- First 2 are contained in the 3rd
All of 3 are sandboxed & share the same com.company.app AppGroup. XPC Service uses network (client) entitlement to fetch settings & control the extension. The app need to support managed preferences as well.
I read many posts in this forum, but I’m confused about using NSUserDefaults accross those processes.
Pb 1 - standardsUserDefaults vs initWithSuiteName
I noticed that to observe defaults using KVO I need to use initWithSuiteName:@"com.company.app"
(or addSuiteName
).
Observing standardsUserDefaults alone will never trigger any event. This is the first confusion because my understanding was that KVO observation wasn’t restrincted to suites.
Pb 2 - AppGroup ‘group.’ prefix
If I observe a suite named ‘com.company.app’ from the container app or XPC Service I get error : [User Defaults] Couldn't read values in CFPrefsManagedSource<> (Domain: com.company.app, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: No): accessing preferences outside an application's container requires user-preference-read or file-read-data sandbox access
This can be fixed using ‘group.com.company.app’ suite (both in the code and AppGroup entitlement). However if I use the same AppGroup for extension it will fail loading with error code OSSystemExtensionErrorValidationFailed.
Checked the provisioning profiles, they all map to the same ID in Dev portal. Including the TeamID in the suite name will produce the same situation.
The only way to load the extension is to use AppGroup com.company.app. This again is confusing because Dev portal force the ‘group.’ prefix. I can’t figure out how to use the same suite name for all processes.
Pb 3 - Inter-process synchronisation
Based on previous conclusion the situation is both container & controller use AppGroup (TeamID).group.com.company.app and addSuiteNamed:@"group.com.company.app"
for observing & updating the defaults.
Each process can observe its own defaults updates but they do not synchronize between container app and XPC Service.
This is the most frustating part. The documentation says:
NSUserDefaultsDidChangeNotification is posted whenever any user defaults changed within the current process, but is not posted when ubiquitous defaults change, or when an outside process changes defaults. Using key-value observing to register observers for the specific keys of interest will inform you of all updates, regardless of where they're from.
Did I missed some steps ?