微信小程序项目中有使用到蓝牙连接打印,参考官方文档做了一个参考笔记,这样使用的时候就按着步骤查看。
uni-app蓝牙连接
蓝牙:
1、初始化蓝牙
uni.openBluetoothAdapter(OBJECT)
uni.openBluetoothAdapter({
success(res) {
console.log(res)
},
fail:(res)=>{
},
complete:()=>{
}
})
错误 :res.errCode
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
注意
2、监听蓝牙适配器状态变化事件
uni.onBluetoothAdapterStateChange(CALLBACK)
CALLBACK 返回参数
属性 | 类型 | 说明 |
---|
available | boolean | 蓝牙适配器是否可用 | discovering | boolean | 蓝牙适配器是否处于搜索状态 |
示例代码
uni.onBluetoothAdapterStateChange((res) => {
console.log('onBluetoothAdapterStateChange', res)
if (res.available) {
uni.onBluetoothAdapterStateChange(() => {});
uni.startBluetoothDevicesDiscovery(OBJECT)
}
})
3、开始搜寻附近的蓝牙外围设备
uni.startBluetoothDevicesDiscovery(OBJECT)
此操作比较耗费系统资源,请在搜索并连接到设备后调用 uni.stopBluetoothDevicesDiscovery 方法停止搜索。
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
services | Array | | 否 | 要搜索但蓝牙设备主 service 的 uuid 列表。某些蓝牙设备会广播自己的主 service 的 uuid。如果设置此参数,则只搜索广播包有对应 uuid 的主服务的蓝牙设备。建议主要通过该参数过滤掉周边不需要处理的其他蓝牙设备。 | allowDuplicatesKey | boolean | false | 否 | 是否允许重复上报同一设备。如果允许重复上报,则 uni.onBlueToothDeviceFound 方法会多次上报同一设备,但是 RSSI 值会有不同。 | interval | number | 0 | 否 | 上报设备的间隔。0 表示找到新设备立即上报,其他数值根据传入的间隔上报。 | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
注意:
- App 端目前仅支持发现ble蓝牙设备,更多蓝牙设备发现,可以使用 Native.js,参考:https://ask.dcloud.net.cn/article/114。也可以在插件市场获取原生插件
示例代码
uni.startBluetoothDevicesDiscovery({
services: ['FEE7'],
success(res) {
console.log(res)
uni.onBluetoothDeviceFound(OBJECT)
}
})
4、监听寻找到新设备的事件
uni.onBluetoothDeviceFound(CALLBACK)
CALLBACK 返回参数
属性 | 类型 | 说明 |
---|
devices | Array | 新搜索到的设备列表 |
devices 的结构
属性 | 类型 | 说明 |
---|
name | string | 蓝牙设备名称,某些设备可能没有 | deviceId | string | 用于区分设备的 id | RSSI | number | 当前蓝牙设备的信号强度 | advertisData | ArrayBuffer | 当前蓝牙设备的广播数据段中的 ManufacturerData 数据段。 | advertisServiceUUIDs | Array | 当前蓝牙设备的广播数据段中的 ServiceUUIDs 数据段 | localName | string | 当前蓝牙设备的广播数据段中的 LocalName 数据段 | serviceData | Object | 当前蓝牙设备的广播数据段中的 ServiceData 数据段 |
注意
示例代码
function ab2hex(buffer) {
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
}
uni.onBluetoothDeviceFound(function (devices) {
console.log('new device list has founded')
console.dir(devices)
console.log(ab2hex(devices[0].advertisData))
})
5、停止搜寻附近的蓝牙外围设备
uni.stopBluetoothDevicesDiscovery(OBJECT)
若已经找到需要的蓝牙设备并不需要继续搜索时,建议调用该接口停止蓝牙搜索。
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
示例代码
uni.stopBluetoothDevicesDiscovery({
success(res) {
console.log(res)
}
})
6、根据 uuid 获取处于已连接状态的设备
uni.getConnectedBluetoothDevices(OBJECT)
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
services | Array | | 是 | 蓝牙设备主 service 的 uuid 列表 | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
success 返回参数说明:
属性 | 类型 | 说明 |
---|
devices | Array | 搜索到的设备列表 |
res.devices 的结构
属性 | 类型 | 说明 |
---|
name | string | 蓝牙设备名称,某些设备可能没有 | deviceId | string | 用于区分设备的 id |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
示例代码
uni.getConnectedBluetoothDevices({
success(res) {
console.log(res)
}
})
7、获取在蓝牙模块生效期间所有已发现的蓝牙设备
uni.getBluetoothDevices(OBJECT)
包括已经和本机处于连接状态的设备。
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
success 返回参数说明:
属性 | 类型 | 说明 |
---|
devices | Array | uuid 对应的的已连接设备列表 |
res.devices 的结构
属性 | 类型 | 说明 |
---|
name | string | 蓝牙设备名称,某些设备可能没有 | deviceId | string | 用于区分设备的 id | RSSI | number | 当前蓝牙设备的信号强度 | advertisData | ArrayBuffer | 当前蓝牙设备的广播数据段中的 ManufacturerData 数据段。 | advertisServiceUUIDs | Array | 当前蓝牙设备的广播数据段中的 ServiceUUIDs 数据段 | localName | string | 当前蓝牙设备的广播数据段中的 LocalName 数据段 | serviceData | Object | 当前蓝牙设备的广播数据段中的 ServiceData 数据段 |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
示例代码
function ab2hex(buffer) {
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
}
uni.getBluetoothDevices({
success(res) {
console.log(res)
if (res.devices[0]) {
console.log(ab2hex(res.devices[0].advertisData))
}
}
})
注意
- 该接口获取到的设备列表为蓝牙模块生效期间所有搜索到的蓝牙设备,若在蓝牙模块使用流程结束后未及时调用
uni.closeBluetoothAdapter 释放资源,会存在调用该接口会返回之前的蓝牙使用流程中搜索到的蓝牙设备,可能设备已经不在用户身边,无法连接。 - 蓝牙设备在被搜索到时,系统返回的 name 字段一般为广播包中的 LocalName 字段中的设备名称,而如果与蓝牙设备建立连接,系统返回的 name 字段会改为从蓝牙设备上获取到的
GattName 。若需要动态改变设备名称并展示,建议使用 localName 字段。
8、获取本机蓝牙适配器状态
uni.getBluetoothAdapterState(OBJECT)
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
success 返回参数说明:
属性 | 类型 | 说明 |
---|
discovering | boolean | 是否正在搜索设备 | available | boolean | 蓝牙适配器是否可用 |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
示例代码
uni.getBluetoothAdapterState({
success(res) {
console.log(res)
}
})
9、关闭蓝牙模块
uni.closeBluetoothAdapter(OBJECT)
调用该方法将断开所有已建立的连接并释放系统资源。建议在使用蓝牙流程后,与 uni.openBluetoothAdapter 成对调用。
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
示例代码
uni.closeBluetoothAdapter({
success(res) {
console.log(res)
}
})
低功耗蓝牙:
1、设置蓝牙最大传输单元
[uni.setBLEMTU(OBJECT)
需在 uni.createBLEConnection调用成功后调用,mtu 设置范围 (22,512)。安卓5.1以上有效。
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
deviceId | string | | 是 | 用于区分设备的 id | mtu | number | | 是 | 最大传输单元(22,512) 区间内,单位 bytes | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
2、向低功耗蓝牙设备特征值中写入二进制数据
uni.writeBLECharacteristicValue(OBJECT)
注意:必须设备的特征值支持 write 才可以成功调用。
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
deviceId | string | | 是 | 蓝牙设备 id | serviceId | string | | 是 | 蓝牙特征值对应服务的 uuid | characteristicId | string | | 是 | 蓝牙特征值的 uuid | value | ArrayBuffer | | 是 | 蓝牙设备特征值对应的二进制值 | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
注意
- 并行调用多次会存在写失败的可能性。
- APP不会对写入数据包大小做限制,但系统与蓝牙设备会限制蓝牙4.0单次传输的数据大小,超过最大字节数后会发生写入错误,建议每次写入不超过20字节。
- 若单次写入数据过长,iOS 上存在系统不会有任何回调的情况(包括错误回调)。
- 安卓平台上,在调用
notifyBLECharacteristicValueChange 成功后立即调用 writeBLECharacteristicValue 接口,在部分机型上会发生 10008 系统错误
示例代码
const buffer = new ArrayBuffer(1)
const dataView = new DataView(buffer)
dataView.setUint8(0, 0)
uni.writeBLECharacteristicValue({
deviceId,
serviceId,
characteristicId,
value: buffer,
success(res) {
console.log('writeBLECharacteristicValue success', res.errMsg)
}
})
3、读取低功耗蓝牙设备的特征值的二进制数据值
uni.readBLECharacteristicValue(OBJECT)
注意:必须设备的特征值支持 read 才可以成功调用。
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
deviceId | string | | 是 | 蓝牙设备 id | serviceId | string | | 是 | 蓝牙特征值对应服务的 uuid | characteristicId | string | | 是 | 蓝牙特征值的 uuid | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
注意
- 并行调用多次会存在读失败的可能性。
- 接口读取到的信息需要在
onBLECharacteristicValueChange 方法注册的回调中获取。
示例代码
uni.onBLECharacteristicValueChange(function (characteristic) {
console.log('characteristic value comed:', characteristic)
})
uni.readBLECharacteristicValue({
deviceId,
serviceId,
characteristicId,
success(res) {
console.log('readBLECharacteristicValue:', res.errCode)
}
})
4、监听低功耗蓝牙连接状态的改变事件
uni.onBLEConnectionStateChange(CALLBACK)
包括开发者主动连接或断开连接,设备丢失,连接异常断开等等
CALLBACK 返回参数
属性 | 类型 | 说明 |
---|
deviceId | string | 蓝牙设备ID | connected | boolean | 是否处于已连接状态 |
示例代码
uni.onBLEConnectionStateChange(function (res) {
console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`)
})
5、监听低功耗蓝牙设备的特征值变化事件
uni.onBLECharacteristicValueChange(CALLBACK)
必须先启用 notifyBLECharacteristicValueChange 接口才能接收到设备推送的 notification。
CALLBACK 返回参数
属性 | 类型 | 说明 |
---|
deviceId | string | 蓝牙设备 id | serviceId | string | 蓝牙特征值对应服务的 uuid | characteristicId | string | 蓝牙特征值的 uuid | value | ArrayBuffer | 特征值最新的值 |
示例代码
function ab2hex(buffer) {
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
}
uni.onBLECharacteristicValueChange(function (res) {
console.log(`characteristic ${res.characteristicId} has changed, now is ${res.value}`)
console.log(ab2hex(res.value))
})
6、订阅特征值
uni.notifyBLECharacteristicValueChange(OBJECT)
启用低功耗蓝牙设备特征值变化时的 notify 功能,订阅特征值。注意:必须设备的特征值支持 notify 或者 indicate 才可以成功调用。 另外,必须先启用 notifyBLECharacteristicValueChange 才能监听到设备 characteristicValueChange 事件
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
deviceId | string | | 是 | 蓝牙设备 id | serviceId | string | | 是 | 蓝牙特征值对应服务的 uuid | characteristicId | string | | 是 | 蓝牙特征值的 uuid | state | boolean | | 是 | 是否启用 notify | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
注意
- 订阅操作成功后需要设备主动更新特征值的 value,才会触发
uni.onBLECharacteristicValueChange 回调。 - 安卓平台上,在调用
notifyBLECharacteristicValueChange 成功后立即调用 writeBLECharacteristicValue 接口,在部分机型上会发生 10008 系统错误
示例代码
uni.notifyBLECharacteristicValueChange({
state: true,
deviceId,
serviceId,
characteristicId,
success(res) {
console.log('notifyBLECharacteristicValueChange success', res.errMsg)
}
})
7、获取蓝牙设备所有服务(service)
uni.getBLEDeviceServices(OBJECT)
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
deviceId | string | | 是 | 蓝牙设备 id | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
success 返回参数说明:
属性 | 类型 | 说明 |
---|
services | Array | 设备服务列表 |
res.services 的结构
属性 | 类型 | 说明 |
---|
uuid | string | 蓝牙设备服务的 uuid | isPrimary | boolean | 该服务是否为主服务 |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
示例代码
uni.getBLEDeviceServices({
deviceId,
success(res) {
console.log('device services:', res.services)
}
})
8、获取蓝牙设备的信号强度
uni.getBLEDeviceRSSI(OBJECT)
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
deviceId | string | | 是 | 蓝牙设备 id | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
9、获取蓝牙设备某个服务中所有特征值(characteristic)。
uni.getBLEDeviceCharacteristics(OBJECT)
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
deviceId | string | | 是 | 蓝牙设备 id | serviceId | string | | 是 | 蓝牙服务 uuid,需要使用 getBLEDeviceServices 获取 | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
success 返回参数说明:
属性 | 类型 | 说明 |
---|
characteristics | Array | 设备服务列表 |
res.characteristics 的结构
属性 | 类型 | 说明 |
---|
uuid | string | 蓝牙设备特征值的 uuid | properties | Object | 该特征值支持的操作类型 |
properties 的结构
属性 | 类型 | 说明 |
---|
read | boolean | 该特征值是否支持 read 操作 | write | boolean | 该特征值是否支持 write 操作 | notify | boolean | 该特征值是否支持 notify 操作 | indicate | boolean | 该特征值是否支持 indicate 操作 |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
示例代码
uni.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success(res) {
console.log('device getBLEDeviceCharacteristics:', res.characteristics)
}
})
10、连接低功耗蓝牙设备
uni.createBLEConnection(OBJECT)
若APP在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需进行搜索操作。
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
deviceId | string | | 是 | 用于区分设备的 id | timeout | number | | 否 | 超时时间,单位ms,不填表示不会超时 | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
注意
- 请保证尽量成对的调用
createBLEConnection 和 closeBLEConnection 接口。安卓如果多次调用 createBLEConnection 创建连接,有可能导致系统持有同一设备多个连接的实例,导致调用 closeBLEConnection 的时候并不能真正的断开与设备的连接。 - 蓝牙连接随时可能断开,建议监听
uni.onBLEConnectionStateChange 回调事件,当蓝牙设备断开时按需执行重连操作 - 若对未连接的设备或已断开连接的设备调用数据读写操作的接口,会返回 10006 错误,建议进行重连操作。
示例代码
uni.createBLEConnection({
deviceId,
success(res) {
console.log(res)
}
})
11、断开与低功耗蓝牙设备的连接。
uni.closeBLEConnection(OBJECT)
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|
deviceId | string | | 是 | 用于区分设备的 id | success | function | | 否 | 接口调用成功的回调函数 | fail | function | | 否 | 接口调用失败的回调函数 | complete | function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
错误
错误码 | 错误信息 | 说明 |
---|
0 | ok | 正常 | 10000 | not init | 未初始化蓝牙适配器 | 10001 | not available | 当前蓝牙适配器不可用 | 10002 | no device | 没有找到指定设备 | 10003 | connection fail | 连接失败 | 10004 | no service | 没有找到指定服务 | 10005 | no characteristic | 没有找到指定特征值 | 10006 | no connection | 当前连接已断开 | 10007 | property not support | 当前特征值不支持此操作 | 10008 | system error | 其余所有系统上报的异常 | 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
示例代码
uni.closeBLEConnection({
deviceId,
success(res) {
console.log(res)
}
})
实现代码:
<script>
const LAST_CONNECTED_DEVICE = 'last_connected_device';
import PrinterJobs from '../../common/printer/printerjobs';
import printerUtil from '../../common/printer/printerutil';
function inArray(arr, key, val) {
for (let i = 0; i < arr.length; i++) {
if (arr[i][key] === val) {
return i;
}
}
return -1;
}
function ab2hex(buffer) {
const hexArr = Array.prototype.map.call(new Uint8Array(buffer), function(bit) {
return ('00' + bit.toString(16)).slice(-2);
});
return hexArr.join(',');
}
function str2ab(str) {
let buffer = new ArrayBuffer(str.length);
let dataView = new DataView(buffer);
for (let i = 0; i < str.length; i++) {
dataView.setUint8(i, str.charAt(i).charCodeAt(0));
}
return buffer;
}
export default {
data() {
return {
devices:[]
}
};
},
onLoad(e) {
this.openBluetoothAdapter()
},
methods: {
openBluetoothAdapter() {
console.log('初始化蓝牙模块 openBluetoothAdapter');
if (!uni.openBluetoothAdapter) {
console.log('微信版本过低');
uni.showModal({
title: this.$t('wechat.w102'),
content: this.$t('wechat.w226')
});
return;
}
uni.openBluetoothAdapter({
success: res => {
console.log('初始化成功openBluetoothAdapter success', res);
this.startBluetoothDevicesDiscovery();
},
fail: res => {
console.log('初始化失败openBluetoothAdapter fail', res);
if (res.errCode === 10001) {
uni.showModal({
title: this.$t('wechat.w227'),
content: this.$t('wechat.w228'),
showCancel: false
});
uni.onBluetoothAdapterStateChange(res => {
console.log('监听蓝牙适配器状态 onBluetoothAdapterStateChange', res);
if (res.available) {
this.startBluetoothDevicesDiscovery();
}
});
}
}
});
},
startBluetoothDevicesDiscovery() {
if (this._discoveryStarted) {
return;
}
this._discoveryStarted = true;
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 0,
success: res => {
console.log('搜寻附近的蓝牙外围设备 startBluetoothDevicesDiscovery success111', res);
this.onBluetoothDeviceFound();
},
fail: res => {
console.log('搜寻附近的蓝牙外围设备 startBluetoothDevicesDiscovery fail', res);
}
});
},
onBluetoothDeviceFound() {
console.log('进入查询设备');
uni.onBluetoothDeviceFound(res => {
console.log('寻找设备', res.devices);
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return;
}
const foundDevices = this.devices;
const idx = inArray(foundDevices, 'deviceId', device.deviceId);
const data = {};
if (idx === -1) {
this.$set(this.devices, `${foundDevices.length}`, device);
} else {
this.$set(this.devices, `${idx}`, device);
}
});
});
},
createBLEConnection(e) {
console.log('点击连接蓝牙', e);
const deviceId = e.deviceId;
const name = e.name;
this._createBLEConnection(deviceId, name);
},
_createBLEConnection(deviceId, name) {
this.$myToast(this.$t('wechat.w224'), 'loading');
uni.createBLEConnection({
deviceId,
success: () => {
console.log('连接蓝牙接口调用成功 createBLEConnection success', this.devices);
this.devices.forEach((item, index) => {
this.$set(this.devices[index], 'isShowConnect', false);
if (item.deviceId === deviceId) {
this.$set(this.devices[index], 'isShowConnect', true);
}
});
this.$myToast(this.$t('wechat.w225'), 'success');
this.connected = true;
this.isConnected = false;
this.name = name;
this.deviceId = deviceId;
this.getBLEDeviceServices(deviceId);
uni.setStorage({
key: LAST_CONNECTED_DEVICE,
data: name + ':' + deviceId
});
},
complete() {
uni.hideLoading();
},
fail: res => {
console.log('连接蓝牙接口调用失败 createBLEConnection fail', res);
uni.showModal({
title: this.$t('wechat.w227'),
content: '蓝牙连接失败',
showCancel: false
});
}
});
this.stopBluetoothDevicesDiscovery();
},
getBLEDeviceServices(deviceId) {
uni.getBLEDeviceServices({
deviceId,
success: res => {
console.log('获取蓝牙设备所有服务 getBLEDeviceServices', res);
for (let i = 0; i < res.services.length; i++) {
if (res.services[i].isPrimary) {
this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid);
return;
}
}
}
});
},
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery({
complete: () => {
this._discoveryStarted = false;
}
});
},
getBLEDeviceCharacteristics(deviceId, serviceId) {
uni.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: res => {
console.log('特征值变化 getBLEDeviceCharacteristics success', res.characteristics);
for (let i = 0; i < res.characteristics.length; i++) {
const item = res.characteristics[i];
if (item.properties.write) {
this.canWrite = true;
this._deviceId = deviceId;
this._serviceId = serviceId;
this._characteristicId = item.uuid;
}
if (item.properties.notify || item.properties.indicate) {
uni.notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId: item.uuid,
state: true
});
}
}
},
fail(res) {
console.error('特征值变化 getBLEDeviceCharacteristics', res);
}
});
},
writeBLECharacteristicValue() {
this.isLoading = true;
setTimeout(() => {
this.isDisabled = false;
this.isLoading = false;
}, 3000);
let printerJobs = new PrinterJobs();
const { channels, header, dataList } = this.printInfo;
let title = '';
header.forEach(item => {
title = `${item.name} `;
});
printerJobs
.setAlign('ct')
.setSize(2, 2)
.print(this.$t('wechat.w221'))
.setSize(0, 0)
.print()
.setAlign('lt')
.setSize(1, 1)
.print(`${this.$t('wechat.w51')}:${this.info.name}`)
.print(`${this.$t('wechat.w76')}:${this.info.modelName}`)
.print(`${this.$t('wechat.w46')}:${this.info.deviceSerial}`)
.print(`${this.$t('wechat.w100')}:${this.userInfo.relName}`)
.print(`${this.$t('wechat.w101')}:${this.remark}`);
if (this.isEn) {
channels.forEach(item => {
printerJobs
.print(`${item.name}(Max):${item.max}${item.unitIcon}`)
.print(`${this.$t('wechat.w148')}:${this.$timestampToTimeEn(item.maxDate)}`)
.print(`${item.name}(Min):${item.min}${item.unitIcon}`)
.print(`${this.$t('wechat.w148')}:${this.$timestampToTimeEn(item.minDate)}`);
});
} else {
channels.forEach(item => {
printerJobs
.print(`${item.name}(Max):${item.max}${item.unitIcon}`)
.print(`${this.$t('wechat.w148')}:${this.$timestampToTime2(item.maxDate)}`)
.print(`${item.name}(Min):${item.min}${item.unitIcon}`)
.print(`${this.$t('wechat.w148')}:${this.$timestampToTime2(item.minDate)}`);
});
}
printerJobs.print(printerUtil.fillLine()).setSize(1, 1);
let titleStr = '';
header.forEach((item, index) => {
titleStr = titleStr + `${index === 0 ? '' : ' '}` + `${item.name}`;
});
printerJobs.print(printerUtil.inline(this.$t('wechat.w222'), `${titleStr}`));
printerJobs.print(printerUtil.fillLine());
dataList.forEach(item => {
let str = '';
header.forEach((item2, index2) => {
str = str + `${index2 === 0 ? '' : ' '}` + `${item[item2.columnName] ? item[item2.columnName].toFixed(2) : this.$t('wechat.w71empty')}`;
});
if (this.isEn) {
printerJobs.print(printerUtil.inline(`${this.$timestampToTimeEn2(item.dataTime)}`, `${str}`));
} else {
printerJobs.print(printerUtil.inline(`${this.$timestampToTime3(item.dataTime)}`, `${str}`));
}
});
printerJobs
.println()
.print(`${this.$t('wechat.w223')}:`)
.println()
.println();
let buffer = printerJobs.buffer();
const maxChunk = 20;
const delay = 40;
for (let i = 0, j = 0, length = buffer.byteLength; i < length; i += maxChunk, j++) {
let subPackage = buffer.slice(i, i + maxChunk <= length ? i + maxChunk : length);
setTimeout(this._writeBLECharacteristicValue, j * delay, subPackage);
}
},
_writeBLECharacteristicValue(buffer) {
uni.writeBLECharacteristicValue({
deviceId: this._deviceId,
serviceId: this._serviceId,
characteristicId: this._characteristicId,
value: buffer,
success(res) {
console.log('writeBLECharacteristicValue success', res);
},
fail(res) {
console.log('writeBLECharacteristicValue fail', res);
}
});
},
}
打印效果:
其他文件:
printerutil.js
const PAGE_WIDTH = 384;
const MAX_CHAR_COUNT_EACH_LINE = 32;
function isChinese(str) {
return /^[\u4e00-\u9fa5]$/.test(str);
}
function getStringWidth(str) {
let width = 0;
for (let i = 0, len = str.length; i < len; i++) {
width += isChinese(str.charAt(i)) ? 2 : 1;
}
return width;
}
function inline(str1, str2, fillWith = ' ', fontWidth = 1) {
const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;
let fillCount = lineWidth - (getStringWidth(str1) + getStringWidth(str2)) % lineWidth;
let fillStr = new Array(fillCount).fill(fillWith.charAt(0)).join('');
return str1 + fillStr + str2;
}
function fillLine(fillWith = '-', fontWidth = 1) {
const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;
return new Array(lineWidth).fill(fillWith.charAt(0)).join('');
}
function fillAround(str, fillWith = '-', fontWidth = 1) {
const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;
let strWidth = getStringWidth(str);
if (strWidth >= lineWidth) {
return str;
}
let fillCount = lineWidth - strWidth;
let leftCount = Math.round(fillCount / 2);
let fillStr = new Array(leftCount).fill(fillWith.charAt(0)).join('');
return fillStr + str + fillStr.substr(0, fillCount - leftCount);
}
module.exports = {
inline: inline,
fillLine: fillLine,
fillAround: fillAround,
};
printerjobs.js
const commands = require('./commands.js');
const TextEncoder = require('../text-encoding/index').TextEncoder;
const printerJobs = function () {
this._queue = Array.from(commands.HARDWARE.HW_INIT);
this._encoder = new TextEncoder("gb2312", {NONSTANDARD_allowLegacyEncoding: true});
this._enqueue = function (cmd) {
this._queue.push.apply(this._queue, cmd);
}
};
printerJobs.prototype.text = function (content) {
if (content) {
let uint8Array = this._encoder.encode(content);
let encoded = Array.from(uint8Array);
this._enqueue(encoded);
}
return this;
};
printerJobs.prototype.print = function (content) {
this.text(content);
this._enqueue(commands.LF);
return this;
};
printerJobs.prototype.println = function (content = '') {
return this.print(content + commands.EOL);
};
printerJobs.prototype.setAlign = function (align) {
this._enqueue(commands.TEXT_FORMAT['TXT_ALIGN_' + align.toUpperCase()]);
return this;
};
printerJobs.prototype.setFont = function (family) {
this._enqueue(commands.TEXT_FORMAT['TXT_FONT_' + family.toUpperCase()]);
return this;
};
printerJobs.prototype.setSize = function (width, height) {
if (2 >= width && 2 >= height) {
this._enqueue(commands.TEXT_FORMAT.TXT_NORMAL);
if (2 === width && 2 === height) {
this._enqueue(commands.TEXT_FORMAT.TXT_4SQUARE);
} else if (1 === width && 2 === height) {
this._enqueue(commands.TEXT_FORMAT.TXT_2HEIGHT);
} else if (2 === width && 1 === height) {
this._enqueue(commands.TEXT_FORMAT.TXT_2WIDTH);
}
}
return this;
};
printerJobs.prototype.setBold = function (bold) {
if (typeof bold !== 'boolean') {
bold = true;
}
this._enqueue(bold ? commands.TEXT_FORMAT.TXT_BOLD_ON : commands.TEXT_FORMAT.TXT_BOLD_OFF);
return this;
};
printerJobs.prototype.setUnderline = function (underline) {
if (typeof underline !== 'boolean') {
underline = true;
}
this._enqueue(underline ? commands.TEXT_FORMAT.TXT_UNDERL_ON : commands.TEXT_FORMAT.TXT_UNDERL_OFF);
return this;
};
printerJobs.prototype.setLineSpacing = function (n) {
if (n === undefined || n === null) {
this._enqueue(commands.LINE_SPACING.LS_DEFAULT);
} else {
this._enqueue(commands.LINE_SPACING.LS_SET);
this._enqueue([n]);
}
return this;
};
printerJobs.prototype.lineFeed = function (n = 1) {
return this.print(new Array(n).fill(commands.EOL).join(''));
};
printerJobs.prototype.setColor = function (color) {
this._enqueue(commands.COLOR[color === 1 ? 1 : 0]);
return this;
};
printerJobs.prototype.beep = function (n, t) {
this._enqueue(commands.BEEP);
this._enqueue([n, t]);
return this;
};
printerJobs.prototype.clear = function () {
this._queue = Array.from(commands.HARDWARE.HW_INIT);
return this;
};
printerJobs.prototype.buffer = function () {
return new Uint8Array(this._queue).buffer;
};
module.exports = printerJobs;
commands.js
var _ = {
LF: [0x0a],
FS: [0x1c],
FF: [0x0c],
GS: [0x1d],
DLE: [0x10],
EOT: [0x04],
NUL: [0x00],
ESC: [0x1b],
EOL: '\n',
};
_.FEED_CONTROL_SEQUENCES = {
CTL_LF: [0x0a],
CTL_GLF: [0x4a, 0x00],
CTL_FF: [0x0c],
CTL_CR: [0x0d],
CTL_HT: [0x09],
CTL_VT: [0x0b],
};
_.CHARACTER_SPACING = {
CS_DEFAULT: [0x1b, 0x20, 0x00],
CS_SET: [0x1b, 0x20]
};
_.LINE_SPACING = {
LS_DEFAULT: [0x1b, 0x32],
LS_SET: [0x1b, 0x33]
};
_.HARDWARE = {
HW_INIT: [0x1b, 0x40],
HW_SELECT: [0x1b, 0x3d, 0x01],
HW_RESET: [0x1b, 0x3f, 0x0a, 0x00],
};
_.CASH_DRAWER = {
CD_KICK_2: [0x1b, 0x70, 0x00],
CD_KICK_5: [0x1b, 0x70, 0x01],
};
_.MARGINS = {
BOTTOM: [0x1b, 0x4f],
LEFT: [0x1b, 0x6c],
RIGHT: [0x1b, 0x51],
};
_.PAPER = {
PAPER_FULL_CUT: [0x1d, 0x56, 0x00],
PAPER_PART_CUT: [0x1d, 0x56, 0x01],
PAPER_CUT_A: [0x1d, 0x56, 0x41],
PAPER_CUT_B: [0x1d, 0x56, 0x42],
};
_.TEXT_FORMAT = {
TXT_NORMAL: [0x1b, 0x21, 0x00],
TXT_2HEIGHT: [0x1b, 0x21, 0x10],
TXT_2WIDTH: [0x1b, 0x21, 0x20],
TXT_4SQUARE: [0x1b, 0x21, 0x30],
TXT_UNDERL_OFF: [0x1b, 0x2d, 0x00],
TXT_UNDERL_ON: [0x1b, 0x2d, 0x01],
TXT_UNDERL2_ON: [0x1b, 0x2d, 0x02],
TXT_BOLD_OFF: [0x1b, 0x45, 0x00],
TXT_BOLD_ON: [0x1b, 0x45, 0x01],
TXT_ITALIC_OFF: [0x1b, 0x35],
TXT_ITALIC_ON: [0x1b, 0x34],
TXT_FONT_A: [0x1b, 0x4d, 0x00],
TXT_FONT_B: [0x1b, 0x4d, 0x01],
TXT_FONT_C: [0x1b, 0x4d, 0x02],
TXT_ALIGN_LT: [0x1b, 0x61, 0x00],
TXT_ALIGN_CT: [0x1b, 0x61, 0x01],
TXT_ALIGN_RT: [0x1b, 0x61, 0x02],
};
_.BARCODE_FORMAT = {
BARCODE_TXT_OFF: [0x1d, 0x48, 0x00],
BARCODE_TXT_ABV: [0x1d, 0x48, 0x01],
BARCODE_TXT_BLW: [0x1d, 0x48, 0x02],
BARCODE_TXT_BTH: [0x1d, 0x48, 0x03],
BARCODE_FONT_A: [0x1d, 0x66, 0x00],
BARCODE_FONT_B: [0x1d, 0x66, 0x01],
BARCODE_HEIGHT: function (height) {
return [0x1d, 0x68, height];
},
BARCODE_WIDTH: function (width) {
return [0x1d, 0x77, width];
},
BARCODE_HEIGHT_DEFAULT: [0x1d, 0x68, 0x64],
BARCODE_WIDTH_DEFAULT: [0x1d, 0x77, 0x01],
BARCODE_UPC_A: [0x1d, 0x6b, 0x00],
BARCODE_UPC_E: [0x1d, 0x6b, 0x01],
BARCODE_EAN13: [0x1d, 0x6b, 0x02],
BARCODE_EAN8: [0x1d, 0x6b, 0x03],
BARCODE_CODE39: [0x1d, 0x6b, 0x04],
BARCODE_ITF: [0x1d, 0x6b, 0x05],
BARCODE_NW7: [0x1d, 0x6b, 0x06],
BARCODE_CODE93: [0x1d, 0x6b, 0x48],
BARCODE_CODE128: [0x1d, 0x6b, 0x49],
};
_.IMAGE_FORMAT = {
S_RASTER_N: [0x1d, 0x76, 0x30, 0x00],
S_RASTER_2W: [0x1d, 0x76, 0x30, 0x01],
S_RASTER_2H: [0x1d, 0x76, 0x30, 0x02],
S_RASTER_Q: [0x1d, 0x76, 0x30, 0x03],
};
_.BITMAP_FORMAT = {
BITMAP_S8: [0x1b, 0x2a, 0x00],
BITMAP_D8: [0x1b, 0x2a, 0x01],
BITMAP_S24: [0x1b, 0x2a, 0x20],
BITMAP_D24: [0x1b, 0x2a, 0x21]
};
_.GSV0_FORMAT = {
GSV0_NORMAL: [0x1d, 0x76, 0x30, 0x00],
GSV0_DW: [0x1d, 0x76, 0x30, 0x01],
GSV0_DH: [0x1d, 0x76, 0x30, 0x02],
GSV0_DWDH: [0x1d, 0x76, 0x30, 0x03]
};
_.BEEP = [0x1b, 0x42];
_.COLOR = {
0: [0x1b, 0x72, 0x00],
1: [0x1b, 0x72, 0x01]
};
module.exports = _;
注: 1、连接的蓝牙必须是低功耗的蓝牙,经典蓝牙无法搜索到(因为不能执行uni.onBluetoothDeviceFound) 2、部分手机需要将定位打开才能搜索到蓝牙(开启定位才能执行uni.onBluetoothDeviceFound)
|