Cordova插件callbackContext.success无法返回至调用应用求助
我之前开发Cordova插件对接第三方aar SDK时,也碰到过几乎一模一样的回调失效问题,结合你的流程来看,主要问题大概率出在线程调度或者回调上下文的生命周期管理上,咱们一步步来排查解决:
1. 核心问题:回调必须在Cordova主线程执行
Cordova的callbackContext相关方法(比如success())不是线程安全的,必须在WebView所在的主线程(也就是Cordova Activity的主线程)调用才会生效。而BroadcastReceiver的onReceive()方法不一定是在主线程执行的,直接在这里调用回调就会导致数据无法传回前端。
解决办法:
用cordova.getActivity().runOnUiThread()把回调逻辑包裹起来,确保在主线程执行:
@Override public void onReceive(Context context, Intent intent) { // 从SDK广播的Intent中取出结果数据 String sdkResult = intent.getStringExtra("your_result_key"); // 切换到Cordova主线程执行回调 cordova.getActivity().runOnUiThread(new Runnable() { @Override public void run() { // 这里调用success才会正确传回前端 savedCallbackContext.success(sdkResult); // 回调完成后记得注销广播接收器,避免内存泄漏 cordova.getActivity().unregisterReceiver(this); } }); }
2. 避免回调上下文被提前回收
如果你的插件execute()方法执行完后,没有保存callbackContext的引用,当广播触发时,这个上下文可能已经被GC回收了,自然无法触发回调。
解决办法:
在插件类中把callbackContext作为成员变量保存:
public class ExternalScreenPlugin extends CordovaPlugin { // 保存回调上下文,避免被回收 private CallbackContext savedCallbackContext; // 广播接收器实例 private BroadcastReceiver sdkResultReceiver; @Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { if ("launchExternalScreen".equals(action)) { // 保存回调上下文 this.savedCallbackContext = callbackContext; // 动态注册广播接收器(一定要动态注册,静态注册拿不到回调引用) IntentFilter filter = new IntentFilter("com.your.sdk.BROADCAST_ACTION"); sdkResultReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 这里处理广播数据并回调 handleSdkResult(intent); } }; cordova.getActivity().registerReceiver(sdkResultReceiver, filter); // 启动SDK的Activity Intent sdkIntent = new Intent(cordova.getActivity(), SDKMainActivity.class); cordova.getActivity().startActivity(sdkIntent); // 返回true表示插件将异步返回结果 return true; } return false; } private void handleSdkResult(Intent intent) { String result = intent.getStringExtra("result_data"); // 切换主线程回调 cordova.getActivity().runOnUiThread(() -> { savedCallbackContext.success(result); // 注销广播 cordova.getActivity().unregisterReceiver(sdkResultReceiver); }); } }
3. 排查广播是否正常触发
有时候看起来是回调没生效,其实是广播根本没传到插件这里。可以在onReceive()里加日志确认:
Log.d("ExternalScreenPlugin", "收到SDK广播:" + intent.getAction()); Log.d("ExternalScreenPlugin", "返回数据:" + intent.getStringExtra("result_data"));
然后通过adb logcat | grep ExternalScreenPlugin查看日志,确认广播是否被正确接收、数据是否存在。
4. 不要混淆sendPluginResult和success()
如果你的需求是只返回一次结果,直接用callbackContext.success()就足够了。只有当需要多次返回结果时,才需要用sendPluginResult()并设置keepCallback=true,比如:
// 多次回调场景才需要这么写 PluginResult result = new PluginResult(PluginResult.Status.OK, partialData); result.setKeepCallback(true); savedCallbackContext.sendPluginResult(result);
如果误用了sendPluginResult却没设置正确的参数,也可能导致前端收不到回调。
最后总结
优先检查线程调度和回调上下文保存这两点,这是Cordova插件异步回调失效的最常见原因。如果还是不行,再排查广播的Action是否匹配、Intent数据是否正确。
内容的提问来源于stack exchange,提问作者jr_jr

