App Groups: macOS vs iOS: Fight!

This thread has been locked by a moderator; it no longer accepts new replies.

I regularly see folks confused by the difference in behaviour of app groups between macOS and iOS. One day I’ll have time to write this up for the official docs (r. 92322409) but, in the meantime, here’s a quick overview.

[Well, it was a quick overview. Things have got considerably more complicated in recent years.]

If you have questions or comments, start a new thread with the details. Put it in the Privacy & Security > General topic area and tag it with Code Signing and Entitlements. Oh, and if this is about app group container protection, also include Files and Storage.

Share and Enjoy

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


App Groups: macOS vs iOS: Fight!

The app groups mechanism works differently on macOS and iOS. On iOS:

  • App group IDs start with the group. prefix.

  • To use an app group ID, first allocate it on the Developer website. This associates the app group ID with your team.

  • Then claim the app group ID in your app’s App Groups entitlement (com.apple.security.application-groups) entitlement.

  • Like all entitlements on iOS, that claim must be authorised by a provisioning profile. A profile will only authorise an app group ID that’s allocated by your team.

For more background on provisioning profiles, see TN3125 Inside Code Signing: Provisioning Profiles.

In contrast, on macOS:

  • App group IDs typically start with your Team ID.

  • They can’t be explicitly allocated on the Developer website.

  • Code that isn’t sandboxed doesn’t need to claim the app group ID in the App Groups entitlement. [1]

  • To use an app group, claim the app group ID in the App Groups entitlement.

  • The App Groups entitlement is not restricted, meaning that this claim doesn’t need to be authorised by a provisioning profile.

  • The App Store submission process checks that your app group IDs make sense.

IMPORTANT In this context I’m using macOS to refer to a standard macOS app. In Mac Catalyst things behave as they do on iOS. Likewise for iOS Apps on Mac. Also, anything I say about iOS also applies to tvOS, watchOS, and visionOS.

This difference is a product of the way that each platform protects app group content. On iOS the Developer website enforces group uniqueness, that is, the site prevents team B from using an app group ID that’s assigned to team A. In contrast, on macOS:

  • App group IDs are prefixed with the Team ID solely to prevent collisions.

  • The Mac App Store prevents you from publishing an app that uses an app group ID that’s used by another team.

  • In macOS 15 and later, all apps are subject to app group container protection.

[1] This was true prior to macOS 15. It may still technically be true in macOS 15 and later, but the most important thing, access to the app group container, requires the entitlement because of app group container protection.

Crossing the Streams

[… and mixing my pop culture metaphors!]

In some circumstances you might need to share an app group between iOS and macOS code. For example, you might have a Mac app that needs to share an app group with:

  • A Mac Catalyst app

  • An iOS app that runs on macOS via iOS Apps on Mac

The solution is to use an iOS-style app group ID in your Mac app. To do this:

  1. Confirm that the app group ID is registered to your team on the Developer website.

  2. Claim the app group ID in the App Groups entitlement.

If you submit that app to the Mac App Store, the submission process checks that your app group ID claims make sense, that is, they either follow the macOS convention (use a prefix of the Team ID) or the iOS convention (allocate a group ID, with the group. prefix, on the Developer website).

IMPORTANT Due to app group container protection, this approach is only viable for Mac App Store apps. For more details, see App Group Container Protection, below.

App Groups and the Keychain

The differences described above explain an oddity associated with keychain access. Consider this quote from Sharing Access to Keychain Items Among a Collection of Apps:

Application groups

When you collect related apps into an application group using the App Groups entitlement, they share access to a group container, and gain the ability to message each other in certain ways. Starting in iOS 8, the array of strings given by this entitlement also extends the list of keychain access groups.

There are three things to note here:

  • Using an app group ID as a keychain access group only works on iOS; it’s not supported on macOS [1] because doing so would be insecure.

  • The App Groups entitlement must be authorised by a provisioning profile on iOS, and that process is what protects the keychain from unauthorised access.

  • The required group. prefix means that these keychain access groups can’t collide with other keychain access groups, which all start with an App ID prefix (there’s also Apple-only keychain access groups that start with other prefixes, like apple).

In contrast, standard keychain access groups are protected the same way on both platforms, using the Keychain Access Groups entitlement (keychain-access-groups).

[1] Except for iOS Apps on Mac.

Not Entirely Unsatisfied

When you launch a Mac app that uses app groups you might see this log entry:

type: error
time: 10:41:35.858009+0000
process: taskgated-helper
subsystem: com.apple.ManagedClient
category: ProvisioningProfiles
message: com.example.apple-samplecode.Test92322409: Unsatisfied entitlements: com.apple.security.application-groups

Note The exact format of that log entry, and the circumstances under which it’s generated, varies by platform. On macOS 13.0.1 I was able to generate it by running a sandboxed app that claims the App Group entitlement and also claims some other restricted entitlement.

This looks kinda worrying and can be the source of problems. You see this error when you have a sandboxed app that uses an app group. In a sandboxed app your use of the app group must be authorised by the App Groups entitlement. This message is telling you that your use of the App Groups entitlement is not authorised by your provisioning profile.

On iOS this would be a show stopper. The trusted execution system would prevent your app from launching at all.

On macOS that’s not the case. The trusted execution system knows that there’s no way to get a Mac provisioning profile that authorises the App Groups entitlement, and thus it allows the app to launch anyway.

However, that’s not the end of the story. You might run into problems with:

  • macOS 15’s app group container protection

  • The entitlements validated flag

App Group Container Protection

macOS 15 introduced app group container protection. To access an app group container without user intervention:

  1. Claim access to the app group by listing its ID in the App Groups entitlement.

  2. Locate the container by calling the containerURL(forSecurityApplicationGroupIdentifier:) method.

  3. Ensure that at least one of the following criteria are met:

    • Your app is deployed via the Mac App Store (A).

    • Or via TestFlight when running on macOS 15.1 or later (B).

    • Or the app group ID starts with your app’s Team ID (C).

    • Or your app’s claim to the app group is authorised by a provisioning profile embedded in the app (D) [1].

If your app doesn’t follow these rules, the system prompts the user to approve its access to the container. If granted, that consent applies only for the duration of that app instance.

For more on this, see:

The above criteria mean that you rarely run into the app group authorisation prompt when your app is deployed. If you encounter a case where that happens, feel free to start a thread here on DevForums. See the top of this post for info on the topic and tags to use.

However, you might run into some issues during development:

  • If you have a multiplatform app built from a single target — for example, if you created the project from the Multiplatform > App template — Xcode’s Signing & Capabilities editor doesn’t understand all of these app group nuances. To work around this, conditionalise the entitlements file build setting. See this thread for more.

  • If you use an iOS-style app group ID in a macOS app, you might run into the authorisation prompt during day-to-day development. One way around this is to use a macOS-style app group ID during development and switch to the iOS-style app group ID for production.

[1] This is what allows Mac Catalyst and iOS Apps on Mac to work.

Entitlements Validated Flag

If your app claims the app group entitlement but that claim isn’t authorised by a provisioning profile, the trusted execution system allows the app to launch but it clears its entitlements validated flag. Some subsystems that rely on entitlements will fail in this case. The most notable example of this is the data protection keychain.

Note If you’re curious about this flag, use the procinfo subcommand of launchctl to view it. For example:

% sudo launchctl procinfo `pgrep Test20230126`
…
code signing info = valid
    …
    entitlements validated
…

If the flag has been cleared, this line will be missing from the code signing info section.

The practical impact of this is that, for a sandboxed app on macOS, you can either use app groups or use the data protection keychain, but not both. Needless to say, this is less than ideal (r. 104859788).

IMPORTANT This doesn’t stop you using the keychain in general. You can still use the file-based keychain. For more information about these terms, see TN3137 On Mac keychain APIs and implementations.

One place this often crops up is with Network Extension (NE) framework system extensions. These must be sandboxed and often use an app group as part of their IPC story. Specifically, they might want to publish an XPC named endpoint and, when doing that, the name listed in NEMachServiceName must be a ‘child’ of an app group.

Fortunately, system extensions are effectively daemons and so can’t use the data protection keychain anyway. So, if you’re building an NE system extension, this message is probably nothing to be worried about.

If you’re building some other program that’s affected by this, open a thread here on DevForums and let’s talk. See the top of this post for info on the topic and tags to use.

Revision History

  • 2024-11-05 Further clarified app group container protection. Reworked some other sections to account for this new reality.

  • 2024-10-29 Clarified the points in App Group Container Protection.

  • 2024-10-23 Fleshed out the discussion of app group container protection on macOS 15.

  • 2024-09-04 Added information about app group container protection on macOS 15.

  • 2023-01-31 Renamed the Not Entirely Unsatisfactory section to Not Entirely Unsatisfied. Updated it to describe the real impact of that log message.

  • 2022-12-12 First posted.

Boost
App Groups: macOS vs iOS: Fight!
 
 
Q