Expo构建React Native应用集成Braintree Drop-in UI启动Activity问题求助
方案一:修复Expo模块内启动Braintree Drop-in的逻辑
别在模块里折腾自定义Activity,直接通过React上下文调用Braintree原生Drop-in的启动逻辑:
正确获取当前Activity上下文
模块方法里必须用reactContext.getCurrentActivity()拿当前活跃的Activity,不能用ApplicationContext——启动Activity必须依赖Activity上下文:@ReactMethod public void startBraintreeDropIn(String clientToken, Promise promise) { Activity currentActivity = reactContext.getCurrentActivity(); if (currentActivity == null) { promise.reject("ACTIVITY_NULL", "找不到活跃的Activity"); return; } // 初始化Braintree Drop-in请求 DropInRequest dropInRequest = new DropInRequest() .clientToken(clientToken); // 启动Drop-in UI currentActivity.startActivityForResult(dropInRequest.getIntent(currentActivity), 1001); // 后续需要监听Activity返回结果,把结果回调给RN }注册Activity结果监听
让你的Expo模块实现ActivityEventListener,在onActivityResult里处理Braintree返回的支付结果,再通过Promise传给React Native:@Override public void initialize() { super.initialize(); reactContext.addActivityEventListener(this); } @Override public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { if (requestCode == 1001) { if (resultCode == Activity.RESULT_OK) { DropInResult result = data.getParcelableExtra(DropInResult.EXTRA_DROP_IN_RESULT); String paymentNonce = result.getPaymentMethodNonce().getNonce(); promise.resolve(paymentNonce); } else if (resultCode == Activity.RESULT_CANCELED) { promise.reject("USER_CANCELED", "用户取消了支付"); } else { Exception error = (Exception) data.getSerializableExtra(DropInActivity.EXTRA_ERROR); promise.reject("BRAINTREE_ERROR", error.getMessage()); } } }
方案二:修复自定义Activity的Intent Launcher启动问题
如果非要用自定义Activity,检查以下几个关键点:
AndroidManifest.xml配置要到位
自定义Activity必须正确声明,Android 12+还要加exported="true":<activity android:name=".BraintreeDropInActivity" android:exported="true" android:launchMode="singleTop"> </activity>先预构建再改Manifest
如果你用的是Expo managed workflow,必须先跑npx expo prebuild生成原生目录,再修改android/app/src/main/AndroidManifest.xml——不然修改会被覆盖。Intent的组件名要写全
用Expo Intent Launcher时,组件名必须是应用包名加Activity的完整类名,参数传递格式要对:import * as IntentLauncher from 'expo-intent-launcher'; const startCustomDropIn = async () => { try { await IntentLauncher.startActivityAsync('com.your.app.package.BraintreeDropInActivity', { clientToken: '你的Braintree客户端令牌', }); } catch (e) { console.error('启动Activity失败:', e); } };自定义Activity内正确初始化Braintree
在onCreate里拿到Intent传的参数,直接启动Braintree Drop-in:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String clientToken = getIntent().getStringExtra("clientToken"); DropInRequest dropInRequest = new DropInRequest().clientToken(clientToken); startActivityForResult(dropInRequest.getIntent(this), 1002); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1002) { // 处理支付结果,用EventEmitter把数据发回RN finish(); // 处理完关闭自定义Activity } }
额外注意事项
- 确保
android/app/build.gradle里加了Braintree依赖:dependencies { implementation 'com.braintreepayments.api:drop-in:6.+' } - Expo managed workflow要保证
app.json里的android.package和原生目录的包名一致,不然Intent会找不到组件。 - 尽量用真机测试,部分模拟器可能和Braintree SDK不兼容。
内容的提问来源于stack exchange,提问作者Alex Aelenei

