1. 混合开发背景与核心需求
在移动应用开发领域,混合开发已经成为平衡开发效率与性能体验的主流方案。uni-app作为基于Vue.js的跨平台框架,允许开发者使用同一套代码构建iOS、Android以及各种小程序应用。但当我们需要访问设备原生功能(如蓝牙、摄像头、传感器等)或复用现有Java/Kotlin代码时,就必须掌握uni-app与Android原生交互的技术方案。
实际开发中常见的三种典型场景:
- 需要调用Android特有的硬件API(如NFC读写)
- 复用企业现有的Java业务逻辑模块
- 实现uni-app难以处理的高性能计算任务
2. 方案一:通过UniModule扩展原生能力
这是DCloud官方推荐的标准化方案,适合需要长期维护的中大型项目。
2.1 环境准备与项目配置
- 在Android Studio中创建原生模块:
public class MyNativeModule extends UniModule { @UniJSMethod(uiThread = true) public void showToast(String message) { Toast.makeText(mUniSDKInstance.getContext(), message, Toast.LENGTH_SHORT).show(); } }- 注册模块到uni-app工程:
// 在build.gradle中添加 dependencies { implementation 'com.github.dcloudio:uni-app-android-sdk:3.6.12' } // 在assets/dcloud_uniplugins.json中注册 { "nativeModules": [ { "class": "com.example.MyNativeModule", "name": "myNative" } ] }2.2 前端调用与参数传递
// 获取模块实例 const nativeModule = uni.requireNativePlugin('myNative') // 调用原生方法 nativeModule.showToast('Hello from JS!') // 复杂参数传递示例 nativeModule.processData({ id: 1001, items: ['a', 'b'], config: { timeout: 5000 } })关键提示:UniModule默认运行在UI线程,耗时操作需自行创建子线程。返回Promise需使用@UniJSMethod(uiThread = false)注解。
3. 方案二:WebView JavaScript Bridge通信
适合已有H5页面需要快速集成到Android应用的场景。
3.1 Android端桥接实现
webView.settings.javaScriptEnabled = true webView.addJavascriptInterface(object { @JavascriptInterface fun getDeviceInfo(): String { return JSONObject().apply { put("model", Build.MODEL) put("sdk", Build.VERSION.SDK_INT) }.toString() } }, "AndroidBridge")3.2 uni-app侧调用适配
// 判断运行环境 function callNative(method, params) { if (uni.getSystemInfoSync().platform === 'android') { return new Promise((resolve) => { const callback = `callback_${Date.now()}` window[callback] = (data) => { resolve(JSON.parse(data)) delete window[callback] } const script = `AndroidBridge.${method}(${JSON.stringify(params)}, ${callback})` const iframe = document.createElement('iframe') iframe.style.display = 'none' iframe.src = `javascript:${script}` document.body.appendChild(iframe) setTimeout(() => iframe.remove(), 1000) }) } return Promise.reject('Not in Android environment') }4. 方案三:URL Scheme与Intent跳转
适用于简单指令传递和第三方应用调起的场景。
4.1 AndroidManifest配置
<activity android:name=".SchemeActivity"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="uniandroid" android:host="command"/> </intent-filter> </activity>4.2 双向通信实现
Android端:
protected void onCreate(Bundle savedInstanceState) { Uri uri = getIntent().getData(); if (uri != null) { String action = uri.getQueryParameter("action"); if ("vibrate".equals(action)) { Vibrator vibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE); vibrator.vibrate(500); } } }uni-app端:
function sendCommand(command, params) { const query = new URLSearchParams(params).toString() window.location.href = `uniandroid://command/?action=${command}&${query}` // 回传结果监听 document.addEventListener('resume', () => { const result = plus.android.getResult() console.log('Native response:', result) }) }5. 方案对比与性能优化
5.1 三种方案特性对比
| 特性 | UniModule | JS Bridge | URL Scheme |
|---|---|---|---|
| 执行效率 | ★★★★★ | ★★★☆☆ | ★★☆☆☆ |
| 开发复杂度 | ★★★☆☆ | ★★☆☆☆ | ★☆☆☆☆ |
| 双向通信支持 | 完整支持 | 需要适配 | 有限支持 |
| 数据类型支持 | 丰富 | 需序列化 | 仅字符串 |
| 适用场景 | 高频复杂交互 | 简单方法调用 | 应用间通信 |
5.2 性能优化实践
- 线程管理:将CPU密集型操作放在Native线程,通过回调返回结果
@UniJSMethod(uiThread = false) public void heavyCompute(String params, UniJSCallback callback) { new Thread(() -> { String result = doCompute(params); callback.invoke(result); }).start(); }- 批量调用:减少跨语言调用次数
// 不推荐 for (let i = 0; i < 100; i++) { nativeModule.updateItem(i, data[i]) } // 推荐 nativeModule.batchUpdate({ items: data.map((item, index) => ({id: index, data: item})) })- 内存优化:及时释放Native对象引用
@Override public void onDestroy() { releaseResources(); // 释放native资源 super.onDestroy(); }6. 常见问题排查指南
6.1 方法未找到错误
- 检查模块是否正确注册到dcloud_uniplugins.json
- 确认方法添加了@UniJSMethod注解
- 清理项目重新编译(Android Studio的Build > Clean Project)
6.2 数据类型转换异常
- Android端处理JSON的推荐方式:
@UniJSMethod public void handleComplexData(JSONObject params) { String name = params.optString("name"); JSONArray items = params.optJSONArray("items"); // ... }- uni-app侧类型提示(Vue3 + TypeScript):
interface NativeBridge { showToast(message: string): void; processData(params: {id: number; items: string[]}): Promise<{code: number}>; } const bridge = uni.requireNativePlugin('myNative') as NativeBridge6.3 调试技巧
- Android Logcat过滤标签:
adb logcat -s UniJSService - 开启uni-app调试模式:
// main.js uni.setEnableDebug({ enableDebug: true })- 使用Chrome远程调试WebView:
adb forward tcp:9222 localabstract:webview_devtools_remote_<pid>7. 进阶开发模式
7.1 事件监听机制
Android端发送事件:
mUniSDKInstance.fireGlobalEventCallback("nativeEvent", new JSONObject().put("type", "dataUpdate").toString());uni-app端监听:
uni.onNativeEventReceive((event) => { console.log('Received:', event.type) })7.2 插件化扩展
开发可复用的原生插件:
- 创建独立Android Library模块
- 实现UniModule接口
- 打包为aar文件
- 发布到私有Maven仓库或直接引用
7.3 性能关键路径优化
- 使用ByteBuffer传输二进制数据
- 建立长连接通道替代频繁调用
- 预加载常用Native模块
// 在Application初始化时预加载 UniSDKEngine.preLoadModule(MyNativeModule.class);在实际项目开发中,我们通常会根据功能特性混合使用多种方案。比如核心业务逻辑采用UniModule保证性能,辅助功能使用JS Bridge快速实现,而深度链接则通过URL Scheme处理。这种分层架构既能满足性能要求,又能保持开发效率