Unable to Write to UserDefaults from Widget Extension Despite Correct App Group Configuration

Hi Apple team, I'm experiencing a persistent issue with writing to UserDefaults from a widget extension on iOS. Here's the situation:

  1. I've set up an App Group: group.test.blah
  2. The main app has the correct entitlement and can read/write from UserDefaults(suiteName:) using this group successfully.
  3. I can read the value written by the app from the widget (e.g., "testFromApp": "hiFromApp").
  4. The widget extension has the same App Group enabled under Signing & Capabilities.
  5. The provisioning profile reflects the App Group and the build installs successfully on a real device.
  6. The suite name is correct and matches across both targets.
  7. I’ve confirmed via FileManager.default.containerURL(...) that the app group container resolves properly.

When I try to write from the widget extension like this

let sharedDefaults = UserDefaults(suiteName: "group.test.blah")
sharedDefaults?.set("hiFromWidget", forKey: "testFromWidget")

...I get this error in the console:

Couldn't write values for keys (
    testFromWidget
) in CFPrefsPlistSource<0x1140d2880> (Domain: group.test.blah, 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

Questions:

What could still cause the widget extension to lack write access to the app group container, even though it reads just fine?

Are there any internal sandboxing nuances or timing-related issues specific to Live Activity widgets that could explain this?

Is this a known limitation or platform issue?

Answered by Engineer in 852815022

These limitations are put in on purpose as privacy policies for Widget and LA extensions.

There is no way for an extension to export any of its data to be consumed by another process automatically.

You can use unified logging for post execution debugging by accessing the sysdiagnose from an device, or if you are able to, watch the log output live using the Console app on an attached Mac.

I switched to writing to a file instead and I get the same error:

    Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “testFromWidget.txt” in the folder “B6DF24C2-XXXX-XXXXX-XXX-XXXXXXX." UserInfo={NSFilePath=.../testFromWidget.txt, NSURL=.../testFromWidget.txt, NSUnderlyingError=0x1078790e0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

It kinda looks like the widget extension is limited to read-only access to the group. However, I’d like to check one thing just to be sure. In the error you posted you elided the full path shown by the error. Please post that full path.

Share and Enjoy

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

If I may add some info here: you mention "Live Activity widget", so I am not sure if you are talking about a Live Activity extension or a Widget extension. But they are similar in their restrictions (although Live Activities are more limited)

Due to privacy policies, Live Activity and Widget extensions, which could be able to run on the Lock Screen, have restricted abilities to send any data outside the extension.

Widget extensions can read from a shared container but they can’t write to it. Live Activity extensions can’t perform networking and they can’t even write to the logging system.

These are sandboxing nuances as you suspect, and can't be circumvented by workarounds or special permissions.


Argun Tekant /  DTS Engineer / Core Technologies

I also switched to using unified logging with os.Logger(subsystem:category) in the widget extension, and it's successfully logging details. Do you think there's a way to leverage these logs for tracking events?

I'm not sure how to route them to an external log management system, since widget extensions can't make network calls or write to persistent storage.

Accepted Answer

These limitations are put in on purpose as privacy policies for Widget and LA extensions.

There is no way for an extension to export any of its data to be consumed by another process automatically.

You can use unified logging for post execution debugging by accessing the sysdiagnose from an device, or if you are able to, watch the log output live using the Console app on an attached Mac.

Do you think there's a way to leverage these logs for tracking events?

Do not attempt to use the system log as an IPC channel. That’s not its intended purpose.

I’ve not investigated this for other app extension types but, for NE content filter data providers at least, the restricted sandbox prevents the provider from recording system log entries. I talk about this in Your Friend the System Log.

Share and Enjoy

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

Do you have any alternative suggestions for tracking live activity events?

Not specifically. Live Activity isn’t really my wheelhouse.

I think it’d be worthwhile you running a quick test to see if the sandbox is blocking the extensions from recording log events. That should be pretty straightforward:

  1. Update your extension to add a log point on some obvious code path.
  2. Run it normally and see if the log event shows up.
  3. If they do, export an Ad Hoc signed version of your app.
  4. Repeat step 2.

ps It’s better to reply as a reply, rather than in the comments; see Quinn’s Top Ten DevForums Tips for this and other titbits.

Share and Enjoy

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

Unable to Write to UserDefaults from Widget Extension Despite Correct App Group Configuration
 
 
Q