Skip to content

fix: make initialize() resolve only when native manager is ready - #55

Merged
wesdewitte merged 5 commits into
developfrom
feature/flic2-init-ready
Jul 16, 2026
Merged

fix: make initialize() resolve only when native manager is ready#55
wesdewitte merged 5 commits into
developfrom
feature/flic2-init-ready

Conversation

@jdegger

@jdegger jdegger commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Android: resolve initialize() only when getManager() is non-null after service bind; emit managerStateChange { event: "restored" } so JS readiness matches iOS.
  • iOS: defer initialize() resolve until managerRestored (managerDidRestoreState / PoweredOn). Keep a NOT_RESTORED gate on startScan as belt-and-suspenders for callers that race an in-flight initialize() (preferred path is still await initialize()).
  • JS: document that await initialize() means APIs are safe; make re-init idempotent (return instead of throw).

Fixes the library-level NOT_INITIALIZED / readiness race where await initialize() could resolve before the native manager was usable.

Test plan

  • Android: await Flic2.initialize() then immediately getButtons() / connectAllKnownButtons() / startScan() — no NOT_INITIALIZED
  • Android: confirm managerStateChange with event: "restored" after init
  • iOS: same sequence after await initialize() — scan works; calling startScan before restore still rejects NOT_RESTORED
  • Second Flic2.initialize() returns without throwing
  • After merge: publish a new beta and bump consumers

Android was resolving on service bind even if Flic2Manager was null and never
emitted restored. iOS resolved before managerDidRestoreState, so scan could
still hit NOT_RESTORED. Await initialize() now means APIs are safe to call.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings July 16, 2026 13:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR changes the semantics of initialize() across JS, iOS, and Android so that await initialize() only resolves when the native manager is actually ready for subsequent API calls, reducing initialization/readiness races between platforms.

Changes:

  • JS: initialize() becomes idempotent after successful initialization (no longer throws when already initialized) and documentation is updated to reflect the stronger readiness contract.
  • iOS: initialize() defers resolution until managerDidRestoreState / PoweredOn, and removes the redundant NOT_RESTORED scan gate.
  • Android: initialize() resolves only when the service is bound and getManager() is non-null, and emits a "restored" managerStateChange event after readiness.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/index.ts Updates JS initialize() behavior + docs to align with native readiness guarantees.
ios/Flic2.mm Defers init resolution until manager readiness and aligns scan gating with new contract.
ios/Flic2.h Adds storage for pending initialize promise callbacks while waiting for restore/power-on.
android/src/main/java/nl/xguard/flic2/Flic2Module.kt Tightens Android init readiness to require a non-null manager and emits a restored event.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/index.ts
Comment thread android/src/main/java/nl/xguard/flic2/Flic2Module.kt
Comment thread ios/Flic2.mm Outdated
Comment thread android/src/main/java/nl/xguard/flic2/Flic2Module.kt
Comment thread android/src/main/java/nl/xguard/flic2/Flic2Module.kt
Comment thread android/src/main/java/nl/xguard/flic2/Flic2Module.kt Outdated
Comment thread src/index.ts
Comment thread ios/Flic2.mm
Comment thread ios/Flic2.mm
Comment thread ios/Flic2.mm Outdated
Comment thread ios/Flic2.mm
Comment thread src/index.ts
Dedupe in-flight JS initialize, reject Android re-entry while pending,
unbind after null-manager failure so retries work, and track process-level
iOS restore so RN remount still resolves.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings July 16, 2026 13:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread android/src/main/java/nl/xguard/flic2/Flic2Module.kt
Unbind alone left a running service with a null manager; onCreate would
not re-run on rebind. stopService lets the next initialize() start fresh.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings July 16, 2026 13:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread ios/Flic2.mm
Comment thread ios/Flic2.mm
Comment thread ios/Flic2.mm
Comment thread android/src/main/java/nl/xguard/flic2/Flic2Module.kt
JS Flic2 is a singleton but the native module is not. Remount fast-path now
reassigns FLICManager/button delegates. Pending init rejects on invalidate.
Android reset uses Handler and invalidate always stopService.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings July 16, 2026 13:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread ios/Flic2.mm
Comment thread android/src/main/java/nl/xguard/flic2/Flic2Module.kt
Comment thread ios/Flic2.mm
sharedManager is non-null after configure but before managerDidRestoreState.
Keep an explicit NOT_RESTORED gate so scan cannot race await initialize().

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings July 16, 2026 14:05
@jdegger

jdegger commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Sentry analysis: does this PR fix the reported Manager not initialized issue?

Queried via Sentry MCP against the consumer app’s production error tracker.

What Sentry shows

Field Value
Events 2 (1 user)
Env staging
OS / device Android 16 / Samsung mid-range
Error Error: Manager not initialized
Mechanism onunhandledrejection
Stacktrace None
Screen Flic “add button” flow (both events)
App state in_foreground: false (both events)
BT scan permission granted; connect permission not granted

What this PR (#55) fixes

In react-native-flic2@2.0.0-beta.25 (current consumer dependency):

  • Android: initialize() could resolve on service bind even when getManager() was still null → immediate follow-up APIs reject NOT_INITIALIZED.
  • Android: never emitted managerStateChange / restored.
  • iOS: initialize() could resolve before restore → scan/NOT_RESTORED races (same class of “await init ≠ ready”).

This PR makes await Flic2.initialize() mean the native manager is actually ready (gate on manager, emit restored, defer iOS resolve until restored, remount/teardown hardening).

That is the correct library-layer fix for the post-successful-init race.

Does #55 alone clear this Sentry issue?

Not by itself — only after consumers bump, and the app may still have a gap.

Failure mode consistent with Sentry Fixed by #55?
initialize() resolved, then getButtons/connect raced before manager ready Yes
Screen calls getButtons before anyone successfully initialize()s No — APIs still correctly reject NOT_INITIALIZED
App backgrounded (in_foreground: false) so Android FGS/initialize fails or never runs, then UI still calls native APIs No — out of scope here (app lifecycle / foreground-service policy)

These events look most like screen call before ready + background, not only a clean “init returned then raced” stack. Shipping #55 without a consumer version bump + thin app gating would not clear this telemetry on its own.

Verdict

Question Answer
Is #55 the right root fix for the library bug behind NOT_INITIALIZED after init? Yes
Will merging #55 alone stop the observed Sentry events? No — consumer still on beta.25; UI can call APIs without a successful init; background FGS remains an app concern
What closes the loop? Merge + publish a new beta → bump the consumer → thin app change: don’t call Flic APIs until await Flic2.initialize() succeeds; defer Android init while backgrounded — not app-level NOT_INITIALIZED retry loops

Bottom line: Merge this PR. Necessary library fix, not sufficient alone for the observed events; consumer needs a small follow-up after the version bump.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread ios/Flic2.mm

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6b1db2b. Configure here.

Comment thread android/src/main/java/nl/xguard/flic2/Flic2Module.kt
@wesdewitte
wesdewitte merged commit 6db17c6 into develop Jul 16, 2026
4 checks passed
@jdegger
jdegger deleted the feature/flic2-init-ready branch July 17, 2026 08:41
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.

3 participants