Skip to content

fix(android): tie observer cleanup to the React module lifetime - #1977

Merged
fadi-george merged 3 commits into
OneSignal:mainfrom
OskarEichler:codex/onesignal-android-module-lifetime
Aug 31, 2026
Merged

fadi-george merged 3 commits into
OneSignal:mainfrom
OskarEichler:codex/onesignal-android-module-lifetime

Conversation

@OskarEichler

Copy link
Copy Markdown
Contributor

Description

One Line Summary

Remove the activity lifecycle listener, whose destroy callback removed observers even while the React instance remained usable. Keep cleanup in invalidate and release retained notification events and the current static instance there.

Compatibility and observable changes

Observers remain available across host activity recreation until module invalidation. Invalidating an old module does not clear a newer current instance. No JS API changes.

Details

Motivation

The source audit reproduced the failure paths described below. This PR contains only the associated fix; unrelated audit changes are in separate PRs.

Scope

  • android/src/main/java/com/onesignal/rnonesignalandroid/RNOneSignal.java

Testing

Compiled actual constructor/invalidate methods and activity lifecycle reproduction; checked ReactContext and LifecycleEventListener source to distinguish activity destruction from React instance invalidation.

Each code/tooling fix was also applied independently to upstream commit a70312207cf094ac361eaa9196c317acb175c2cd and passed its targeted external actual-source diagnostics. Documentation snippets were checked separately. Native diagnostic harnesses use bridge/SDK doubles and are not an end-to-end push test.

On the combined audit branch:

  • Existing SDK suite: 5 files, 262 tests pass; unchanged 95% coverage thresholds pass.
  • vp check: formatting, lint and type checks pass; native Spotless check passes.
  • Both example apps: Android Debug and unsigned iOS Simulator builds pass.
  • Both example apps: iOS and Android production Metro bundles pass.

No checked-in test files were added or modified; regression evidence comes from external diagnostic harnesses and the existing suite. No physical-device, live notification delivery, Appium/BrowserStack, or release-workflow execution is claimed. The no-location example's stale native lock was updated locally to resolve the current SDK for verification; generated locks are not part of this PR.

Checklist

  • Required description sections completed.
  • Scope and observable/API behavior explained.
  • Diff reviewed and targeted regression checks run.
  • Automated checks and device-testing limitations documented.

@OskarEichler
OskarEichler requested a review from a team as a code owner August 27, 2026 23:46
OskarEichler and others added 3 commits August 31, 2026 12:44
…idate

Invalidate only released one of the two notification caches, so events
retained by preventDefault survived teardown and any thread parked in
onWillDisplay was never woken. Guard both caches behind a single lock,
wake pending waiters, and swap the static instance atomically so a
concurrent reload cannot clear a newer live module.

Co-authored-by: Cursor <cursoragent@cursor.com>
Emulator testing showed the activity lifecycle listener was the only
cause of lost observers. The cache locking, waiter wake-up and eviction
changes were never reproduced and reworked the notification delivery
path, so revert them. Invalidate still clears both notification caches
and releases the static instance.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fadi-george
fadi-george force-pushed the codex/onesignal-android-module-lifetime branch from 9242858 to 54aee2b Compare August 31, 2026 21:50
@fadi-george
fadi-george merged commit 13ba666 into OneSignal:main Aug 31, 2026
2 checks passed
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.

2 participants