别再为Uniapp原生插件头疼了!手把手教你从零封装一个获取设备信息的Android插件(附完整源码)

张开发
2026/5/3 17:08:29 15 分钟阅读
别再为Uniapp原生插件头疼了!手把手教你从零封装一个获取设备信息的Android插件(附完整源码)
从零构建Uniapp Android原生插件设备信息获取实战指南如果你已经熟悉Uniapp的基础开发却对原生插件开发望而却步这篇文章将彻底改变你的认知。我们将通过一个完整的设备信息插件案例拆解Android原生插件开发的全流程让你体验从Java代码到JavaScript调用的无缝衔接。1. 环境准备与项目初始化在开始编码前需要确保开发环境配置正确。不同于纯前端开发原生插件开发需要Android Studio和Uniapp开发环境协同工作。必备工具清单Android Studio 2022HBuilderX 3.7Java JDK 11Uniapp离线SDK创建插件项目时建议采用以下目录结构DeviceInfoPlugin/ ├── android/ │ ├── build.gradle │ ├── src/ │ │ └── main/ │ │ ├── java/ │ │ └── res/ ├── package.json └── README.md在package.json中定义插件基本信息{ name: DeviceInfoPlugin, id: com.yourcompany.deviceinfo, version: 1.0.0, description: 获取设备信息的原生插件, _dp_type: nativeplugin, _dp_nativeplugin: { android: { plugins: [ { type: module, name: DeviceInfo, class: com.yourcompany.deviceinfo.DeviceInfoModule } ] } } }2. Android原生模块开发核心功能实现在Java层我们需要创建一个继承自UniModule的类。这个类将作为JavaScript与原生代码交互的桥梁。package com.yourcompany.deviceinfo; import android.content.Context; import android.os.Build; import android.provider.Settings; import com.alibaba.fastjson.JSONObject; import io.dcloud.feature.uniapp.annotation.UniJSMethod; import io.dcloud.feature.uniapp.common.UniModule; public class DeviceInfoModule extends UniModule { UniJSMethod(uiThread false) public JSONObject getDeviceInfo() { JSONObject info new JSONObject(); try { Context context mUniSDKInstance.getContext(); info.put(manufacturer, Build.MANUFACTURER); info.put(model, Build.MODEL); info.put(osVersion, Build.VERSION.RELEASE); info.put(androidId, Settings.Secure.getString( context.getContentResolver(), Settings.Secure.ANDROID_ID)); info.put(sdkVersion, Build.VERSION.SDK_INT); info.put(screenWidth, mUniSDKInstance.getContext() .getResources().getDisplayMetrics().widthPixels); info.put(screenHeight, mUniSDKInstance.getContext() .getResources().getDisplayMetrics().heightPixels); } catch (Exception e) { e.printStackTrace(); } return info; } }关键点解析UniJSMethod注解标记了可供JavaScript调用的方法uiThread false表示该方法在工作线程执行通过mUniSDKInstance可以获取应用上下文返回类型使用JSONObject确保数据可序列化3. 插件集成与调试完成Java代码编写后需要将插件集成到Uniapp项目中测试。集成步骤将插件目录复制到项目的nativeplugins文件夹在manifest.json中添加插件声明app-plus: { plugins: { DeviceInfoPlugin: { version: 1.0.0, provider: com.yourcompany } } }制作自定义调试基座在HBuilderX中选择运行→制作自定义调试基座勾选你的插件等待编译完成在页面中调用插件const deviceInfo uni.requireNativePlugin(DeviceInfo-DeviceInfo); export default { data() { return { deviceData: null } }, mounted() { this.getDeviceInfo(); }, methods: { getDeviceInfo() { const info deviceInfo.getDeviceInfo(); console.log(设备信息:, info); this.deviceData info; } } }4. 高级功能与优化技巧基础功能实现后我们可以进一步优化插件的性能和稳定性。4.1 权限动态申请某些设备信息需要运行时权限我们可以增强插件的权限处理能力。UniJSMethod(uiThread true) public void requestDeviceInfo(Promise promise) { if (ContextCompat.checkSelfPermission(mUniSDKInstance.getContext(), Manifest.permission.READ_PHONE_STATE) ! PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(mUniSDKInstance.getContext(), new String[]{Manifest.permission.READ_PHONE_STATE}, 1001); promise.reject(PERMISSION_DENIED, 需要READ_PHONE_STATE权限); } else { promise.resolve(getDeviceInfo()); } }4.2 性能优化建议减少跨语言调用单次调用返回完整数据避免多次小数据量调用复杂数据使用JSON格式传输线程管理UI相关操作必须在主线程执行耗时操作放在工作线程内存优化避免在回调中持有Activity引用及时释放原生资源4.3 错误处理机制完善的错误处理能让插件更健壮。我们可以在Java层定义错误码public class PluginErrors { public static final int PERMISSION_DENIED 1001; public static final int FEATURE_NOT_SUPPORTED 1002; public static final int UNKNOWN_ERROR 9999; } UniJSMethod public void getBatteryLevel(Promise promise) { try { IntentFilter ifilter new IntentFilter(Intent.ACTION_BATTERY_CHANGED); Intent batteryStatus mUniSDKInstance.getContext() .registerReceiver(null, ifilter); if (batteryStatus null) { JSONObject error new JSONObject(); error.put(code, PluginErrors.FEATURE_NOT_SUPPORTED); error.put(message, 电池信息不可用); promise.reject(error); return; } int level batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int scale batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); float batteryPct level * 100 / (float)scale; JSONObject result new JSONObject(); result.put(level, batteryPct); result.put(status, batteryStatus.getIntExtra( BatteryManager.EXTRA_STATUS, -1)); promise.resolve(result); } catch (Exception e) { promise.reject(UNKNOWN_ERROR, e.getMessage()); } }5. 插件打包与发布开发完成后你可能需要将插件分享给团队或发布到市场。打包注意事项压缩插件目录为zip文件包含完整的文档说明注明兼容的Uniapp版本提供示例项目发布流程登录DCloud开发者中心进入插件管理页面上传插件包并填写相关信息等待审核通过对于企业内部分享可以直接提供插件目录其他开发者只需将插件放入项目的nativeplugins目录在manifest.json中配置重新制作自定义调试基座6. 实战中的经验分享在实际项目开发中有几个关键点值得特别注意版本兼容性不同Uniapp版本对原生插件的支持可能有差异建议在插件文档中明确说明兼容的版本范围。日志输出在Android Studio的Logcat中过滤uniPlugin可以查看插件相关的日志输出调试时非常有用。异步处理对于耗时操作务必使用异步回调避免阻塞JavaScript线程。数据类型转换JavaScript和Java之间的数据类型转换需要特别注意基本类型可以直接映射复杂对象需要序列化为JSON二进制数据建议使用Base64编码插件热更新虽然原生代码不能热更新但可以通过设计插件配置化来部分实现动态调整功能。// 示例从服务器加载配置 UniJSMethod public void fetchConfig(String url, Promise promise) { new Thread(() - { try { URL configUrl new URL(url); HttpURLConnection conn (HttpURLConnection) configUrl.openConnection(); InputStream in conn.getInputStream(); String config readStream(in); promise.resolve(JSON.parseObject(config)); } catch (Exception e) { promise.reject(FETCH_ERROR, e.getMessage()); } }).start(); }开发过程中遇到问题时可以优先检查以下几个方面插件是否被正确打包到APK中方法名和参数类型是否匹配是否有必要的权限声明控制台日志中的错误信息

更多文章