Skip to content

feat(Android): add notification action buttons - #271

Open
Dre-Van-den-Hooff-Codifly wants to merge 1 commit into
Rapsssito:masterfrom
Dre-Van-den-Hooff-Codifly:feat/notification-actions
Open

feat(Android): add notification action buttons#271
Dre-Van-den-Hooff-Codifly wants to merge 1 commit into
Rapsssito:masterfrom
Dre-Van-den-Hooff-Codifly:feat/notification-actions

Conversation

@Dre-Van-den-Hooff-Codifly

@Dre-Van-den-Hooff-Codifly Dre-Van-den-Hooff-Codifly commented Aug 13, 2026

Copy link
Copy Markdown

Adds an optional actions option that renders buttons on the foreground service notification, and emits notificationAction when one is pressed.

Closes #60.

Usage

await BackgroundService.start(task, {
    ...options,
    actions: [
        { id: 'pause', title: 'Pause' },
        { id: 'cancel', title: 'Cancel' },
    ],
});

BackgroundService.on('notificationAction', ({ id }) => {
    if (id === 'pause') pauseMyTask();
});

Passing a new actions array to updateNotification() swaps the buttons, so a
task can show pause while running and resume while paused.

Notes on the implementation

  • The receiver is registered at runtime, not in the manifest. The
    notification only exists while the service — and therefore the process — is
    alive, so there is never a press with no receiver to take it. It also avoids
    an exported manifest receiver. Unregistered in invalidate() so a JS reload
    doesn't leak one.
  • Each button gets its own PendingIntent request code. Sharing one makes
    every button deliver whichever intent was registered first.
  • _normalizeOptions passes actions through. It runs on every
    updateNotification() too, so without this the buttons would disappear on the
    first progress update. Covered by a regression test.
  • notificationAction is re-emitted through the existing EventEmitter, so
    it's consumed exactly like expiration.
  • actions is optional and Android-only; no behaviour changes when it's absent,
    and no iOS changes.

Testing

  • yarn ci passes: 15 tests, 100% coverage on index.js. Four new cases —
    actions passed through on start, kept across updateNotification(),
    undefined when not supplied, and the event re-emission.
  • The Java isn't compiled by CI, so I verified it separately: it compiles
    against RN 0.85 / AGP, and the full flow (buttons rendering, presses driving
    pause/resume/cancel through the foreground service) is running in a shipped
    release build on a physical device.

Adds an `actions` option that renders buttons on the foreground service
notification, and emits `notificationAction` with the pressed button's id.

Closes Rapsssito#60.

- `actions: [{id, title}]` is added to the notification builder, each button
  broadcasting an explicit intent carrying its own id.
- The broadcast receiver is registered at runtime rather than in the manifest:
  the notification only exists while the service, and therefore the process, is
  alive, so there is never a press with no receiver to take it. It is
  unregistered in `invalidate()` so a JS reload does not leak one.
- Each button gets its own PendingIntent request code; sharing one makes every
  button deliver whichever intent was registered first.
- `notificationAction` is re-emitted through the existing EventEmitter, so it is
  consumed the same way as `expiration`.
- The subscription is Android-only. `RNBackgroundActions` declares `expiration`
  as its only supported event on iOS, so subscribing there makes
  RCTEventEmitter log `\`notificationAction\` is not a supported event type`
  on every launch of a debug build.
- The platform is set in `jest.setup.js` rather than in the test file: the
  server subscribes when it is constructed, which is when a test file imports
  it — before any assignment inside that file has run.
- `_normalizeOptions` passes `actions` through. It is applied on every
  `updateNotification()` too, so without this the buttons would disappear on the
  first progress update.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

How to add action button on notification

1 participant