UNIAPP 蓝牙权限实战:Android 12+ 与鸿蒙系统适配全解析

张开发
2026/4/13 5:21:39 15 分钟阅读

分享文章

UNIAPP 蓝牙权限实战:Android 12+ 与鸿蒙系统适配全解析
1. 为什么Android 12和鸿蒙需要特殊适配最近在开发一个跨平台的智能家居控制应用时遇到了一个棘手的问题很多用户反馈在Android 12及以上版本的手机上无法正常连接蓝牙设备。经过排查发现这其实是Android 12引入的新权限机制导致的。而鸿蒙系统虽然兼容Android应用但在权限管理上也有自己的特点。Android 12对蓝牙权限做了更细粒度的划分新增了BLUETOOTH_CONNECT权限。这个变化让很多开发者措手不及因为之前的代码在Android 11及以下版本运行良好但到了Android 12就突然失效了。我刚开始也踩了这个坑调试了半天才发现问题所在。鸿蒙系统的情况稍微复杂些。虽然它支持Android应用但在权限管理上有些细微差别。比如在某些鸿蒙设备上即使已经授权了蓝牙权限系统仍然会弹出二次确认对话框。这就需要我们在代码中做额外的兼容处理。2. 基础权限配置全攻略2.1 manifest文件配置首先要在项目的manifest.json文件中正确配置权限。很多开发者容易忽略这一步导致后续的权限请求根本不会生效。我在实际项目中遇到过好几次因为漏配权限导致的bug调试起来特别费时间。对于UNIAPP项目需要在app-plus - distribute - android - permissions节点下添加以下配置{ permissions: [ uses-permission android:name\android.permission.BLUETOOTH_SCAN\/, uses-permission android:name\android.permission.BLUETOOTH_CONNECT\/, uses-permission android:name\android.permission.ACCESS_FINE_LOCATION\/ ] }这里有几个关键点需要注意BLUETOOTH_CONNECT是Android 12新增的权限用于控制蓝牙连接BLUETOOTH_SCAN用于蓝牙设备扫描ACCESS_FINE_LOCATION在部分设备上仍然是必需的2.2 动态权限请求时机配置好manifest只是第一步更重要的是在运行时动态请求权限。根据我的经验最佳的请求时机是在用户首次尝试使用蓝牙功能时。过早请求可能会让用户感到困惑过晚则会影响用户体验。在UNIAPP中我们可以使用plus.android.requestPermissions方法来请求权限。但要注意这个方法在不同平台上的表现可能不一致。特别是在鸿蒙系统上建议在页面onLoad时就先检查权限状态而不是等到用户操作时才检查。3. 权限请求的完整实现方案3.1 检查权限状态在实际开发中我发现很多开发者直接请求权限而不先检查当前状态这会导致不好的用户体验。正确的做法应该是先检查权限状态根据不同的状态采取不同的策略。下面是一个完整的权限检查函数我在多个项目中都使用过这个方案function checkBluetoothPermission() { return new Promise((resolve, reject) { const permissions [ android.permission.BLUETOOTH_SCAN, android.permission.BLUETOOTH_CONNECT, android.permission.ACCESS_FINE_LOCATION ]; plus.android.requestPermissions(permissions, (e) { if (e.granted.length permissions.length) { resolve(true); } else if (e.deniedPresent.length 0) { // 权限被临时拒绝 this.showPermissionRequestDialog(); resolve(false); } else if (e.deniedAlways.length 0) { // 权限被永久拒绝 this.showGoToSettingsDialog(); resolve(false); } }, (err) { console.error(权限检查出错:, err); reject(err); }); }); }3.2 处理用户拒绝的情况用户拒绝权限是很常见的情况我们需要妥善处理。根据我的经验大约有30%的用户会在首次请求时拒绝权限。这时候我们需要做好两件事解释为什么需要这个权限提供简单的方式让用户可以重新授权我通常会在用户拒绝后显示一个友好的对话框function showPermissionRequestDialog() { uni.showModal({ title: 需要蓝牙权限, content: 使用蓝牙功能需要您授予相关权限否则无法连接设备, confirmText: 去授权, success: (res) { if (res.confirm) { this.checkBluetoothPermission(); } } }); }对于永久拒绝的情况则需要引导用户去系统设置中手动开启权限function showGoToSettingsDialog() { uni.showModal({ title: 权限被禁用, content: 您已永久拒绝蓝牙权限请前往设置中手动开启, confirmText: 打开设置, success: (res) { if (res.confirm) { plus.runtime.openSettings(); } } }); }4. 鸿蒙系统的特殊处理4.1 鸿蒙的权限特性鸿蒙系统虽然兼容Android应用但在权限管理上有一些特殊之处。根据我的测试鸿蒙系统在以下方面表现不同权限对话框可能会弹出两次某些设备上位置权限是必须的即使只是用蓝牙权限状态检查的返回值可能不一致针对这些差异我们需要在代码中做特殊处理。我建议在鸿蒙设备上增加额外的权限检查function isHarmonyOS() { try { const buildClass plus.android.importClass(android.os.Build); return buildClass.HARMONY.equals(buildClass.MANUFACTURER); } catch (e) { return false; } } if (isHarmonyOS()) { // 鸿蒙特殊处理 this.checkHarmonyPermission(); }4.2 鸿蒙最佳实践经过多次尝试我总结出了在鸿蒙系统上处理蓝牙权限的最佳实践在应用启动时就检查蓝牙权限状态对于位置权限即使不使用时也建议请求处理权限回调时要考虑鸿蒙的特殊情况测试时要用真实的鸿蒙设备模拟器可能表现不同下面是一个针对鸿蒙优化的权限检查函数function checkHarmonyPermission() { const permissions [ android.permission.BLUETOOTH_SCAN, android.permission.BLUETOOTH_CONNECT, android.permission.ACCESS_FINE_LOCATION, android.permission.ACCESS_COARSE_LOCATION ]; // 鸿蒙需要先检查权限状态 plus.android.requestPermissions(permissions, (e) { if (e.granted.length permissions.length) { // 在鸿蒙上可能需要二次请求 setTimeout(() { plus.android.requestPermissions(permissions); }, 300); } }); }5. 调试技巧与常见问题5.1 真机调试要点在调试蓝牙权限相关问题时真机调试是必不可少的。根据我的经验以下技巧可以帮助你更快定位问题使用adb命令查看权限状态adb shell pm list permissions -g在开发者选项中启用权限使用情况监控使用logcat过滤权限相关日志adb logcat | grep -i permission测试时要注意清除应用的权限状态模拟首次使用场景一个实用的调试技巧是在代码中加入详细的日志记录function logPermissionState() { const context plus.android.importClass(android.content.Context); const pm plus.android.runtimeMainActivity().getPackageManager(); const packageName plus.android.runtimeMainActivity().getPackageName(); const bluetoothConnect pm.checkPermission( android.permission.BLUETOOTH_CONNECT, packageName ); console.log(BLUETOOTH_CONNECT权限状态:, bluetoothConnect context.PERMISSION_GRANTED ? 已授权 : 未授权); }5.2 常见问题解决方案在实际开发中我遇到过不少关于蓝牙权限的疑难杂症这里分享几个典型问题的解决方法问题1权限请求没有弹出对话框解决方案检查manifest配置是否正确确保targetSdkVersion31问题2在鸿蒙设备上权限被重复请求解决方案增加防抖处理确保不会在短时间内多次请求问题3某些设备上即使授权了也无法使用蓝牙解决方案检查是否缺少位置权限有些厂商设备需要位置权限问题4权限回调不执行解决方案确保没有其他模态窗口阻挡尝试在主线程执行权限请求下面是一个综合性的权限处理函数解决了很多常见问题async function handleBluetoothPermission() { try { const hasPermission await this.checkBluetoothPermission(); if (!hasPermission) return false; // 额外检查鸿蒙设备 if (this.isHarmonyOS()) { await this.checkHarmonyPermission(); } // 最终确认 const finalCheck await this.checkBluetoothPermission(); if (!finalCheck) { uni.showToast({ title: 无法使用蓝牙功能, icon: none }); return false; } return true; } catch (error) { console.error(处理蓝牙权限出错:, error); return false; } }在实际项目中我发现把这些权限处理逻辑封装成一个独立的模块会大大提升代码的可维护性。建议创建一个permissionHelper.js文件集中管理所有权限相关的逻辑。这样不仅方便复用也便于后续维护和更新。

更多文章