这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

本文简介

这是一次真实的 蓝牙收发数据 的全过程讲解。

本文使用 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) 里,最后讲这个列表的数据渲染到页面上。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cePpaik0-1652253685142)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f3a21f372d3b40e996e3a0db9f4aa66b~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]

连接目标设备

连接目标设备只需要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>

本文转载于:

https://blog.csdn.net/pfourfire/article/details/124711068

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--『uni-app、小程序』蓝牙连接、读写数据全过程的更多相关文章

  1. 微信小程序之蓝牙 BLE 踩坑记录

    前言 前段时间接手了一个微信小程序的开发,主要使用了小程序在今年 3 月开放的蓝牙 API ,此过程踩坑无数,特此记录一下跳坑过程.顺便开了另一个相关的小项目,欢迎 start 和 fork: BLE ...

  2. 微信小程序之蓝牙开发(详细读数据、写数据、附源码)

    本文将详细介绍微信小程序的蓝牙开发流程(附源码)准备:微信只支持低功耗蓝牙也就是蓝牙4.0,普通的蓝牙模块是用不了的,一定要注意. 蓝牙可以连TTL接到电脑上,再用XCOM调试 一开始定义的变量 va ...

  3. 微信小程序调用蓝牙功能控制车位锁

    第一次学用微信小程序,项目需要,被逼着研究了一下,功能是调用微信小程序的蓝牙功能,连接上智能车位锁,控制升降,大概步骤及调用的小程序接口API如下: 1.打开蓝牙模块 wx.openBluetooth ...

  4. 微信小程序开发-蓝牙功能开发

    0. 前言 这两天刚好了解了一下微信小程序的蓝牙功能.主要用于配网功能.发现微信的小程序蓝牙API已经封装的很好了.编程起来很方便.什么蓝牙知识都不懂的情况下,不到两天就晚上数据的收发了,剩下的就是数 ...

  5. Java生鲜电商平台-APP/小程序接口传输常见的加密算法及详解

    Java生鲜电商平台-APP/小程序接口传输常见的加密算法及详解 说明:Java生鲜电商平台-APP/小程序接口传输常见的加密算法及详解,加密算法,是现在每个软件项目里必须用到的内容. 广泛应用在包括 ...

  6. Java生鲜电商平台-电商中"再来一单"功能架构与详细设计(APP/小程序)

    Java生鲜电商平台-电商中"再来一单"功能架构与详细设计(APP/小程序) 说明:在实际的业务场景中(无论是TO B还是TO C)不管是休闲食品.餐饮.水果.日用百货.母婴等高频 ...

  7. uni与小程序,vue的区别

    标签区别 uni使用小程序的标签,vue使用web端的标签 标签名变化的: 标签描述\类别 vue uniapp 文本 span\font text 链接 a navigator/ router-li ...

  8. 微信小程序添加外部地图服务数据

    先上效果: 缘起 使用微信小程序做地图相关功能的时候,有个需求是需要接入自己发布的地图服务.查看微信小程序地图组件文档,发现它对地图相关的支持很少,只有一些基础功能,比如添加点.线.面.气泡和一些常规 ...

  9. 小迪安全 Web安全 基础入门 - 第三天 - 抓包&封包&协议&APP&小程序&PC应用&WEB应用

    一.抓包工具 1.Fiddler.Fiddler是一个用于HTTP调试的代理服务器应用程序,能捕获HTTP和HTTPS流量,并将其记录下来供用户查看.它通过使用自签名证书实现中间人攻击来进行日志记录. ...

  10. 小程序学习三 一切的开始app() 小程序的注册

    现在打开 app.js //app.js App({ onLaunch(options) { //小程序初始化 // console.log("小程序初始化", options) ...

随机推荐

  1. NEMU PA 3-2 实验报告

    一.实验目的 在上一章节我们完成了Cache的实现,但是这只是在速度上提高了取指和存取操作数的效率,而在访问的安全性上没有得到有效提升. 在PA3-2中我们要完成的,就是在NEMU中实现分段机制. 二 ...

  2. 【Unity3D】刚体组件Rigidbody

    1 前言 ​ 刚体(Rigidbody)是运动学(Kinematic)中的一个概念,指在运动中和受力作用后,形状和大小不变,而且内部各点的相对位置不变的物体.在 Unity3D 中,刚体组件赋予了游戏 ...

  3. Redhat7更改网易yum源

    说明 之前写了一篇关于Redhat6更换Yum源的文章,时隔已久很多包都变了,正好最近搭建环境需要用到Redhat7.3所以就再记录一下如何更换为国内最新最常用的yum源. 操作步骤 1.卸载系统自带 ...

  4. An Introduction to ANYDATA

    以下内容来自Oracle FAQ writen By Kevin,关于ANYDATA类型在项目中的应用. My newest project needed to create a record kee ...

  5. db2伪表sysibm.sysdummy1

    $ db2 describe table sysibm.sysdummy1 Column                         Type      Type name             ...

  6. SIP协议解析

    起始行(start-line) INVITE sip:34020000001320000001@202.102.11.27:35611 SIP/2.0 请求消息的起始行包括三个参数,格式:Reques ...

  7. win32 - DIB 与 DDB

    设备相关位图(DDB): DDB不包含颜色值,因为每个设备可以具有自己的一组颜色,所以为一个设备创建的DDB可能无法在其他设备上很好地显示. DDB通常被称为兼容位图,并且它通常比DIB具有更好的GD ...

  8. 【Android逆向】破解看雪 test1.apk

    1. 获取apk,并安装至手机 apk 获取地址: https://www.kanxue.com/work-task_read-800624.htm adb install -t test1.apk ...

  9. jstack查看JVM堆栈信息

    目录 介绍 线程状态 Monitor 调用修饰 线程动作 命令格式 常用参数说明 使用实例 jstack pid jstack 查看线程具体在做什么,可看出哪些线程在长时间占用CPU,尽快定位问题和解 ...

  10. 【Azure 应用程序见解】通过无代码方式在App Service中启用Application Insights后,如何修改在Application Insights中显示的App Service实例名呢?

    问题描述 在App Service中,可以非常容易的启动Application Insights服务.默认情况中,在Application Insights中查看信息时候,其中的对象名称默认为App ...