fix sms otp retriver

This commit is contained in:
2026-05-31 00:05:21 +08:00
parent 80bf462d2c
commit 557931892f
6 changed files with 168 additions and 74 deletions

69
utils/smsRetriever.ts Normal file
View File

@@ -0,0 +1,69 @@
import { Platform } from 'react-native';
type SmsRetrieverModule = {
requestPhoneNumber: () => Promise<string>;
startSmsRetriever: () => Promise<boolean>;
addSmsListener: (callback: (event: { message?: string }) => void) => Promise<boolean>;
removeSmsListener: () => void;
};
function getModule(): SmsRetrieverModule | null {
if (Platform.OS !== 'android') return null;
return require('react-native-sms-retriever').default as SmsRetrieverModule;
}
export function extractOtpFromMessage(message: string, length: number): string | null {
const exact = new RegExp(`(?:^|[^\\d])(\\d{${length}})(?:[^\\d]|$)`);
const m = message.match(exact);
if (m) return m[1];
const any = message.match(/(\d{4,8})/);
if (!any) return null;
const digits = any[1];
if (digits.length >= length) return digits.slice(0, length);
if (digits.length === length) return digits;
return null;
}
/** SMS Retriever无需 READ_SMS短信需含 app hash见 Google 文档) */
export async function startOtpSmsListener(
otpLength: number,
onOtp: (otp: string) => void,
): Promise<() => void> {
const mod = getModule();
if (!mod) return () => {};
const stop = () => {
try {
mod.removeSmsListener();
} catch {
/* ignore */
}
};
try {
const registered = await mod.startSmsRetriever();
if (!registered) return stop;
await mod.addSmsListener((event) => {
const msg = event.message ?? '';
const otp = extractOtpFromMessage(msg, otpLength);
if (otp) {
onOtp(otp);
stop();
}
});
} catch {
stop();
}
return stop;
}
/** 系统号码选择器,一次性授权,无需 READ_SMS */
export async function requestPhoneNumberHint(): Promise<string> {
const mod = getModule();
if (!mod) throw new Error('仅支持 Android');
return mod.requestPhoneNumber();
}
export function normalizeHintPhone(raw: string, mobileLength = 10): string {
return raw.replace(/\D/g, '').slice(-mobileLength);
}