Skip to content

fix(android): unsubscribe click listener when Flutter engine detaches#1140

Merged
nan-li merged 1 commit into
mainfrom
fix/notification_click_listener_fired
May 5, 2026
Merged

fix(android): unsubscribe click listener when Flutter engine detaches#1140
nan-li merged 1 commit into
mainfrom
fix/notification_click_listener_fired

Conversation

@nan-li
Copy link
Copy Markdown
Contributor

@nan-li nan-li commented Apr 30, 2026

One Line Summary

Closes #1138 — unsubscribe the notification click listener when the Flutter engine detaches so click events that arrive while the engine is dead are queued and replayed on relaunch.

Details

Motivation

Since #1102 made OneSignalNotifications a singleton, the click listener stays subscribed to the native Android SDK across engine detach/reattach cycles. When the user backgrounds the app via the back button:

  1. The Flutter engine is destroyed, but the singleton listener remains registered with the native SDK.
  2. A subsequent notification click fires onClick on the listener, which tries to send a platform message on the now-detached BinaryMessenger. The message is dropped (logged as FlutterJNI was detached from native C++. Could not send.).
  3. When the app reopens, the click event is gone — never queued, never delivered.

Customers report that prior to 5.3.6 the click listener fired correctly in this scenario.

Scope

  • Adds OneSignalNotifications.onDetachedFromEngine() which calls OneSignal.getNotifications().removeClickListener(this).
  • Wires it up from OneSignalPlugin.onDetachedFromEngine().
  • With the listener removed, the native SDK's unprocessedOpenedNotifs queues the click event (no subscriber), and addExternalClickListener replays it when Dart calls addClickListeneraddNativeClickListenerregisterClickListener after the engine reattaches.

Dependency

This PR depends on OneSignal/OneSignal-Android-SDK#2632, which clears unprocessedOpenedNotifs after replay. Without that Android SDK fix, the queue accumulates across back-press cycles and each new addClickListener call refires every previously delivered event. The Android SDK release containing #2632 must land first, and the com.onesignal:OneSignal dependency in android/build.gradle must be bumped to that version before this fix is shipped.

Manual testing

Reproduced and verified on the examples/demo_pods app on an Android emulator (API 35):

  1. Launch the demo app and confirm the click listener fires when a notification is tapped from the foreground.
  2. Press the back button to destroy the activity (engine detaches; logs show NotificationsManager.removeClickListener).
  3. Send a push notification while the app is backgrounded.
  4. Tap the notification.
  5. Verify the app reopens, Dart re-registers via addNativeClickListener, and Notification clicked: ... is logged.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

@nan-li nan-li requested a review from a team as a code owner April 30, 2026 16:59
@nan-li nan-li requested a review from fadi-george April 30, 2026 18:16
@arthurgiani
Copy link
Copy Markdown

arthurgiani commented May 4, 2026

is there any expectations for this to be merged and released? This will solve a huge bug on my flutter project (android side).

@nan-li

thank you very much!

When the engine is destroyed (e.g. back press) the singleton listener
remains subscribed to the native SDK and any subsequent click event
fires on a detached channel and is dropped. Removing the listener in
onDetachedFromEngine lets the native SDK queue the click instead, so
it replays correctly when Dart re-registers via addNativeClickListener
after the engine reattaches.
@nan-li nan-li force-pushed the fix/notification_click_listener_fired branch from d78b12b to 793ced8 Compare May 5, 2026 00:41
@nan-li
Copy link
Copy Markdown
Contributor Author

nan-li commented May 5, 2026

Re-tested using Android release 5.8.1

  1. tap notification after swipe app away - callback fires
  2. tap notification after backpress app way - callback fires
  3. tap notification after backgrounding app - callback fires
  4. tap notification and then add the click listener late (~ 5 seconds late) - callback fires

@nan-li nan-li merged commit 63f57af into main May 5, 2026
5 checks passed
@nan-li nan-li deleted the fix/notification_click_listener_fired branch May 5, 2026 18:13
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.

[bug]: addClickListener never fires on background/killed app notification tap on Android since Flutter SDK 5.3.6

5 participants