I have an iOS app which contains a custom keyboard that can be used by any app. They share a few prefs by using an app group and a named suite of NSUserDefaults. Each target (app, keyboard) keep their own instance of the shared prefs by storing it in a property:
self.sharedPrefs = [[NSUserDefaults alloc] initWithSuiteName:kPrefsSuiteName];
And then add observers for a couple different prefs:
[self.sharedPrefs addObserver:self forKeyPath:kPrefRecents options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
When running in the Simulator, both the app and keyboard can write to the shared prefs and both target's observers correctly respond to changes. But when running on a device (iPhone X, iPad Pro 11"), the app can write to the prefs, but the keyboard fails with:
2023-04-17 14:20:20.095600-0500 projectname[561:23591] [User Defaults] Couldn't write values for keys (
Recents
) in CFPrefsPlistSource<0x2807dc500> (Domain: group.com.my.key, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null), Contents Need Refresh: No): setting preferences outside an application's container requires user-preference-write or file-write-data sandbox access
I also noticed this when the app adds its first key value observer to the shared prefs:
2023-04-17 14:57:36.610366-0500 projectname[820:45796] [User Defaults] Couldn't read values in CFPrefsPlistSource<0x280bc1c80> (Domain: group.com.my.key, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd
This is supposed to work. What's wrong here?
OMG, user error, but one that Apple could prevent. I revisited the docs for keyboard extensions and found it right in the first paragraph:
Custom keyboards operate in a sandboxed environment running in an isolated process. This sandbox’s default configuration disallows access to the network and prevents writing to the containing app’s shared group containers (reading is permitted). Open access lets you do things like store keyboard configuration, perform more complex analysis on text the user typed, or provide advanced features that require server support.
But Apple could help developers by mentioning RequestsOpenAccess in the error message instead of being somewhat cryptic about it.