Files
rnpay/utils/smsRetriever.ts
2026-05-31 00:05:21 +08:00

70 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}