当前位置: 首页 > news >正文

uniapp开发蓝牙搜索startBluetoothDevicesDiscovery:fail Location services are turned off

  1. 问题描述
    在使用uniapp开发安卓应用程序时,使用uni.startBluetoothDevicesDiscovery搜索蓝牙时,在部分设备上出现fail Location services are turned off报错(特别是无GPS硬件支持的设备),已确认开启位置信息,且给了权限
  2. 解决方法
    使用安卓原生蓝牙扫描+广播接收实现(借助AI),具体示例代码如下:
    <template> <view class="container"> <view class="status">状态: {{ isScanning ? '正在扫描...' : '停止扫描' }}</view> <button type="primary" @click="startScan" :disabled="isScanning">开始扫描</button> <button type="warn" @click="stopScan" :disabled="!isScanning">停止扫描</button> <view class="list-title">已发现设备:</view> <scroll-view scroll-y="true" class="device-list"> <view v-for="(item, index) in deviceList" :key="index" class="device-item"> <text class="name">{{ item.name || '未知设备' }}</text> <text class="address">{{ item.address }}</text> <text class="rssi">信号: {{ item.rssi }} dBm</text> </view> </scroll-view> </view> </template> <script> // 在这里声明变量,使其在整个组件内可用 let _BluetoothAdapter; let _BluetoothDevice; let _IntentFilter; let _mainActivity; export default { data() { return { isScanning: false, deviceList: [], receiver: null, nativeAdapter: null }; }, onLoad() { // 确保在 plus 环境下初始化 // #ifdef APP-PLUS this.initNativeClasses(); // #endif }, onUnload() { this.stopScan(); this.unregisterReceiver(); }, methods: { // 1. 导入原生类并获取适配器 initNativeClasses() { try { // 导入原生类并赋值给外部变量 _BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter"); _BluetoothDevice = plus.android.importClass("android.bluetooth.BluetoothDevice"); _IntentFilter = plus.android.importClass("android.content.IntentFilter"); _mainActivity = plus.android.runtimeMainActivity(); this.nativeAdapter = _BluetoothAdapter.getDefaultAdapter(); if (!this.nativeAdapter) { uni.showToast({ title: "该设备不支持蓝牙", icon: "none" }); } } catch (e) { console.error("初始化原生类失败", e); } }, // 2. 注册广播接收器 registerReceiver() { if (this.receiver) return; const self = this; // 必须使用 plus.android.implements 实现 BroadcastReceiver 接口 this.receiver = plus.android.implements("io.dcloud.feature.internal.reflect.BroadcastReceiver", { onReceive: function(context, intent) { plus.android.importClass(intent); const action = intent.getAction(); if (action == _BluetoothDevice.ACTION_FOUND) { // 查找到设备 const device = intent.getParcelableExtra(_BluetoothDevice.EXTRA_DEVICE); const rssi = intent.getShortExtra(_BluetoothDevice.EXTRA_RSSI, -100); // 使用 plus.android.invoke 调用原生方法获取属性 const name = plus.android.invoke(device, "getName"); const address = plus.android.invoke(device, "getAddress"); const index = self.deviceList.findIndex(d => d.address === address); if (index === -1) { self.deviceList.push({ name, address, rssi }); } else { self.deviceList[index].rssi = rssi; } } else if (action == _BluetoothAdapter.ACTION_DISCOVERY_FINISHED) { self.isScanning = false; uni.hideLoading(); } } }); const filter = new _IntentFilter(); filter.addAction(_BluetoothDevice.ACTION_FOUND); filter.addAction(_BluetoothAdapter.ACTION_DISCOVERY_FINISHED); _mainActivity.registerReceiver(this.receiver, filter); }, // 3. 开始扫描 async startScan() { if (!this.nativeAdapter) return; // 权限检查 const hasPermission = await this.checkPermission(); if (!hasPermission) return; this.deviceList = []; this.registerReceiver(); // 如果正在扫描,先停止 if (this.nativeAdapter.isDiscovering()) { this.nativeAdapter.cancelDiscovery(); } // 启动原生扫描 const success = this.nativeAdapter.startDiscovery(); if (success) { this.isScanning = true; uni.showLoading({ title: "原生扫描中..." }); } else { uni.showToast({ title: "开启扫描失败", icon: "none" }); } }, // 4. 停止扫描 stopScan() { if (this.nativeAdapter && this.nativeAdapter.isDiscovering()) { this.nativeAdapter.cancelDiscovery(); } this.isScanning = false; uni.hideLoading(); }, unregisterReceiver() { if (this.receiver) { _mainActivity.unregisterReceiver(this.receiver); this.receiver = null; } }, // Android 高版本定位权限申请 checkPermission() { return new Promise((resolve) => { plus.android.requestPermissions( ["android.permission.ACCESS_FINE_LOCATION"], (result) => { if (result.granted.length > 0) resolve(true); else resolve(false); }, (err) => resolve(false) ); }); } } }; </script> <style scoped> .container { padding: 20px; } .status { color: #007AFF; margin-bottom: 10px; font-size: 14px; } .list-title { margin-top: 20px; font-weight: bold; border-bottom: 1px solid #eee; padding-bottom: 5px; } .device-list { height: 400px; } .device-item { padding: 10px 0; border-bottom: 1px solid #f9f9f9; } .name { display: block; font-size: 16px; } .address { font-size: 12px; color: #888; } .rssi { font-size: 12px; color: #007AFF; margin-left: 10px; } button { margin-top: 10px; } </style>
http://www.jsqmd.com/news/963797/

相关文章:

  • 【项目博客】系统核心功能模块开发
  • Windows 11终极瘦身神器:Win11Debloat让你的系统重获新生
  • 如何用Deep-Live-Cam实现实时人脸替换:3步打造专业级视频特效
  • 2026年光身压入式定位珠/压入定位珠/无牙碰珠厂家推荐:滚花定位珠、平台定位珠、台阶定位珠等精密五金定位珠品牌选择指南 - 品牌企业推荐师(官方)
  • BugKu CTF 眼见非实
  • STM32CubeMX实战:独立看门狗IWDG的HAL库喂狗时机与避坑指南(附代码)
  • 2026年AI写作辅助软件深度评测:6款工具全能表现得分排名
  • 2026太原市权威认证贵金属回收 TOP5+黄金回收白银回收铂金回收门店地址电话推荐
  • 拯救MacBook电池健康:3分钟学会用Charge Limiter延长电池寿命
  • 告别熬夜做答辩PPT!百考通AI一站式解决学术汇报制作难题
  • 2026年一键生成论文工具实测排行,哪款真正适合一站式撰稿?
  • 跨网数据安全交换:从“遍地是门”到“一道安检门”
  • 倍硫磷农药残留检测卡快速检测果蔬中的倍硫磷农药残留
  • iOS越狱完整解决方案:从iOS 17到iOS 26.5的终极实战指南
  • 3步诊断法:彻底解决novel-downloader小说下载失败问题
  • ESP8266内存不够用?巧用TFT_eSPI的Sprite类打造流畅动画和复杂UI界面
  • Windows CMD与Powershell常用命令
  • 2026年好用的AI论文工具推荐
  • 株洲黄金回收认准湘奢汇(天元店),拒绝隐形套路省心高效变现(附靠谱机构排行) - 生活测评小能手
  • 2026 掌握选店窍门,轻松锁定成都黄金回收口碑第一的权威实体门店 - 奢侈品回收评测
  • 技术大纲:DeepSeek一键导出word文档的办法
  • 2026台州市权威认证贵金属回收 TOP5+黄金回收白银回收铂金回收门店地址电话推荐
  • AI分发后单平台撤回成功率骤降42%?——基于137个真实案例的CSDN 2024 Q2分发引擎变更影响分析
  • 终极指南:5分钟学会使用uesave编辑Unreal Engine游戏存档
  • 快速掌握OpenRocket:免费火箭设计仿真软件的完整指南
  • 在Photoshop中无缝使用Stable Diffusion:Auto-Photoshop-StableDiffusion-Plugin完全指南
  • 小蜜蜂企微 RPA,把企业微信变成 24 小时不眠的销冠军团
  • 别只看天梯图了!用这套‘需求-预算’匹配法,5分钟搞定你的专属电脑配置单
  • ColorWanted:让Windows屏幕取色变得轻松高效的开源工具
  • 谷歌推广开户多少费用?独立站卖家防坑必看的4大成本