iOS capability sync strips Push Notifications "Broadcast" sub-feature (PUSH_NOTIFICATION_FEATURE_BROADCAST) every build
- Dominant language
- TypeScript
- Stars
- 1.4k
- Forks
- 236
- Avg merge
- 3d 8h
- Merged PRs (30d)
- 98
Description
### Build/Submit summary
iOS capability syncing **disables the "Broadcast" sub-feature of Push Notifications on every `eas build`**, because Broadcast is not a standalone capability — it's a setting nested under `PUSH_NOTIFICATIONS` (`PUSH_NOTIFICATION_FEATURES → PUSH_NOTIFICATION_FEATURE_BROADCAST`). The syncer's push patch only sends `{ capabilityType: 'PUSH_NOTIFICATIONS', option: 'ON' }` (no sub-options), so it re-creates the Push Notifications capability at its defaults and drops the Broadcast flag.
Broadcast push is required for **iOS 18 Live Activity broadcast push channels**. After every build, creating a channel via the APNs channel-management API returns `400 BroadcastFeatureNotEnabled`, until you re-enable Broadcast by hand in the Developer portal — only for the next build to strip it again.
### Environment
- eas-cli 19.1.0 (darwin-arm64, node 24.15.0)
- iOS, EAS-managed credentials
### Steps to reproduce
1. In the Apple Developer portal, enable **Broadcast** under Push Notifications for your App ID (Identifiers → App ID → Push Notifications → Broadcast → Save). Required for iOS 18 broadcast push / Live Activity channels.
2. Run `eas build -p ios` with managed credentials.
3. Capability sync re-patches Push Notifications, dropping the Broadcast sub-feature.
4. A backend `POST /1/apps/{bundleId}/channels` to APNs now returns `400 {"reason":"BroadcastFeatureNotEnabled"}`.
### Evidence (`EAS_DEBUG=1`)
The remote capability shows Broadcast as a nested **setting** under Push Notifications:
```json
{
"id": "_PUSH_NOTIFICATIONS",
"attributes": {
"settings": [
{
"key": "PUSH_NOTIFICATION_FEATURES",
"options": [
{ "key": "PUSH_NOTIFICATION_FEATURE_BROADCAST", "properties": [null] }
]
}
],
"enabled": true
}
}
```
The sync decision + patch:
```
Will enable remote capability: aps-environment (Push Notifications).
Will skip remote capability: com.apple.security.application-groups (App Groups).
Will skip remote capability: com.apple.developer.associated-domains (Associated Domains).
Existing to disable: [ '_IN_APP_PURCHASE', '_PUSH_NOTIFICATIONS' ]
Patch Request: [ { capabilityType: 'PUSH_NOTIFICATIONS', option: 'ON' } ]
```
The patch re-enables Push Notifications with **default** settings, so the `PUSH_NOTIFICATION_FEATURE_BROADCAST` sub-setting is lost. (It also lists `IN_APP_PURCHASE` to disable — the same reconciliation can strip other portal-only capabilities the syncer doesn't model.)
### Why there is no config-level workaround
- **Broadcast has no entitlement**, so it can't be declared in `ios.entitlements` for the syncer to preserve.
- The capability is an App-ID-level setting in App Store Connect, **not part of the build**, so a config plugin can't set it.
- The push patch has no field for sub-options.
### Current workaround
`EXPO_NO_CAPABILITY_SYNC=1` disables capability syncing entirely, preserving the manually-enabled Broadcast setting (and other portal-only capabilities like In-App Purchase).
**It must be set in the shell environment** — e.g. `EXPO_NO_CAPABILITY_SYNC=1 eas build …`, or exported in your shell. Setting it under a build profile's `env` in `eas.json` does **not** work: capability sync runs locally during credential resolution, before/outside the build-profile env (and `eas credentials` uses no build profile at all), so it never sees the eas.json value.
### Request
One of:
- Preserve capability **sub-settings** (e.g. `PUSH_NOTIFICATION_FEATURE_BROADCAST`) during sync rather than resetting Push Notifications to defaults; or
- Don't disable/reset capabilities (or sub-features) the syncer doesn't model — treat them like the already-skipped App Groups / Associated Domains; or
- At minimum, document that enabling Broadcast push requires `EXPO_NO_CAPABILITY_SYNC=1` (or local credentials).
Contributor guide
Assessment
This issue has not been assessed yet.