react-native-phone-sms-retriever
v1.2.4
Published
Android SMS Retriever and Google phone number hint for React Native
Readme
react-native-phone-sms-retriever
Android SMS Retriever OTP auto-read and Google phone-number hint for React Native.
Platform: Android only. On iOS, SMS helpers (getOtp / getHash) return empty/false; hint methods (requestHint, etc.) reject.
Fork of react-native-otp-verify. Native module: PhoneSmsRetriever (com.phonesmsretriever).
Install
npm install react-native-phone-sms-retriever
# or
yarn add react-native-phone-sms-retrieverRebuild the native app after install (autolinking, RN ≥ 0.60). Does not work in Expo Go — use a dev client or bare workflow.
SMS OTP
1. Get your app hash
Run once on a debug/release build of your app (hashes differ by signing key):
import { getHash } from 'react-native-phone-sms-retriever';
getHash().then(console.log); // e.g. ["FA+9qCX9VSu"]Give this string to whoever sends the OTP SMS.
2. SMS body format
Google requires this pattern (docs):
<#> Your OTP is 1234
FA+9qCX9VSu- First line: message text containing the OTP digits.
- Second line: 11-character app hash from
getHash(). <#>prefix is required.
SMS must arrive on the device within ~5 minutes of starting the listener.
3. Listen in JS
import { useEffect } from 'react';
import { startOtpListener, removeListener } from 'react-native-phone-sms-retriever';
useEffect(() => {
startOtpListener((message) => {
if (message === 'Timeout Error.') {
// no SMS within retriever window — restart listener or ask user to re-request OTP
return;
}
const otp = /(\d{4})/.exec(message)?.[1];
if (otp) setOtp(otp);
});
return () => removeListener();
}, []);Or use the hook (starts listener on mount, calls removeListener on unmount):
import { useOtpVerify } from 'react-native-phone-sms-retriever';
const { hash, otp, message, timeoutError, startListener, stopListener } =
useOtpVerify({ numberOfDigits: 4 });Event name (if you use addListener directly): com.phonesmsretriever:otpReceived.
Phone number hint
Shows a Google picker so the user can select a number instead of typing it.
import { requestHint } from 'react-native-phone-sms-retriever';
requestHint()
.then((phone) => setPhone(phone))
.catch((err) => {
// err.code — see table below
});| Method | Behavior |
|--------|----------|
| requestHint() | New Phone Number Hint API, then legacy Credentials picker only if the new API fails before UI |
| requestPhoneHint() | New API only |
| requestLegacyPhoneHint() | Legacy Credentials HintRequest only |
Cancel vs unavailable: If the new picker opens and the user closes it (resultCode=0), the promise rejects with HINT_CANCELLED — legacy is not shown. Legacy runs only when getPhoneNumberHintIntent fails (e.g. ApiException: 16) or the intent cannot be launched.
When hint fails (not a bug)
Many SIMs do not store the phone number (MSISDN). Play Services then returns errors like ApiException: 16: No phone number is found on this device. Use manual entry — there is no client-side fix.
Hint error codes (err.code)
| Code | When | What to do |
|------|------|------------|
| No Sim Avaiable | SIM not SIM_STATE_READY | Ask user to check SIM |
| No Activity Found | No foreground Activity | Call from a mounted screen, not at app launch |
| HINT_CANCELLED | User dismissed picker (new or legacy) | Manual entry |
| HINT_UNAVAILABLE | No number on device, no hints, legacy API missing, or parse failed | Manual entry |
| HINT_LAUNCH_FAILED | Could not open hint UI (new API only path) | Retry or manual entry |
| HINT_IN_PROGRESS | Another hint request is already open | Wait for it to finish |
Legacy picker needs com.google.android.gms.auth.api.credentials.HintRequest, removed in play-services-auth 21.0.0+. This package pins 20.7.0 (see below).
play-services-auth 20.7.0
This library's android/build.gradle already depends on and forces com.google.android.gms:play-services-auth:20.7.0 app-wide:
implementation "com.google.android.gms:play-services-auth:20.7.0"
rootProject.allprojects {
configurations.all {
resolutionStrategy {
force "com.google.android.gms:play-services-auth:20.7.0"
}
}
}If Firebase or Google Sign-In still resolves 21.x in your app, add the same resolutionStrategy block to your Android root build.gradle, then rebuild and retest sign-in flows.
Use with react-native-otp-verify
Both packages can be installed together. They use different Java packages and native module names, so you avoid dex duplicate errors on AppSignatureHelper:
| Package | Native module | Java package |
|---------|---------------|--------------|
| react-native-phone-sms-retriever | PhoneSmsRetriever | com.phonesmsretriever |
| react-native-otp-verify | OtpVerify | com.faizal.OtpVerify |
Import SMS/hint APIs from whichever package your screen uses — do not assume both expose the same JS module name.
API
getHash(): Promise<string[]>
getOtp(): Promise<boolean>
startOtpListener(handler: (message: string) => void): Promise<EmitterSubscription>
addListener(handler: (message: string) => void): EmitterSubscription
removeListener(): void
requestHint(): Promise<string>
requestPhoneHint(): Promise<string>
requestLegacyPhoneHint(): Promise<string>
useOtpVerify({ numberOfDigits?: number })
// → { hash, otp, message, timeoutError, startListener, stopListener }Debug
adb logcat -s PhoneSmsRetrieverModule:D PhoneSmsRetrieverModule:E SMS:DLicense
MIT
