当前位置: 首页 > 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.cnnetsun.cn/news/2796342.html

相关文章:

  • 小小屠龙 - 冰雪骑战手游官网下载:小小屠龙冰雪骑战最新官方下载渠道
  • FlowGame 从零上手:开源 AI 工作流编排框架与 Vue 3 接入实战
  • 分享一个免费下载全行业报告的宝藏网站,职场人亲测好用
  • 告别裸奔!用CubeMX+Keil给STM32F407装上RTX5实时系统(保姆级图文教程)
  • 抖音视频下载终极指南:douyin-downloader完整解决方案
  • 电脑主板装配线防静电配置标准 7 年实测经验分享
  • 快马平台一键生成c语言文件读写原型,告别手动编码繁琐流程
  • AI赋能CNN创新:让快马平台智能生成集成注意力机制的先进模型代码
  • # 别再自己啃协议了!用 RESTful API 和 Webhook 搞定个人微信自动化接入
  • 老网站收录差就重构?这是一种技术惰性。聊聊我们是如何用3个月盘活存量站点的
  • 还在为升降设备的维护成本高而烦恼?丝杆升降机给您答案。
  • FastGithub 3分钟极速指南:让你的GitHub访问体验飞起来
  • Python转Java系列:环境搭建与项目结构
  • LinkSwift网盘直链下载助手:3分钟实现高速下载自由的终极指南
  • 医疗废水处理的进步你看到了吗?
  • IDM激活脚本实战指南:30天试用期无限续期的实用解决方案
  • 2026年智能门锁质量选购指南:国内TOP3品牌实测对比与行业趋势解析
  • 流式输出:让 Agent 的回答边生成边显示,前端到底怎么接
  • LangGraph多智能体系统实战:监督者架构旅行规划全链路
  • 采集的数据可以自动上传到企业网盘吗?全景技术路径解析与2026选型指南
  • QT自定义控件之热换站远程监控系统
  • 从零到一:手把手教你用PyTorch Geometric实现GraphSAGE(附完整代码)
  • 基于清洁架构的Unitree Go2机器人ROS2 SDK:解决实时多模态数据同步与分布式控制的技术实践
  • macOS光标定制终极指南:Mousecape深度解析与实战教程
  • 商务科技:数字化转型如何重塑企业竞争力
  • STM8S开发实战:STVD自动生成HEX与BIN文件全攻略
  • 论文解读--BEV-radar:: bidirectional radar-camera fusion for 3D object detection
  • N皇后问题的遗传算法Python实战:从原理到可调试工程实现
  • Windows系统字体个性化指南:使用No!! MeiryoUI恢复字体自定义功能
  • 终极指南:如何用DeTikZify 3分钟生成专业LaTeX图表