React Native模块无法获取手机号问题排查求助
排查React Native PhoneNumberHintModule无法获取手机号的问题
我基于Smart Lock for Passwords API实现了React Native原生模块PhoneNumberHintModule用于获取手机号,原生模块代码和RN端事件监听代码如下,但始终无法成功获取手机号,事件回调也没触发,请帮忙排查原因。
原生模块代码
public class PhoneNumberHintModule extends ReactContextBaseJavaModule { private static ReactApplicationContext reactContext; private static final int CREDENTIAL_PICKER_REQUEST = 1; private static Promise mPromise; private static final String EVENT_PHONE_NUMBER_SELECTED = "phoneNumberSelected"; private final BaseActivityEventListener activityEventListener = new BaseActivityEventListener() { @Override public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { PhoneNumberHintModule.this.onActivityResult(requestCode, resultCode, data); } }; public PhoneNumberHintModule(ReactApplicationContext context) { super(context); reactContext = context; if (reactContext != null) { reactContext.addActivityEventListener(activityEventListener); } } @NonNull @Override public String getName() { return "PhoneNumberHintModule"; } @ReactMethod public void getPhoneNumberHint(final Promise promise) { mPromise = promise; final Activity currentActivity = getCurrentActivity(); if (currentActivity == null) { promise.reject("ACTIVITY_NOT_AVAILABLE", "Activity is not available"); return; } Context context = getReactApplicationContext(); HintRequest hintRequest = new HintRequest.Builder() .setPhoneNumberIdentifierSupported(true) .build(); IntentSender intent = Credentials.getClient(context).getHintPickerIntent(hintRequest).getIntentSender(); try { currentActivity.startIntentSenderForResult( intent, CREDENTIAL_PICKER_REQUEST, null, 0, 0, 0, new Bundle() ); } catch (IntentSender.SendIntentException e) { e.printStackTrace(); sendErrorToReactNative("SEND_INTENT_ERROR", e.getMessage()); } } private void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CREDENTIAL_PICKER_REQUEST) { if (resultCode == Activity.RESULT_OK) { handleCredentialResult(data); } else { sendErrorToReactNative("RESULT_NOT_OK", "Result code is not OK"); } } } private void handleCredentialResult(Intent data) { if (data != null) { Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY); if (credential != null) { String phoneNumber = credential.getId(); if (phoneNumber != null) { emitPhoneNumberSelectedEvent(phoneNumber); if (mPromise != null) { mPromise.resolve(phoneNumber); } } else { sendErrorToReactNative("PHONE_NUMBER_NULL", "Phone number is null"); } } else { sendErrorToReactNative("CREDENTIAL_NULL", "Credential is null"); } } else { sendErrorToReactNative("DATA_NULL", "Intent data is null"); } } private void emitPhoneNumberSelectedEvent(String phoneNumber) { if (reactContext != null) { reactContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(EVENT_PHONE_NUMBER_SELECTED, phoneNumber); } } private void sendErrorToReactNative(String code, String message) { if (mPromise != null) { mPromise.reject(code, message); } } }
React Native端代码
useEffect(() => { const subscription = phoneNumberHintModuleEventEmitter.addListener( 'phoneNumberSelected', phoneNumber => { console.log('Received phone number:', phoneNumber); }, ); return () => { subscription.remove(); }; }, []); const handleOpenHint = async () => { try { const phoneNumber = await PhoneNumberHintModule.getPhoneNumberHint(); console.log('Selected phone number:', phoneNumber); } catch (error) { console.error('Error fetching phone number hint:', error); } };
可能的问题及修复方案
1. 静态变量导致的上下文/Promise污染
代码中reactContext和mPromise使用了静态变量,当模块被多次初始化或多组件调用时,会出现上下文覆盖、Promise复用的问题,直接导致回调失效。
- 修复:将静态变量改为实例变量:
// 移除static修饰符 private ReactApplicationContext reactContext; private Promise mPromise;
2. ActivityEventListener注册时机错误
构造函数中注册监听时,Activity可能尚未绑定到ReactContext,导致onActivityResult无法被捕获。
- 修复:通过重载
onHostResume/onHostPause方法,在Activity生命周期节点注册/移除监听:@Override public void onHostResume() { super.onHostResume(); if (getReactApplicationContext() != null) { getReactApplicationContext().addActivityEventListener(activityEventListener); } } @Override public void onHostPause() { super.onHostPause(); if (getReactApplicationContext() != null) { getReactApplicationContext().removeActivityEventListener(activityEventListener); } }
3. Credential解析方式过时
新版Smart Lock API中,直接通过Credential.EXTRA_KEY获取数据可能失效,建议使用HintResult解析返回的Intent:
- 修复:修改
handleCredentialResult方法:private void handleCredentialResult(Intent data) { if (data != null) { try { HintResult hintResult = Credentials.getClient(getReactApplicationContext()).getHintResultFromIntent(data); if (hintResult != null) { String phoneNumber = hintResult.getCredential().getId(); if (phoneNumber != null) { emitPhoneNumberSelectedEvent(phoneNumber); if (mPromise != null) { mPromise.resolve(phoneNumber); mPromise = null; // 清空Promise避免内存泄漏 } } else { sendErrorToReactNative("PHONE_NUMBER_NULL", "Phone number is null"); } } else { sendErrorToReactNative("HINT_RESULT_NULL", "Hint result is null"); } } catch (ApiException e) { e.printStackTrace(); sendErrorToReactNative("API_EXCEPTION", e.getMessage()); } } else { sendErrorToReactNative("DATA_NULL", "Intent data is null"); } }
4. 权限配置缺失
确保AndroidManifest.xml中添加了必要权限,Android 10+还需动态申请部分权限:
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
5. RN端事件发射器初始化错误
确认phoneNumberHintModuleEventEmitter是基于NativeEventEmitter正确创建的:
import { NativeEventEmitter, NativeModules } from 'react-native'; const { PhoneNumberHintModule } = NativeModules; const phoneNumberHintModuleEventEmitter = new NativeEventEmitter(PhoneNumberHintModule);
6. Promise未清空导致内存泄漏
处理完Promise后需主动清空,避免后续调用复用旧Promise:
private void sendErrorToReactNative(String code, String message) { if (mPromise != null) { mPromise.reject(code, message); mPromise = null; // 添加此行 } }
内容的提问来源于stack exchange,提问作者Murshid Ansari
相关产品推荐
相关产品推荐

