What does an app group look like on disk, and what happens with a group the target is not entitled to?

19.10.2 · L3 · Interview

Predict first

What does containerURL return for the entitled group and for another group?

// entitlement: group.com.example.bank on App and Widget
let ok = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.example.bank")
let other = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.example.other")
  • A Shared/AppGroup/<UUID> URL for the first; nil for the second
  • nil for both
  • A URL for both

Mental model. The group container is a shared mailbox in the lobby: both flats need a key, and the key must be for the same mailbox number.

In a built sample with the group group.com.example.bank on both the app and the widget, containerURL(forSecurityApplicationGroupIdentifier:) returned a folder under the simulator’s Containers/Shared/AppGroup/<UUID>, and xcrun simctl listapps showed it as the app’s GroupContainers entry. Asking for a different group (group.com.example.other) returned nil, the same symptom as a missing entitlement (Q402). UserDefaults(suiteName:) with the entitled group worked and read back 42. A group container is separate from the app’s own Containers/Data folder and it survives deleting the app only while another app of the same team still uses the group (device behaviour; not run).

Diagnostic order for “the widget sees nothing”: (1) is the group in both targets’ entitlements and spelled identically; (2) does containerURL return non-nil in the extension; (3) are both writing the same file path inside it; (4) is the data written atomically and read after the widget is reloaded (Q232). The simulator signs ad hoc with the entitlement file, which is enough for groups; a real device additionally needs the group registered in the developer account and a provisioning profile that includes it (not run).

Only entitled groups get a container; others return nil.

Common traps

  • Force-unwrapping containerURL. A typo in one target crashes the extension.
  • Assuming the group exists on a device because it worked in the simulator. The profile must contain it.

They might follow up with

  • Where do I put shared files? In a subfolder of the group container, written atomically.

Related questions

  • 19.1.2 How do app groups, shared containers and keychain access groups let an app and its extensions share data, and…
  • 6.8.1 What is an app group, and what can go wrong when an app and an extension share a database?
  • 6.8.3 Why is an app extension a separate process, and what does that mean for how you build it?

← What makes an extension valid inside an app bundle: the Info.plist…   How do you make a shared payload that an older widget can still… →