共计 16499 个字符,预计需要花费 42 分钟才能阅读完成。
本文简介
点赞 + 关注 + 珍藏 = 学会了
这是一次实在的 蓝牙收发数据 的全过程解说。
本文应用 uni-app
+ Vue3
的形式进行开发,以手机 app 的形式运行(微信小程序同样可行)。
uni-app
提供了 蓝牙 和 低功耗蓝牙 的 api
,和微信小程序提供的 api
是一样的,所以本文的解说也 实用于微信小程序。
本文只实现 蓝牙收发数据 性能,至于款式,我懒得调~
蓝牙相干性能我会逐渐解说。如果你根底好,又急的话,能够间接跳到『残缺代码』的章节查看,那里没废话。
花了几块钱巨款买回来的蓝牙学习套装~
环境阐明
- 开发工具:
HBuilder X 3.4.7.20220422
uni-app
+Vue3
- 以安卓 App 的形式运行(iOS 和小程序同理)
思路
蓝牙收发数据的逻辑和咱们罕用的 AJAX
进行的网络申请是有一丢丢不同的。
其中较大的区别是:蓝牙接收数据不是那么的稳固,相比起网络申请,蓝牙更容易呈现丢包的状况。
在开发中,AJAX
发动的申请不论胜利还是失败,浏览器根本都会给你一个回答。但 uni-app
提供的 api
来看,蓝牙接收数据会显得更加“异步”。
大抵思路
应用蓝牙进行数据传输的大略思路如下:
- 初始化:关上蓝牙模块
- 搜查:检测左近存在的设施
- 连贯:找到指标设施进行
- 监听:开启监听性能,接管其余设施传过来的数据
- 发送指令:不论发送数据还是读取数据,都能够了解为向外发送指令
实现
下面整顿出应用蓝牙传输数据的 5 大动作,但每个动作其实都是由 uni-app
提供的一个或者多个 api
组合而成。
初始化阶段
应用蓝牙之前,须要初始化蓝牙模块,这是最最最开始就要做的!
应用 uni.openBluetoothAdapter
这个 api
就能够初始化蓝牙模块。其余蓝牙相干 API 必须在 uni.openBluetoothAdapter
调用之后应用。否则 API 会返回谬误(errCode=10000
)。
错误代码能够查阅《错误码文档》
代码示例
<template>
<view>
<button @click="initBlue"> 初始化蓝牙 </button>
</view>
</template>
<script setup>
//【1】初始化蓝牙
function initBlue() {
uni.openBluetoothAdapter({success(res) {console.log('初始化蓝牙胜利')
console.log(res)
},
fail(err) {console.log('初始化蓝牙失败')
console.error(err)
}
})
}
</script>
如果你手机开启了蓝牙,点击页面上的按钮后,控制台就会输入如下内容
初始化蓝牙胜利
{"errMsg":"openBluetoothAdapter:ok"}
如果手机没开启蓝牙,就会返回如下内容
初始化蓝牙失败
{"errMsg":"openBluetoothAdapter:fail not available","code":10001}
依据文档提醒,10001 代表 以后蓝牙适配器不可用。
如果你的控制台能打印出 {"errMsg":"openBluetoothAdapter:ok"}
证实第一步曾经胜利了。
接下来能够开始搜寻左近蓝牙设施。
搜查左近设施
这一步须要 2 个 api
配合实现。所以能够分解成以下 2 步:
- 开启搜查性能:
uni.startBluetoothDevicesDiscovery
- 监听搜查到新设施:
uni.onBluetoothDeviceFound
开发蓝牙相干性能时,操作逻辑更像是推送,所以“开启搜寻”和“监听新设施”是离开操作的。
uni.startBluetoothDevicesDiscovery
能够让设施开始搜寻左近蓝牙设施,但这个办法比拟消耗系统资源,倡议在连贯到设施之后就应用 uni.stopBluetoothDevicesDiscovery
进行持续搜寻。
uni.startBluetoothDevicesDiscovery
办法里能够传入一个对象,该对象接管几个参数,但初学的话咱们只关注 success
和 fail
。如果你的我的项目中硬件佬有提供 service 的 uuid
给你的话,你也能够在 services
里传入。其余参数能够查看官网文档的介绍。
在应用 uni.startBluetoothDevicesDiscovery
(开始搜寻)后,能够应用 uni.onBluetoothDeviceFound
进行监听,这个办法外面接管一个回调函数。
代码示例
<template>
<view>
<scroll-view
scroll-y
class="box"
>
<view class="item" v-for="item in blueDeviceList">
<view>
<text>id: {{item.deviceId}}</text>
</view>
<view>
<text>name: {{item.name}}</text>
</view>
</view>
</scroll-view>
<button @click="initBlue"> 初始化蓝牙 </button>
<button @click="discovery"> 搜寻左近蓝牙设施 </button>
</view>
</template>
<script setup>
import {ref} from 'vue'
// 搜寻到的蓝牙设施列表
const blueDeviceList = ref([])
//【1】初始化蓝牙
function initBlue() {
uni.openBluetoothAdapter({success(res) {console.log('初始化蓝牙胜利')
console.log(res)
},
fail(err) {console.log('初始化蓝牙失败')
console.error(err)
}
})
}
//【2】开始搜查左近设施
function discovery() {
uni.startBluetoothDevicesDiscovery({success(res) {console.log('开始搜寻')
// 开启监听回调
uni.onBluetoothDeviceFound(found)
},
fail(err) {console.log('搜寻失败')
console.error(err)
}
})
}
//【3】找到新设施就触发该办法
function found(res) {console.log(res)
blueDeviceList.value.push(res.devices[0])
}
</script>
<style>
.box {
width: 100%;
height: 400rpx;
box-sizing: border-box;
margin-bottom: 20rpx;
border: 2px solid dodgerblue;
}
.item {
box-sizing: border-box;
padding: 10rpx;
border-bottom: 1px solid #ccc;
}
button {margin-bottom: 20rpx;}
</style>
下面代码的逻辑是,如果开启 “寻找左近设施” 性能胜利,接着就开启 “监听寻找到新设施的事件”。
搜寻到的设施会返回以下数据:
{
"devices": [{
"deviceId": "B4:10:7B:C4:83:14",
"name": "蓝牙设施名",
"RSSI": -58,
"localName": "","advertisServiceUUIDs": ["0000FFF0-0000-1000-8000-00805F9B34FB"],"advertisData": {}}]
}
每监听到一个新的设施,我都会将其增加到 蓝牙设施列表(blueDeviceList) 里,最初讲这个列表的数据渲染到页面上。
连贯指标设施
连贯指标设施只须要 1 个 api
就能实现。但依据文档提醒,咱们连贯后还须要敞开“搜寻左近设施”的性能,这个很好了解,既然找到了,再持续找就是浪费资源。
流程如下:
- 获取设施 ID:依据
uni.onBluetoothDeviceFound
回调,拿到设施 ID - 连贯设施:应用设施 ID 进行连贯
uni.createBLEConnection
- 进行搜寻:
uni.stopBluetoothDevicesDiscovery
我给每条搜寻到的蓝牙后果增加一个 click
事件,会向指标设施发送连贯申请。
我的设施名称是 leihou
,所以我点击了这条。
代码示例
<template>
<view>
<scroll-view
scroll-y
class="box"
>
<view class="item" v-for="item in blueDeviceList" @click="connect(item)">
<view>
<text>id: {{item.deviceId}}</text>
</view>
<view>
<text>name: {{item.name}}</text>
</view>
</view>
</scroll-view>
<button @click="initBlue"> 初始化蓝牙 </button>
<button @click="discovery"> 搜寻左近蓝牙设施 </button>
</view>
</template>
<script setup>
import {ref} from 'vue'
// 搜寻到的蓝牙设施列表
const blueDeviceList = ref([])
//【1】初始化蓝牙
function initBlue() {
uni.openBluetoothAdapter({success(res) {console.log('初始化蓝牙胜利')
console.log(res)
},
fail(err) {console.log('初始化蓝牙失败')
console.error(err)
}
})
}
//【2】开始搜查左近设施
function discovery() {
uni.startBluetoothDevicesDiscovery({success(res) {console.log('开始搜寻')
// 开启监听回调
uni.onBluetoothDeviceFound(found)
},
fail(err) {console.log('搜寻失败')
console.error(err)
}
})
}
//【3】找到新设施就触发该办法
function found(res) {console.log(res)
blueDeviceList.value.push(res.devices[0])
}
// 蓝牙设施的 id
const deviceId = ref('')
//【4】连贯设施
function connect(data) {console.log(data)
deviceId.value = data.deviceId
uni.createBLEConnection({
deviceId: deviceId.value,
success(res) {console.log('连贯胜利')
console.log(res)
// 进行搜寻
stopDiscovery()},
fail(err) {console.log('连贯失败')
console.error(err)
}
})
}
//【5】进行搜寻
function stopDiscovery() {
uni.stopBluetoothDevicesDiscovery({success(res) {console.log('进行胜利')
console.log(res)
},
fail(err) {console.log('进行失败')
console.error(err)
}
})
}
</script>
<style>
.box {
width: 100%;
height: 400rpx;
box-sizing: border-box;
margin-bottom: 20rpx;
border: 2px solid dodgerblue;
}
.item {
box-sizing: border-box;
padding: 10rpx;
border-bottom: 1px solid #ccc;
}
button {margin-bottom: 20rpx;}
</style>
连贯胜利后在控制台会输入
连贯胜利
{"errMsg":"createBLEConnection:ok"}
在连贯胜利后就立即调用 uni.stopBluetoothDevicesDiscovery
办法进行持续搜寻左近其余设施,进行胜利后会输入
进行胜利
{"errMsg":"stopBluetoothDevicesDiscovery:ok"}
连贯胜利后,设施也亮起了绿灯。
监听
在连贯完设施后,就要先开启监听数据的性能。这样能力接管到发送读写指令后设施给你回调的信息。
要开启监听,首先须要晓得蓝牙设施提供了那些 服务 ,而后通过服务获取 特征值 ,特征值会通知你哪个可读,哪个可写。最初依据特征值进行 音讯监听。
步骤如下:
- 获取蓝牙设施服务:
uni.getBLEDeviceServices
- 获取特征值:
uni.getBLEDeviceCharacteristics
- 开启音讯监听:
uni.notifyBLECharacteristicValueChange
- 接管音讯监听传来的数据:
uni.onBLECharacteristicValueChange
失常状况下,硬件佬会提前把蓝牙设施的指定服务还有特征值通知你。
比方我这个设施的蓝牙服务是:0000FFE0-0000-1000-8000-00805F9B34FB
特征值是:0000FFE1-0000-1000-8000-00805F9B34FB
第一步,获取蓝牙服务
<template>
<view>
<!-- 省略上一步的代码 -->
<button @click="getServices"> 获取蓝牙服务 </button>
</view>
</template>
<script setup>
import {ref} from 'vue'
// 省略上一步的代码……
//【6】获取服务
function getServices() {
uni.getBLEDeviceServices({
deviceId: deviceId.value, // 设施 ID,在上一步【4】里获取
success(res) {console.log(res)
},
fail(err) {console.error(err)
}
})
}
</script>
此时点击按钮,将会获取到已连贯设施的所有服务。
我的设施有以下几个服务。你在工作中拿到的 服务 uuid
和我的是不一样的,数量也不肯定雷同。
能够发现,我拿到的后果里有 0000FFE0-0000-1000-8000-00805F9B34FB
这条服务。
{
"services": [{
"uuid": "00001800-0000-1000-8000-00805F9B34FB",
"isPrimary": true
}, {
"uuid": "00001801-0000-1000-8000-00805F9B34FB",
"isPrimary": true
}, {
"uuid": "0000180A-0000-1000-8000-00805F9B34FB",
"isPrimary": true
}, {
"uuid": "0000FFF0-0000-1000-8000-00805F9B34FB",
"isPrimary": true
}, {
"uuid": "0000FFE0-0000-1000-8000-00805F9B34FB",
"isPrimary": true
}],
"errMsg": "getBLEDeviceServices:ok"
}
第二步,获取指定服务的特征值
获取特征值,须要传 设施 ID 和 服务 ID。
在上两步我拿到了 设施 ID 为 B4:10:7B:C4:83:14
,服务 ID 为 0000FFE0-0000-1000-8000-00805F9B34FB
。
<template>
<view>
<!-- 省略后面几步代码 -->
<button @click="getCharacteristics"> 获取特征值 </button>
</view>
</template>
<script setup>
import {ref} from 'vue'
// 省略后面几步代码
//【7】获取特征值
function getCharacteristics() {
uni.getBLEDeviceCharacteristics({
deviceId: deviceId.value, // 设施 ID,在【4】里获取到
serviceId: '0000FFE0-0000-1000-8000-00805F9B34FB', // 服务 UUID,在【6】里能获取到
success(res) {console.log(res)
},
fail(err) {console.error(err)
}
})
}
</script>
最初胜利输入
{
"characteristics": [{
"uuid": "0000FFE1-0000-1000-8000-00805F9B34FB",
"properties": {
"read": true,
"write": true,
"notify": true,
"indicate": false
}
}],
"errMsg": "getBLEDeviceCharacteristics:ok"
}
characteristics
字段里保留了该服务的所有特征值,我的设施这个服务只有 1 个特征值,并且读、写、音讯推送都为 true
。
你的设施可能不止一条特征值,须要监听那条特征值这须要你和硬件佬协商的(通常也是硬件佬间接和你说要监听哪条)。
第三、四步,开启音讯监听 并 接管音讯监听传来的数据
依据曾经拿到的 设施 ID、服务 ID、特征值,就能够开启对应的监听性能。
应用 uni.notifyBLECharacteristicValueChange
开启音讯监听;
并在 uni.onBLECharacteristicValueChange
办法触发监听到的音讯。
<template>
<view>
<!-- 省略后面几步代码 -->
<button @click="notify"> 开启音讯监听 </button>
</view>
</template>
<script setup>
import {ref} from 'vue'
// 省略后面几步代码
//【8】开启音讯监听
function notify() {
uni.notifyBLECharacteristicValueChange({
deviceId: deviceId.value, // 设施 ID,在【4】里获取到
serviceId: '0000FFE0-0000-1000-8000-00805F9B34FB', // 服务 UUID,在【6】里能获取到
characteristicId: '0000FFE1-0000-1000-8000-00805F9B34FB', // 特征值,在【7】里能获取到
success(res) {console.log(res)
// 承受音讯的办法
listenValueChange()},
fail(err) {console.error(err)
}
})
}
// ArrayBuffer 转 16 进度字符串示例
function ab2hex(buffer) {
const hexArr = Array.prototype.map.call(new Uint8Array(buffer),
function (bit) {return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
}
// 将 16 进制的内容转成咱们看得懂的字符串内容
function hexCharCodeToStr(hexCharCodeStr) {var trimedStr = hexCharCodeStr.trim();
var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;
var len = rawStr.length;
if (len % 2 !== 0) {alert("存在非法字符!");
return "";
}
var curCharCode;
var resultStr = [];
for (var i = 0; i < len; i = i + 2) {curCharCode = parseInt(rawStr.substr(i, 2), 16);
resultStr.push(String.fromCharCode(curCharCode));
}
return resultStr.join("");
}
//【9】监听音讯变动
function listenValueChange() {
uni.onBLECharacteristicValueChange(res => {
// 后果
console.log(res)
// 后果里有个 value 值,该值为 ArrayBuffer 类型,所以在控制台无奈用肉眼察看到,必须将该值转换为 16 进制
let resHex = ab2hex(res.value)
console.log(resHex)
// 最初将 16 进制转换为 ascii 码,就能看到对应的后果
let result = hexCharCodeToStr(resHex)
console.log(result)
})
}
</script>
listenValueChange
办法是用来接管设施传过来的音讯。
下面的例子中,res
的后果是
{
"deviceId": "B4:10:7B:C4:83:14",
"serviceId": "0000FFE0-0000-1000-8000-00805F9B34FB",
"characteristicId": "0000FFE1-0000-1000-8000-00805F9B34FB",
"value": {}}
设施传过来的内容就放在 value
字段里,但因为该字段的类型是 ArrayBuffer
,所以无奈在控制台用肉眼间接察看。于是就通过 ab2hex
办法将该值转成 16 进制,最初再用 hexCharCodeToStr
办法将 16 进制 转成 ASCII 码。
我从设施里发送一段字符串过去:leihou
App 端收到的数据转成 16 进制 后的后果:6c6569686f75
再从 16 进制 转成 ASCII 码 后的后果:leihou
发送指令
终于到最初一步了。
从 uni-app
和 微信小程序
提供的蓝牙api
来看,发送指令只有有 2 个办法:
uni.writeBLECharacteristicValue
:向低功耗蓝牙设施特征值中写入二进制数据。uni.readBLECharacteristicValue
:读取低功耗蓝牙设施的特征值的二进制数据值。
这里须要理清一个概念,本节的内容为 “发送指令”,也就是说,从你的 app 或小程序向其余蓝牙设施发送指令,而这个指令分 2 种状况,一种是你要发送一些数据给蓝牙设施,另一种状况是你叫蓝牙设施给你发点信息。
uni.writeBLECharacteristicValue
这两种状况咱们须要离开探讨,先讲讲 uni.writeBLECharacteristicValue
。
uni.writeBLECharacteristicValue
从文档能够看出,这个 api
是能够发送一些数据给蓝牙设施,但发送的值要转成 ArrayBuffer
。
代码示例
<template>
<view>
<!-- 省略后面几步代码 -->
<button @click="send"> 发送数据 </button>
</view>
</template>
<script setup>
import {ref} from 'vue'
// 省略后面几步代码
//【10】发送数据
function send() {
// 向蓝牙设施发送一个 0x00 的 16 进制数据
let msg = 'hello'
const buffer = new ArrayBuffer(msg.length)
const dataView = new DataView(buffer)
// dataView.setUint8(0, 0)
for (var i = 0; i < msg.length; i++) {dataView.setUint8(i, msg.charAt(i).charCodeAt())
}
uni.writeBLECharacteristicValue({
deviceId: deviceId.value, // 设施 ID,在【4】里获取到
serviceId: '0000FFE0-0000-1000-8000-00805F9B34FB', // 服务 UUID,在【6】里能获取到
characteristicId: '0000FFE1-0000-1000-8000-00805F9B34FB', // 特征值,在【7】里能获取到
value: buffer,
success(res) {console.log(res)
},
fail(err) {console.error(err)
}
})
}
</script>
此时,如果 uni.writeBLECharacteristicValue
走 success
,证实你曾经把数据向外胜利发送了,但不代表设施肯定就收到了。
通常设施收到你发送过来的信息,会返回一条音讯给你,而这个回调音讯会在 uni.onBLECharacteristicValueChange
触发,也就是 第【9】步 那里。但这是蓝牙设施那边管制的,你作为前端佬,人家“已读不回”你也拿人家没方法。
uni.readBLECharacteristicValue
在 “监听” 局部,咱们应用了 uni.getBLEDeviceCharacteristics
获取设施的特征值,我的设施提供的特征值反对 read
,所以能够应用 uni.readBLECharacteristicValue
向蓝牙设施发送一条“读取”指令。而后在 uni.onBLECharacteristicValueChange
里能够接管设施发送过去的数据。
代码示例
<template>
<view>
<!-- 省略后面几步代码 -->
<button @click="read"> 读取数据 </button>
</view>
</template>
<script setup>
import {ref} from 'vue'
// 省略后面几步代码
//【11】读取数据
function read() {
uni.readBLECharacteristicValue({
deviceId: deviceId.value,
serviceId: serviceId.value,
characteristicId: characteristicId.value,
success(res) {console.log('读取指令发送胜利')
console.log(res)
},
fail(err) {console.log('读取指令发送失败')
console.error(err)
}
})
}
</script>
应用“读取”的形式向设施发送指令,是不须要另外传值的。
此时我的设施返回 00
这个数据是硬件那边设置的。
在日常工作中,uni.readBLECharacteristicValue
的作用次要是读取数据,但应用场景不算很多。
我在工作中遇到的场景是:蓝牙设施提供了几个接口,而且传过来的数据比拟大,比方传图片给 app 这边。我就会先用 uni.writeBLECharacteristicValue
通知设施我当初须要取什么接口的数据,而后用 uni.readBLECharacteristicValue
发送读取数据的申请,如果数据量比拟大,就要重复使用 uni.readBLECharacteristicValue
进行读取。比方下面的例子,我读第一次的时候返回 00
,读第二次就返回 01
……
最初再揭示一下,uni.readBLECharacteristicValue
只负责发送读取的申请,并且外面的 success
和 fail
只是返回你本次发送申请的动作是否胜利,至于对面的蓝牙设施有没有收到这个指令你是不分明的。
最初须要通过 uni.getBLEDeviceCharacteristics
监听设施传过来的数据。
残缺代码
<template>
<view>
<scroll-view
scroll-y
class="box"
>
<view class="item" v-for="item in blueDeviceList" @click="connect(item)">
<view>
<text>id: {{item.deviceId}}</text>
</view>
<view>
<text>name: {{item.name}}</text>
</view>
</view>
</scroll-view>
<button @click="initBlue">1 初始化蓝牙 </button>
<button @click="discovery">2 搜寻左近蓝牙设施 </button>
<button @click="getServices">3 获取蓝牙服务 </button>
<button @click="getCharacteristics">4 获取特征值 </button>
<button @click="notify">5 开启音讯监听 </button>
<button @click="send">6 发送数据 </button>
<button @click="read">7 读取数据 </button>
<view class="msg_x">
<view class="msg_txt">
监听到的内容:{{message}}
</view>
<view class="msg_hex">
监听到的内容(十六进制):{{messageHex}}
</view>
</view>
</view>
</template>
<script setup>
import {ref} from 'vue'
// 搜寻到的蓝牙设施列表
const blueDeviceList = ref([])
//【1】初始化蓝牙
function initBlue() {
uni.openBluetoothAdapter({success(res) {console.log('初始化蓝牙胜利')
console.log(res)
},
fail(err) {console.log('初始化蓝牙失败')
console.error(err)
}
})
}
//【2】开始搜查左近设施
function discovery() {
uni.startBluetoothDevicesDiscovery({success(res) {console.log('开始搜寻')
// 开启监听回调
uni.onBluetoothDeviceFound(found)
},
fail(err) {console.log('搜寻失败')
console.error(err)
}
})
}
//【3】找到新设施就触发该办法
function found(res) {console.log(res)
blueDeviceList.value.push(res.devices[0])
}
// 蓝牙设施的 id
const deviceId = ref('')
//【4】连贯设施
function connect(data) {console.log(data)
deviceId.value = data.deviceId // 将获取到的设施 ID 存起来
uni.createBLEConnection({
deviceId: deviceId.value,
success(res) {console.log('连贯胜利')
console.log(res)
// 进行搜寻
stopDiscovery()
uni.showToast({title: '连贯胜利'})
},
fail(err) {console.log('连贯失败')
console.error(err)
uni.showToast({
title: '连贯胜利',
icon: 'error'
})
}
})
}
//【5】进行搜寻
function stopDiscovery() {
uni.stopBluetoothDevicesDiscovery({success(res) {console.log('进行胜利')
console.log(res)
},
fail(err) {console.log('进行失败')
console.error(err)
}
})
}
//【6】获取服务
function getServices() {
// 如果是主动链接的话,uni.getBLEDeviceServices 办法倡议应用 setTimeout 提早 1 秒后再执行
uni.getBLEDeviceServices({
deviceId: deviceId.value,
success(res) {console.log(res) // 能够在 res 里判断有没有硬件佬给你的服务
uni.showToast({title: '获取服务胜利'})
},
fail(err) {console.error(err)
uni.showToast({
title: '获取服务失败',
icon: 'error'
})
}
})
}
// 硬件提供的服务 id,开发中须要问硬件佬获取该 id
const serviceId = ref('0000FFE0-0000-1000-8000-00805F9B34FB')
//【7】获取特征值
function getCharacteristics() {
// 如果是主动链接的话,uni.getBLEDeviceCharacteristics 办法倡议应用 setTimeout 提早 1 秒后再执行
uni.getBLEDeviceCharacteristics({
deviceId: deviceId.value,
serviceId: serviceId.value,
success(res) {console.log(res) // 能够在此判断特征值是否反对读写等操作,特征值其实也须要提前向硬件佬索取的
uni.showToast({title: '获取特征值胜利'})
},
fail(err) {console.error(err)
uni.showToast({
title: '获取特征值失败',
icon: 'error'
})
}
})
}
const characteristicId = ref('0000FFE1-0000-1000-8000-00805F9B34FB')
//【8】开启音讯监听
function notify() {
uni.notifyBLECharacteristicValueChange({
deviceId: deviceId.value, // 设施 id
serviceId: serviceId.value, // 监听指定的服务
characteristicId: characteristicId.value, // 监听对应的特征值
success(res) {console.log(res)
listenValueChange()
uni.showToast({title: '已开启监听'})
},
fail(err) {console.error(err)
uni.showToast({
title: '监听失败',
icon: 'error'
})
}
})
}
// ArrayBuffer 转 16 进度字符串示例
function ab2hex(buffer) {
const hexArr = Array.prototype.map.call(new Uint8Array(buffer),
function (bit) {return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
}
// 将 16 进制的内容转成咱们看得懂的字符串内容
function hexCharCodeToStr(hexCharCodeStr) {var trimedStr = hexCharCodeStr.trim();
var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;
var len = rawStr.length;
if (len % 2 !== 0) {alert("存在非法字符!");
return "";
}
var curCharCode;
var resultStr = [];
for (var i = 0; i < len; i = i + 2) {curCharCode = parseInt(rawStr.substr(i, 2), 16);
resultStr.push(String.fromCharCode(curCharCode));
}
return resultStr.join("");
}
// 监听到的内容
const message = ref('')
const messageHex = ref('') // 十六进制
//【9】监听音讯变动
function listenValueChange() {
uni.onBLECharacteristicValueChange(res => {console.log(res)
let resHex = ab2hex(res.value)
console.log(resHex)
messageHex.value = resHex
let result = hexCharCodeToStr(resHex)
console.log(String(result))
message.value = String(result)
})
}
//【10】发送数据
function send() {
// 向蓝牙设施发送一个 0x00 的 16 进制数据
let msg = 'hello'
const buffer = new ArrayBuffer(msg.length)
const dataView = new DataView(buffer)
// dataView.setUint8(0, 0)
for (var i = 0; i < msg.length; i++) {dataView.setUint8(i, msg.charAt(i).charCodeAt())
}
uni.writeBLECharacteristicValue({
deviceId: deviceId.value,
serviceId: serviceId.value,
characteristicId: characteristicId.value,
value: buffer,
success(res) {console.log('writeBLECharacteristicValue success', res.errMsg)
uni.showToast({title: 'write 指令发送胜利'})
},
fail(err) {console.error(err)
uni.showToast({
title: 'write 指令发送失败',
icon: 'error'
})
}
})
}
//【11】读取数据
function read() {
uni.readBLECharacteristicValue({
deviceId: deviceId.value,
serviceId: serviceId.value,
characteristicId: characteristicId.value,
success(res) {console.log(res)
uni.showToast({title: 'read 指令发送胜利'})
},
fail(err) {console.error(err)
uni.showToast({
title: 'read 指令发送失败',
icon: 'error'
})
}
})
}
</script>
<style>
.box {
width: 98%;
height: 400rpx;
box-sizing: border-box;
margin: 0 auto 20rpx;
border: 2px solid dodgerblue;
}
.item {
box-sizing: border-box;
padding: 10rpx;
border-bottom: 1px solid #ccc;
}
button {margin-bottom: 20rpx;}
.msg_x {
border: 2px solid seagreen;
width: 98%;
margin: 10rpx auto;
box-sizing: border-box;
padding: 20rpx;
}
.msg_x .msg_txt {margin-bottom: 20rpx;}
</style>
以上就是本文的残缺代码。
相干文档
uni-app 蓝牙文档
uni-app 低功耗蓝牙文档
微信小程序 蓝牙文档
微信小程序 低功耗蓝牙文档
DataView 应用办法
举荐浏览
👍 uni-app App 端半屏间断扫码
记住:点赞 + 关注 + 珍藏 = 学会了
点赞 + 关注 + 珍藏 = 学会了