1. 为什么选择uniAPP开发低功耗蓝牙应用?
如果你正在为智能手环、温湿度传感器、智能门锁这类硬件开发一个手机端的控制应用,或者想做一个数据采集工具,那你大概率会面临一个选择:是分别开发安卓和iOS两套原生应用,还是找一个能“一次编写,多端运行”的跨平台方案?我猜,被原生开发那繁琐的环境配置、高昂的学习成本和双倍维护工作量劝退的你,已经把目光投向了uniAPP。没错,用uniAPP来搞蓝牙开发,特别是低功耗蓝牙,这条路我走过,而且走得挺顺。
简单来说,uniAPP基于Vue.js,让你能用熟悉的Web前端技术来写应用,然后编译成小程序、H5、以及安卓和iOS的App。对于蓝牙开发,它最大的优势在于统一了API。安卓和iOS的原生蓝牙API差异不小,光是处理平台兼容性就能让人掉不少头发。而uniAPP把底层差异都封装好了,对外提供了一套完全一致的JavaScript API。这意味着,你只需要写一套蓝牙操作代码,就能同时在两个主流移动平台上运行,省心不是一点半点。
但我也得给你提个醒,跨平台的“省心”是有前提的。它封装了通用操作,但一些平台特有的、底层的、或者非常新的蓝牙特性,可能支持得没那么快或那么细。不过,对于绝大多数智能硬件的数据交互场景——发现、连接、读写数据——uniAPP的蓝牙API已经完全够用,而且相当稳定。我做过好几个项目,从简单的数据透传模块到复杂一点的体征监测设备,用uniAPP这套流程都跑通了。所以,如果你是初学者,或者项目周期紧,想快速验证产品和实现功能,uniAPP的低功耗蓝牙开发绝对是你的首选。
2. 开发前的核心准备:理解BLE与关键概念
在动手敲代码之前,咱们得花点时间把低功耗蓝牙的几个核心概念捋清楚。这就像你要去一个陌生的城市旅行,先看看地图,知道几个关键地标,走起来才不会迷路。别担心,我用最直白的话给你解释。
首先,低功耗蓝牙,也叫BLE,和我们传统手机上连接音箱、耳机的经典蓝牙不一样。它主打一个“省电”,设计目标就是让设备用一颗纽扣电池能工作几个月甚至几年。所以它的通信模式是“间歇性”的:大部分时间在睡觉,需要传数据时才快速醒来发一下,发完接着睡。你的智能手环能一周一充电,靠的就是这个。
在BLE的世界里,一切通信都围绕一个结构清晰的“服务树”展开。你可以把它想象成一家医院:
- 设备:就是这家医院本身,比如你的智能手环。
- 服务:医院里的不同科室,比如“心内科”、“骨科”。每个服务都有一个全球唯一的身份证号,叫做 UUID。例如,电池电量的标准服务UUID是
0x180F。 - 特征值:每个科室里提供的具体项目或数据。比如心内科里的“心率测量”、“心电图数据”。特征值是数据交互的真正出入口,它也有自己的UUID。更重要的是,每个特征值都有一组 属性,定义了你能对它做什么:
read:可以读取这个值(比如读取设备电量)。write:可以往里面写入数据(比如发送一个指令让设备震动)。notify或indicate:设备可以主动通知你数据变化了(比如心率变了,设备会主动“推送”新数据给你)。indicate比notify更可靠,因为它要求客户端回复确认。
- 描述符:可以理解为对特征值的额外说明或配置项,比如配置
notify的开关。
我们开发者的工作流程,其实就是:找到医院(设备) -> 挂号(连接) -> 找到对的科室(服务) -> 找到对的检查项目(特征值) -> 然后根据这个项目的规则(属性),去读取报告(read)或下达医嘱(write),或者订阅报告更新(notify)。
在uniAPP里,我们打交道的主要是deviceId(设备ID)、serviceId(服务UUID)和characteristicId(特征值UUID)。理解了这个模型,后面看代码就不会觉得是一团乱麻了。
3. 第一步:初始化与设备发现
好了,理论热身完毕,咱们打开HBuilderX,开始写代码。第一步,我们要初始化蓝牙模块,并开始搜索周围的设备。这个过程就像打开手机蓝牙设置界面,点击“搜索设备”一样。
首先,我们需要在页面的onLoad生命周期里,设置好几个监听器。这些监听器就像安插好的哨兵,一旦有状态变化,就会主动通知我们。
onLoad() {
// 哨兵1:监听蓝牙适配器状态变化(主要是扫描开关)
uni.onBluetoothAdapterStateChange((res) => {
console.log("蓝牙适配器扫描状态:" + (res.discovering ? "开启" : "关闭"));
this.discovering = res.discovering; // 用一个变量记录状态,方便UI控制
});
// 哨兵2:监听搜索到的设备(这是发现设备的核心回调!)
uni.onBluetoothDeviceFound((res) => {
console.log('发现新设备:', res.devices);
// 这里注意:res.devices是一个数组,每次回调可能返回多个设备
// 通常我们需要过滤出我们关心的设备,比如根据设备名称(name)或广播数据
const newDevices = res.devices.filter(device => {
return device.name && device.name.includes('MyDevice'); // 示例:只关心名字包含MyDevice的设备
});
// 将过滤后的设备加入列表,注意去重(根据deviceId)
this.handleNewDevices(newDevices);
});
// 哨兵3:监听蓝牙连接状态变化
uni.onBLEConnectionStateChange((res) => {
console.log(`设备 ${res.deviceId} 连接状态变为: ${res.connected}`);
this.Connecting = res.connected;
this.deviceId = res.deviceId;
// 这里可以更新UI,比如连接成功显示“已连接”,断开显示“已断开”
});
}
设置好哨兵,接下来就要“打开蓝牙开关”并“开始搜索”了。这里有个关键点:必须先初始化蓝牙适配器,成功后才能进行后续操作。我们封装一个openBluetoothAdapter方法。
// 在methods中
openBluetoothAdapter() {
uni.openBluetoothAdapter({
success: (res) => {
console.log('蓝牙适配器初始化成功');
// 初始化成功,立即开始搜索设备
this.startBluetoothDevicesDiscovery();
// 为了避免一直搜索耗电,我们通常设置一个搜索超时,比如10秒
setTimeout(() => {
this.stopBluetoothDevicesDiscovery();
console.log('已自动停止搜索');
}, 10000);
},
fail: (err) => {
console.error('蓝牙适配器初始化失败:', err);
// 失败原因很多,最常见的是用户手机蓝牙没开
if (err.errCode === 10001) {
uni.showModal({
title: '提示',
content: '请打开手机蓝牙功能',
showCancel: false
});
}
}
});
}
初始化成功后,调用startBluetoothDevicesDiscovery开始搜索。这个API调用后,之前设置的哨兵uni.onBluetoothDeviceFound就会开始源源不断地收到设备信息了。
startBluetoothDevicesDiscovery() {
uni.startBluetoothDevicesDiscovery({
success: (res) => {
console.log('开始搜索设备');
},
fail: (err) => {
console.error('启动搜索失败:', err);
}
});
}


1355

被折叠的 条评论
为什么被折叠?



