[expo-notifications] Support explicit Android notification grouping (`setGroup`/`setGroupSummary`) for local `scheduleNotificationAsync`
Fabien Bavent
## Summary
expo-notifications
has no way to opt local (scheduleNotificationAsync
) Android notifications into an explicit, app-authored notification group (NotificationCompat.Builder.setGroup()
/ setGroupSummary()
). Neither NotificationContentInput
nor the native Android builder (ExpoNotificationBuilder.kt
/ BaseNotificationBuilder.kt
) call setGroup
/setGroupSummary
anywhere — this capability just doesn't exist yet.## Problem
Any app that schedules 4+ local notifications into the same channel (a common pattern for reminder/recall-style apps) falls into Android's
implicit
auto-bundling fallback instead of a real, app-authored group. Per Android's own docs:> If your app sends four or more notifications and doesn't specify a group, the system automatically groups them on Android 7.0 and higher. [...] Automatic grouping behavior might vary on some device types.
In practice, on several OEM skins this auto-bundled stack renders an expand chevron that doesn't reliably surface each notification's action buttons (
categoryIdentifier
actions) once expanded — the chevron is there, but expanding it doesn't visibly do anything, and the per-notification action buttons are gone. That's the documented risk of relying on Android's fallback instead of defining the group explicitly, and today there's no way in expo-notifications
to do the latter:- NotificationContentInputhas nogroupKey/isGroupSummary/equivalent field.
- The remote-push payload does support a groupkey, but that's the FCM path — it doesn't touch local scheduled notifications at all.
- The native builder path (ArgumentsNotificationContentBuilder→NotificationContent→ExpoNotificationBuilder.build()) never callssetGroup()/setGroupSummary().
## Proposed solution
Add two optional, Android-only fields to
NotificationContentInput
:```ts
type NotificationContentInput = {
// ...existing fields
/**
* Android notification group key. Notifications sharing the same groupKey are bundled
* together by the system under one app-authored group. Pair with a single
*
isGroupSummary: true
notification per groupKey.* @platform android
*/
groupKey?: string;
/**
* Marks this notification as the group summary for
groupKey
.* @platform android
*/
isGroupSummary?: boolean;
};
```
Wired straight through to
NotificationCompat.Builder.setGroup(groupKey)
/ .setGroupSummary(true)
in ExpoNotificationBuilder.build()
.Ideally, the module would also take care of posting/refreshing the group-summary notification itself at delivery/dismissal time (in
ExpoPresentationDelegate.presentNotification()
/ dismissNotifications()
), reusing each sibling notification's own already-authored title/text for the summary's InboxStyle
lines. That avoids apps having to keep a JS-side summary in sync with what's actually in the tray, which is fragile — notifications can be delivered by an OS alarm while the app is killed, so there's no reliable JS-side hook to recompute a summary from.## Why this matters
Grouping isn't cosmetic here — without it, apps that legitimately schedule several local notifications (reminders, recalls, chat-style updates) have no supported way to keep each one individually actionable once Android's own notification count threshold kicks in. Right now the only way to fix that is a native patch to
expo-notifications
itself.## Reference implementation
I already have a working
patch-package
fix implementing the above (JS type + native builder wiring + delivery-time summary management in ExpoPresentationDelegate.kt
), tested against expo-notifications@57.0.7
— verified end-to-end against a fresh install. Happy to turn this into a PR if that's useful — let me know.## Related
- #28580 — grouping for pushnotifications (android.groupin the FCM payload). Different code path; doesn't cover localscheduleNotificationAsync, which is what this request is about.
- #10962, #31710, #36282 — Android action buttons missing in other contexts (background/killed state, remote push). Related symptom, different root cause.
Searched Canny and GitHub for existing
setGroup
/setGroupSummary
/grouping requests before posting — didn't find one covering this specific gap.