Uniapp——安卓与Uniapp数据通信交互

📅 2026/7/8 3:51:27
Uniapp——安卓与Uniapp数据通信交互
原生向Uniapp通信UniApp 安卓自定义基座Android 原生与 UniApp 双向通信完整方案一、先理解几个核心概念1. globalEvent 是什么2. mUniSDKInstance 是哪里来的3. UniModule 和 UniDestroyableModule 区别二、整体通信架构三、完整代码示例1. 全局保存 UniSDKInstanceUniInstanceHolder.java2. 自定义原生插件NativeBridgeModule.java3. Android Activity 主动发送消息NativeActivity.java4. 注册原生插件dcloud_uniplugins.json5. UniApp 页面使用四、为什么 uni.requireNativePlugin(globalEvent) 不会创建 Module 实例五、Activity 里能不能直接用 mUniSDKInstance六、能不能用 EventBus七、重要注意事项1. 必须先监听再发送2. 必须先绑定 mUniSDKInstance3. globalEvent 只适合当前页面4. 不要强引用 UniSDKInstance5. 关键业务数据建议缓存后主动读取八、推荐使用场景九、最终结论参考文档UniApp 安卓自定义基座Android 原生与 UniApp 双向通信完整方案在 UniApp 安卓自定义基座开发中经常会遇到一个需求Android 原生层拿到数据之后如何传给 UniApp 页面同时 UniApp 页面又如何给 Android 原生发送消息比如这些场景原生登录 SDK 回调登录结果原生支付页面返回支付状态Android Activity 处理完业务后通知 UniAppUniApp 页面主动调用 Android 原生能力原生 SDK 异步回调后需要通知前端页面刷新状态本文整理一套比较完整的双向通信方案Android - UniAppglobalEvent fireGlobalEventCallback UniApp - Androiduni.requireNativePlugin 自定义 UniModule 方法需要注意的是globalEvent不是你自己写的原生插件 Module它只是 UniApp JS 侧的内置事件监听对象。真正能拿到mUniSDKInstance的是你自己写的UniModule或UniDestroyableModule。一、先理解几个核心概念1.globalEvent是什么globalEvent是 UniApp App 端内置的全局事件监听对象。UniApp 页面可以这样监听 Android 原生发来的事件constglobalEventuni.requireNativePlugin(globalEvent)globalEvent.addEventListener(native_event,e{console.log(收到 Android 消息,JSON.stringify(e))})但是它只负责 JS 侧监听不会创建你的 Android Module 实例。也就是说uni.requireNativePlugin(globalEvent)拿到的是 DCloud 内置事件监听对象不是你自己的NativeBridgeModule。2.mUniSDKInstance是哪里来的mUniSDKInstance是UniModule父类提供的当前页面实例。只有你的类继承了UniModule或UniDestroyableModule才可以直接使用mUniSDKInstance例如publicclassNativeBridgeModuleextendsUniModule{UniJSMethod(uiThreadtrue)publicvoidsendEvent(){mUniSDKInstance.fireGlobalEventCallback(native_event,params);}}如果代码写在下面这些地方是没有mUniSDKInstance的ActivityApplicationServiceBroadcastReceiver普通工具类SDK回调类这也是很多人找不到mUniSDKInstance的原因。3.UniModule和UniDestroyableModule区别类作用适合场景UniModule普通原生 Module一次性调用、获取数据、打开页面UniDestroyableModule带销毁生命周期的 ModuleEventBus 注册、监听器、定位、蓝牙、SDK 回调等需要释放的场景如果只是简单调用getToken(callback)用UniModule就可以。如果你有EventBus.register(this)BroadcastReceiver注册Handler延迟任务SDK监听回调Dialog/Popup持有Activity建议使用UniDestroyableModule因为它可以在destroy()中释放资源。二、整体通信架构推荐结构如下UniApp 页面 | | uni.requireNativePlugin(NativeBridge) v NativeBridgeModule | | 保存 mUniSDKInstance v UniInstanceHolder | | Activity / SDK 回调调用 fireEvent v mUniSDKInstance.fireGlobalEventCallback(...) | v UniApp globalEvent.addEventListener(...)双向通信关系UniApp - Android nativeBridge.sendMessageToAndroid(params, callback) Android - UniApp mUniSDKInstance.fireGlobalEventCallback(native_event, data) Android - UniApp 页面监听 globalEvent.addEventListener(native_event, callback)三、完整代码示例下面示例实现两个方向UniApp 主动给 Android 发送消息Android Activity 主动给 UniApp 页面发送消息1. 全局保存 UniSDKInstanceUniInstanceHolder.java不要直接用publicstaticUniSDKInstanceinstance;因为UniSDKInstance绑定的是当前页面实例直接静态强引用容易导致页面泄漏、旧页面收到事件、事件发错页面。建议用WeakReferencepackagecom.xxx.uniplugin;importandroid.os.Handler;importandroid.os.Looper;importjava.lang.ref.WeakReference;importjava.util.Map;importio.dcloud.feature.uniapp.UniSDKInstance;publicclassUniInstanceHolder{privatestaticWeakReferenceUniSDKInstanceinstanceRef;publicstaticvoidbind(UniSDKInstanceinstance){instanceRefnewWeakReference(instance);}publicstaticvoidclear(UniSDKInstanceinstance){if(instanceRef!nullinstanceRef.get()instance){instanceRef.clear();instanceRefnull;}}publicstaticvoidfireEvent(StringeventName,MapString,Objectdata){if(instanceRefnull)return;UniSDKInstanceinstanceinstanceRef.get();if(instancenull)return;newHandler(Looper.getMainLooper()).post(()-{instance.fireGlobalEventCallback(eventName,data);});}}2. 自定义原生插件NativeBridgeModule.java这个 Module 负责绑定当前页面的mUniSDKInstance接收 UniApp 发来的消息回调结果给 UniApp测试 Android 主动发送事件给 UniApp页面销毁时清理实例packagecom.xxx.uniplugin;importcom.alibaba.fastjson.JSONObject;importjava.util.HashMap;importjava.util.Map;importio.dcloud.feature.uniapp.annotation.UniJSMethod;importio.dcloud.feature.uniapp.bridge.UniJSCallback;importio.dcloud.feature.uniapp.common.UniDestroyableModule;publicclassNativeBridgeModuleextendsUniDestroyableModule{UniJSMethod(uiThreadtrue)publicvoidbindUniInstance(){UniInstanceHolder.bind(mUniSDKInstance);}UniJSMethod(uiThreadtrue)publicvoidunbindUniInstance(){UniInstanceHolder.clear(mUniSDKInstance);}/** * UniApp 主动给 Android 发送消息 */UniJSMethod(uiThreadtrue)publicvoidsendMessageToAndroid(JSONObjectparams,UniJSCallbackcallback){Stringtypeparams.getString(type);Stringcontentparams.getString(content);android.util.Log.e(NativeBridge,type type);android.util.Log.e(NativeBridge,content content);if(callback!null){JSONObjectresultnewJSONObject();result.put(code,0);result.put(msg,Android 已收到 UniApp 消息);result.put(receiveType,type);result.put(receiveContent,content);callback.invoke(result);}}/** * Android 主动发送事件给 UniApp */UniJSMethod(uiThreadtrue)publicvoidtestSendEventToUniApp(){MapString,ObjectdatanewHashMap();data.put(type,android_event);data.put(msg,这是 Android 主动发送给 UniApp 的消息);UniInstanceHolder.fireEvent(native_event,data);}Overridepublicvoiddestroy(){UniInstanceHolder.clear(mUniSDKInstance);super.destroy();}}3. Android Activity 主动发送消息NativeActivity.java如果你是在 Activity 中拿到了数据比如登录结果、支付结果、页面选择结果可以这样通知 UniApppackagecom.xxx.uniplugin;importandroid.app.Activity;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.Button;importjava.util.HashMap;importjava.util.Map;publicclassNativeActivityextendsActivity{OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);ButtonbuttonnewButton(this);button.setText(发送数据给 UniApp);button.setOnClickListener(newView.OnClickListener(){OverridepublicvoidonClick(Viewview){sendDataToUniApp();}});setContentView(button);}privatevoidsendDataToUniApp(){MapString,ObjectdatanewHashMap();data.put(type,activity_result);data.put(token,abc123);data.put(userId,10001);UniInstanceHolder.fireEvent(native_event,data);}}4. 注册原生插件dcloud_uniplugins.json注意name要和前端的uni.requireNativePlugin(NativeBridge)保持一致。{nativePlugins:[{plugins:[{type:module,name:NativeBridge,class:com.xxx.uniplugin.NativeBridgeModule}]}]}如果是自定义基座需要重新打包自定义基座。5. UniApp 页面使用template view classpage button clicksendToAndroidUniApp 发消息给 Android/button button clickandroidSendToUniApp测试 Android 发消息给 UniApp/button view classtitle结果/view text{{ result }}/text /view /template script const globalEvent uni.requireNativePlugin(globalEvent) const nativeBridge uni.requireNativePlugin(NativeBridge) export default { data() { return { result: } }, onLoad() { // Android - UniApp globalEvent.addEventListener(native_event, e { console.log(收到 Android 主动消息, JSON.stringify(e)) this.result JSON.stringify(e) }) // 绑定当前页面对应的 mUniSDKInstance nativeBridge.bindUniInstance() }, onUnload() { nativeBridge.unbindUniInstance() }, methods: { // UniApp - Android sendToAndroid() { nativeBridge.sendMessageToAndroid( { type: user_click, content: 用户点击了按钮 }, res { console.log(Android 返回, JSON.stringify(res)) this.result JSON.stringify(res) } ) }, // 测试 Android - UniApp androidSendToUniApp() { nativeBridge.testSendEventToUniApp() } } } /script四、为什么uni.requireNativePlugin(globalEvent)不会创建 Module 实例因为globalEvent是 DCloud 内置事件监听模块不是你自己注册的插件。下面这句constglobalEventuni.requireNativePlugin(globalEvent)只是在 JS 侧拿到事件监听对象用来globalEvent.addEventListener(native_event,callback)它不会创建你的NativeBridgeModule真正创建你自定义 Module 的是constnativeBridgeuni.requireNativePlugin(NativeBridge)前提是你已经在dcloud_uniplugins.json中注册{type:module,name:NativeBridge,class:com.xxx.uniplugin.NativeBridgeModule}五、Activity 里能不能直接用mUniSDKInstance不能直接用。因为 Activity 并不继承UniModule所以它没有mUniSDKInstance。错误理解publicclassNativeActivityextendsActivity{// 这里没有 mUniSDKInstance}正确做法UniModule 拿到 mUniSDKInstance ↓ 保存到 UniInstanceHolder ↓ Activity 通过 UniInstanceHolder.fireEvent(...) ↓ UniApp 通过 globalEvent 收到六、能不能用 EventBus可以。但 EventBus 只能解决 Android 原生层内部通信不能直接把数据发到 UniApp JS。正确结构应该是Activity / SDK 回调 ↓ EventBus.post(...) ↓ NativeBridgeModule 接收事件 ↓ mUniSDKInstance.fireGlobalEventCallback(...) ↓ UniApp globalEvent 收到也就是说EventBus 是 Android 内部消息通道globalEvent才是 Android 通知 UniApp 的通道mUniSDKInstance仍然是最终发送事件的关键如果业务是登录结果、支付结果这种“不允许丢”的数据也可以用postSticky或者更稳一点原生先缓存UniApp 页面加载后主动读取。七、重要注意事项1. 必须先监听再发送UniApp 页面必须先执行globalEvent.addEventListener(native_event,callback)然后 Android 再发送fireGlobalEventCallback(native_event,data)如果 Android 发送太早事件会丢。2. 必须先绑定mUniSDKInstance页面加载后要调用nativeBridge.bindUniInstance()否则 Activity 通过UniInstanceHolder.fireEvent(...)时没有可用的页面实例。3.globalEvent只适合当前页面globalEvent是通过当前页面的UniSDKInstance发送事件所以更适合当前页面接收。如果你的 App 有多个页面或者页面切换频繁需要特别注意当前保存的是不是最新页面实例旧页面销毁时有没有清理事件是否可能发给错误页面4. 不要强引用UniSDKInstance不推荐publicstaticUniSDKInstanceinstance;推荐privatestaticWeakReferenceUniSDKInstanceinstanceRef;并在destroy()中清理UniInstanceHolder.clear(mUniSDKInstance);5. 关键业务数据建议缓存后主动读取如果是下面这些数据登录结果支付结果SDK 初始化结果广告归因结果启动参数不建议完全依赖globalEvent。更稳的方式是Android 先缓存数据 ↓ UniApp 页面 onLoad / onShow ↓ 主动调用 nativeBridge.getPendingData(...) ↓ Android 通过 callback 返回数据因为globalEvent有监听时机问题一旦页面没有准备好事件就可能丢。八、推荐使用场景场景推荐方案UniApp 主动调用原生能力NativeBridgeModule UniJSCallbackAndroid 主动通知当前页面globalEvent fireGlobalEventCallbackActivity 给 UniApp 发实时事件UniInstanceHolder globalEventService / SDK 回调通知页面EventBus NativeBridgeModule globalEvent登录、支付等不能丢的数据原生缓存 UniApp 主动读取长时间监听定位、蓝牙、传感器UniDestroyableModule管理生命周期九、最终结论UniApp 安卓自定义基座里原生与 UniApp 双向通信可以这样理解UniApp - Android 调用自定义 NativeBridgeModule 方法 Android - UniApp 通过 mUniSDKInstance.fireGlobalEventCallback 发送 globalEvent Activity 里没有 mUniSDKInstance 需要通过 UniModule 绑定后间接使用最推荐的整体方案是UniApp 页面 addEventListener ↓ UniApp 调 bindUniInstance ↓ UniModule 保存当前 mUniSDKInstance ↓ Activity / SDK 回调通过 Holder 或 EventBus 通知 ↓ UniModule / Holder 调 fireGlobalEventCallback ↓ UniApp 收到事件如果只是实时通知这套方案可以使用。如果是关键业务结果比如登录、支付、归因建议增加一层缓存让 UniApp 主动读取避免事件丢失。参考文档uni.requireNativePlugin 官方文档DCloud Android 原生插件开发文档DCloud UniMP Android 扩展开发文档