Summary
startOtpListener currently starts SMS Retriever first and only attaches the JS event listener after getOtp() resolves:
return getOtp().then(() => addListener(handler));
Because OtpBroadcastReceiver emits the SMS directly to RCTDeviceEventEmitter, an OTP can be missed if the SMS Retriever broadcast arrives before addListener(handler) is registered on the JS side.
Relevant code
- src/index.tsx: startOtpListener calls getOtp().then(() => addListener(handler)).
- android/src/main/java/com/faizal/OtpVerify/OtpVerifyModule.java: requestOtp() calls SmsRetriever.getClient(...).startSmsRetriever() and resolves the promise on start success.
- android/src/main/java/com/faizal/OtpVerify/OtpBroadcastReceiver.java: receiveMessage() emits the raw SMS immediately through DeviceEventManagerModule.RCTDeviceEventEmitter.
Why this can miss an OTP
The listener setup order is:
- JS calls startOtpListener(handler).
- Native getOtp() starts SmsRetrieverClient.startSmsRetriever().
- Native promise resolves when the retriever starts.
- JS registers addListener(handler).
If the OTP broadcast is received between steps 2/3 and step 4, the receiver emits the event while no JS listener is attached yet. Since there is no native or JS-side pending-message buffer, the app may never receive that OTP event.
Suggested fixes
One of these should close the race:
- Register the JS event listener before calling getOtp() in startOtpListener.
- Or buffer the latest SMS/timeout event natively until the JS listener is active.
- Or make startOtpListener create the subscription first, then start the retriever, and clean up the subscription if getOtp() fails.
Summary
startOtpListener currently starts SMS Retriever first and only attaches the JS event listener after getOtp() resolves:
Because OtpBroadcastReceiver emits the SMS directly to RCTDeviceEventEmitter, an OTP can be missed if the SMS Retriever broadcast arrives before addListener(handler) is registered on the JS side.
Relevant code
Why this can miss an OTP
The listener setup order is:
If the OTP broadcast is received between steps 2/3 and step 4, the receiver emits the event while no JS listener is attached yet. Since there is no native or JS-side pending-message buffer, the app may never receive that OTP event.
Suggested fixes
One of these should close the race: