前言:
微信小程序目前只支持低功耗蓝牙(BLE),文档中的两套API是可以混合使用的,请大家不用再去社区问这些问题了。
微信的文档 已经很详细了,不懂的主要是流程,本文主要介绍流程,通信。
demo请戳:https://github.com/webwjg/blueTooth.git
1.GPS
安卓手机需要GPS才能搜索到蓝牙设备,所以需要提醒用户开启GPS,在进入页面就先获取获取用户信息,判断是否开启GPS,然后提示用户
片段1:
data: {
devicesList:[], //渲染数组(蓝牙设备列表)
isHideList:true, //是否隐藏蓝牙列表
isHideConnect:false, //是否隐藏连接模块
deviceId:'', // 设备id
connectName:'', //连接的蓝牙名称
writeNews:{
}, //写数据三个id
queryData:{
//要写的16进制数组
query:[0x02,0x09,0x00,0x01,0x6A,0x00,0x50,0x06],
stateTest:[0x01,0x08,0x02,0x00,0x56,0x00,0x59,0x06],
},
},
onLoad: function(options) {
let that=this;
wx.getSystemInfo({
success (res) {
console.log(res);
let gps=res.locationEnabled;
if(!gps){
wx.showModal({
title: '请打开GPS定位',
content: '不打开GPS定位,可能无法搜索到蓝牙设备',
showCancel: false
})
}else{
that.openBluetoothAdapter(); //初始化蓝牙模块
}
}
})
},
2.初始化蓝牙模块(wx.openBluetoothAdapter)
蓝牙API都必须初始化之后才能调用。初始化之后需要调用监听蓝牙适配器状态变化事件(wx.onBluetoothAdapterStateChange),如果中途蓝牙适配器状态发生变化,可以提示用户
片段2:
openBluetoothAdapter(){
wx.openBluetoothAdapter({
success (res) {
that.setData({
isOpen:true});
wx.onBluetoothAdapterStateChange(function (res) {
if(!res.available){
//蓝牙适配器是否可用
wx.showModal({
title: '温馨提示',
content: '蓝牙蓝牙适配器不可用,请重新启动',
showCancel: false
})
}
})
that.searchBlue(); //开始搜索蓝牙
},
fail(res){
wx.showToast({
title: '请检查手机蓝牙是否打开',
icon:'none',
})
},
})
},
3.搜索蓝牙设备(wx.startBluetoothDevicesDiscovery)
适配器打开之后就可以搜索蓝牙设备了,startBluetoothDevicesDiscovery就是开始搜索的API,搜索比较耗费资源,连接蓝牙之后不要忘记调用wx.stopBluetoothDevicesDiscovery结束搜索。这步和下一步是一起的,下步上代码。
4.获取蓝牙设备的信息(wx.getBluetoothDevices)
这步就可以获取到蓝牙列表数组,其中包含蓝牙设备的名称(name),设备id(deviceId),还有信号强度(RSSI)等,我们拿到信息数组就可以把蓝牙列表渲染出来了,
上图就是返回的数组
片段3:
searchBlue(){
let that=this;
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
success (res) {
console.log(res);
wx.showLoading({
title: '正在搜索设备',});
wx.getBluetoothDevices({
success: function(res) {
console.log(res);
let devicesListArr=[];
if(res.devices.length>0){
//如果有蓝牙设备就把蓝牙信息放到渲染列表里面
wx.hideLoading();
res.devices.forEach(device=>{
if (!device.name && !device.localName) {
return
}else{
devicesListArr.push(device); //渲染数组
}
})
that.setData({
devicesList:devicesListArr,isHideList:false}); //渲染到页面中
}else{
wx.hideLoading();
wx.showModal({
title: '温馨提示',
content: '无法搜索到蓝牙设备,请打开GPS重新尝试',
showCancel: false
});
wx.closeBluetoothAdapter({
success (res) {
console.log(res)
}
})
}
}
})
},
fail: function(res) {
wx.showToast({
title: '搜索蓝牙外围设备失败,请重新初始化蓝牙!',
icon:'none',
})
}
})
},
这一步已经拿到了设备id(deviceId),我会把设备id以自定义属性放入到标签中,然后用户选择连接那个蓝牙设备,就能拿到那个设备的deviceId。
5.连接低功耗蓝牙(wx.createBLEConnection)
上一步把列表渲染出来了,用户会选择一个设备连接,拿到deviceId,然后去调用createBLEConnection这个API,就能连接到蓝牙了,记住,连接成功之后要关闭搜索蓝牙。
片段4:
connectTo(e){
let that=this;
let deviceId=e.currentTarget.dataset.id; //设备id
let connectName=e.currentTarget.dataset.name; //连接的设备名称
wx.showLoading({
title: '连接中...',});
wx.createBLEConnection({
deviceId,// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
success (res) {
wx.hideLoading();
that.stopBluetoothDevicesDiscovery(); //停止搜索蓝牙
console.log(res);
if(res.errCode==0){
console.log('连接成功');
that.setData({
deviceId:deviceId,
connectName:connectName,
isHideConnect:false, //显示已连接的蓝牙
})
that.getBLEDeviceServices(deviceId); //获取已连接蓝牙的服务
}else if(res.errCode==10012){
wx.showToast({
title: '连接超时,请重试!',
})
}
},
fail(error){
wx.hideLoading();
wx.showToast({
title: error,
})
}
});
},
stopBluetoothDevicesDiscovery(){
wx.stopBluetoothDevicesDiscovery({
success (res) {
console.log(res)
}
})
},
6.获取蓝牙的服务(wx.getBLEDeviceServices)
连接到蓝牙之后就是获取蓝牙的服务了,每个蓝牙都有数个服务,起到不同的功能,每个服务有独立的uuid,我们要做的就是拿到服务的uuid也就是serviceId。
我们需要用到我们需要的服务的uuid,这个一般是跟硬件沟通,知道需要操作哪个服务,我这边需要第二个服务,我就去操作第二个服务
片段5:
//获取服务以及服务的uuid
getBLEDeviceServices(deviceId){
let that=this;
let serviceId;
wx.getBLEDeviceServices({
//获取蓝牙设备所有服务
deviceId,
success: (res) => {
//services:设备服务列表 uuid:服务id
console.log(res);
serviceId=res.services[1].uuid;
that.getBLEDeviceCharacteristics(deviceId, serviceId); //去获取特征值
},
})
},
7.获取服务的特征值(wx.getBLEDeviceCharacteristics)
我拿第二个服务的uuid,去获取这个服务的所有特征值,特征值我们可以读,写(发送请求),监听(接收数据)
获取到的特征值如上图
片段6:
getBLEDeviceCharacteristics(deviceId, serviceId) {
console.log(deviceId,'serviceId='+ serviceId)
let that=this;
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
console.log(res);
let characteristicId=res.characteristics[0].uuid; //要写数据的特征id
let notifyId=res.characteristics[3].uuid; //监听特征变化的特征id(接收数据)
that.notifyBLECharacteristicValueChange(serviceId,notifyId);
let writeNews={
deviceId,serviceId,characteristicId};
that.setData({
writeNews:writeNews}); //写的时候需要用到
},
fail(err){
console.log('获取特征值失败:');
console.log(err)
},
});
},
我这边是对此服务的第一个特征进行写操作(就是发送数据),然后监听第四个特征(接收数据)
8.监听特征值变化(接收数据)
我们需要先订阅特征值,才能监听特征值变化,订阅的API是:wx.notifyBLECharacteristicValueChange,然后在调用wx.onBLECharacteristicValueChange,去监听特征值变化(接收数据),
片段7:
notifyBLECharacteristicValueChange(serviceId,characteristicId){
let that=this;
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: that.data.deviceId,
serviceId,
characteristicId,
success (res) {
console.log('notifyBLECharacteristicValueChange success');
console.log(res);
wx.onBLECharacteristicValueChange(function (res){
console.log(res);
let str=that.ab2hex(res.value); //转为16进制字符串
//这就是需要的字符了
})
}
})
},
// ArrayBuffer转16进制字符串
ab2hex(buffer){
var hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('');
},
这一步就能获取到数据了,我们是先开启监听,然后写数据,就能接收到数据了。
9.写入数据(发送请求) (wx.writeBLECharacteristicValue)
写入数据其实就是发送请求,我们已经开启监听了,就要发送请求了,
片段8:
writeBLECharacteristicValue(){
//页面有个按钮
// 向蓝牙设备发送的16进制数据
let that=this;
let buffer = new ArrayBuffer(8);
let dataView = new DataView(buffer);
console.log(dataView);//第一个参数是字节序号,表示从哪个字节开始写入,第二个参数为写入的数据。
let arr=that.data.queryData.query;
arr.forEach((item,i)=>{
dataView.setInt8(i, arr[i]);
})
console.log(buffer)
wx.writeBLECharacteristicValue({
deviceId: that.data.writeNews.deviceId,
serviceId: that.data.writeNews.serviceId,
characteristicId:that.data.writeNews.characteristicId,
value: buffer,
success:(res)=>{
console.log(res);
},
fail:(err)=>{
console.log(err)
}
})
},
发送需要设备id(deviceId),服务id(serviceId),特征值id(characteristicId),一般情况下,我们写入成功之后就能接收到数据了,
value就是接收到的数据。
基本流程就是这样的,断开连接什么的需要你们自己根据自己的情况来了,我就不写了。
如果需要全部demo的可以在本文开头给的链接去github去拷贝。下面就只贴js了。有问题的可以下方评论询问。
如果本文对大家有帮助,请给我点个赞,蟹蟹!
js:
// pages/blueTooth/blueTooth.js
Page({
data: {
devicesList:[],
isHideList:true, //是否隐藏蓝牙列表
isHideConnect:false, //是否隐藏连接模块
deviceId:'',
connectName:'',
writeNews:{
}, //写数据三个id
queryData:{
query:[0x02,0x09,0x00,0x01,0x6A,0x00,0x50,0x06],
stateTest:[0x01,0x08,0x02,0x00,0x56,0x00,0x59,0x06],
},
},
/**
* 生命周期函数--监听页面加载
*/
// ****流程,大纲
onLoad: function(options) {
//目前只支持低功耗蓝牙,文档上的两套api是可以结合使用的,安卓
let that=this;
wx.getSystemInfo({
success (res) {
console.log(res);
let gps=res.locationEnabled;
if(!gps){
wx.showModal({
title: '请打开GPS定位',
content: '不打开GPS定位,可能无法搜索到蓝牙设备',
showCancel: false
})
}else{
that.openBluetoothAdapter();
}
}
})
},
openBluetoothAdapter(){
wx.openBluetoothAdapter({
success (res) {
wx.onBluetoothAdapterStateChange(function (res) {
if(!res.available){
//蓝牙适配器是否可用
wx.showModal({
title: '温馨提示',
content: '蓝牙蓝牙适配器不可用,请重新启动',
showCancel: false
})
}
})
that.searchBlue(); //开始搜索蓝牙
},
fail(res){
console.log(res);
wx.showToast({
title: '请检查手机蓝牙是否打开',
icon:'none',
})
},
})
},
searchBlue(){
let that=this;
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
success (res) {
console.log(res);
wx.showLoading({
title: '正在搜索设备',});
wx.getBluetoothDevices({
success: function(res) {
console.log(res);
let devicesListArr=[];
if(res.devices.length>0){
//如果有蓝牙就把蓝牙信息放到渲染列表里面
wx.hideLoading();
res.devices.forEach(device=>{
if (!device.name && !device.localName) {
return
}else{
devicesListArr.push(device);
}
})
that.setData({
devicesList:devicesListArr,isHideList:false}); //渲染到页面中
}else{
wx.hideLoading();
wx.showModal({
title: '温馨提示',
content: '无法搜索到蓝牙设备,请打开GPS重新尝试',
showCancel: false
});
wx.closeBluetoothAdapter({
success (res) {
console.log(res)
}
})
}
}
})
},
fail: function(res) {
wx.showToast({
title: '搜索蓝牙外围设备失败,请重新初始化蓝牙!',
icon:'none',
})
}
})
},
//开始连接,获取deviceId
connectTo(e){
let that=this;
let deviceId=e.currentTarget.dataset.id; //设备id
let connectName=e.currentTarget.dataset.name; //连接的设备名称
wx.showLoading({
title: '连接中...',});
wx.createBLEConnection({
deviceId,// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
success (res) {
wx.hideLoading();
that.stopBluetoothDevicesDiscovery(); //停止搜索蓝牙
console.log(res);
if(res.errCode==0){
console.log('连接成功');
that.setData({
deviceId:deviceId,
connectName:connectName,
isHideConnect:false,
})
that.getBLEDeviceServices(deviceId); //获取已连接蓝牙的服务
}else if(res.errCode==10012){
wx.showToast({
title: '连接超时,请重试!',
})
}
},
fail(error){
wx.hideLoading();
wx.showToast({
title: error,
})
}
});
},
//每个蓝牙都有数个服务,起到不同的功能,每个服务有独立的uuid
//获取服务以及服务的uuid
getBLEDeviceServices(deviceId){
let serviceId;
wx.getBLEDeviceServices({
//获取蓝牙设备所有服务
deviceId,
success: (res) => {
//services:设备服务列表 uuid:服务id
console.log(res);
serviceId=res.services[1].uuid;
this.getBLEDeviceCharacteristics(deviceId, serviceId);
},
})
},
//每个服务都有特征值,特征值也有uuid,
//获取特征值(是否能读写)
getBLEDeviceCharacteristics(deviceId, serviceId) {
console.log(deviceId,'serviceId='+ serviceId)
let that=this;
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
console.log(res);
let characteristicId=res.characteristics[0].uuid; //要写数据的特征id
let writeNews={
deviceId,serviceId,characteristicId};
that.setData({
writeNews:writeNews});
let notifyId=res.characteristics[3].uuid; //监听特征变化的特征id(接收数据)
that.notifyBLECharacteristicValueChange(serviceId,notifyId);
},
fail(err){
console.log('获取特征值失败:');
console.log(err)
},
});
},
writeBLECharacteristicValue(){
//页面有个按钮
// 向蓝牙设备发送的16进制数据
let that=this;
let buffer = new ArrayBuffer(8);
let dataView = new DataView(buffer);
console.log(dataView);//第一个参数是字节序号,表示从哪个字节开始写入,第二个参数为写入的数据。
let arr=that.data.queryData.query;
arr.forEach((item,i)=>{
dataView.setInt8(i, arr[i]);
})
console.log(buffer)
wx.writeBLECharacteristicValue({
deviceId: that.data.writeNews.deviceId,
serviceId: that.data.writeNews.serviceId,
characteristicId:that.data.writeNews.characteristicId,
value: buffer,
success:(res)=>{
console.log(res);
},
fail:(err)=>{
console.log(err)
}
})
},
notifyBLECharacteristicValueChange(serviceId,characteristicId){
let that=this;
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: this.data.deviceId,
serviceId,
characteristicId,
success (res) {
console.log('notifyBLECharacteristicValueChange success');
console.log(res);
wx.onBLECharacteristicValueChange(function (res){
console.log(res);
let str=util.ab2hex(res.value);
that.setData({
initializationArr:util.initialization(str)})
console.log(util.initialization(str));
})
}
})
},
// ArrayBuffer转16进制字符串
ab2hex(buffer){
var hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('');
},
//断开连接
closeBLEConnection() {
let that=this;
console.log(that.data)
wx.closeBLEConnection({
deviceId: this.data.deviceId,
success(){
wx.showToast({
title: '已断开连接',
});
that.setData({
deviceId:'',
connectName:'',
isHideConnect:true,
});
}
})
that.closeBluetoothAdapter();
},
stopBluetoothDevicesDiscovery(){
wx.stopBluetoothDevicesDiscovery({
success (res) {
console.log(res)
}
})
},
//关闭蓝牙模块
closeBluetoothAdapter() {
wx.closeBluetoothAdapter({
success (res) {
console.log('关闭蓝牙模块')
that.setData({
devicesList:[],
isHideList:true, //是否隐藏蓝牙列表
isHideConnect:true, //是否隐藏连接模块
})
}
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})