前言:
由于公司业务需求,在原有的APP(H5开发)的基础上,搞一套小程序版本的项目(小程序内嵌H5开发)。为此顺便学习了一下小程序的开发以及连接蓝牙打印机的功能,记录一下开发过程中的一些要点,有需要的小伙伴可以借鉴一下
实现:
目前小程序生态越来越丰富,微信给予了小程序一定的硬件通信能力,比如外部设备—蓝牙。开发过程中需要用到的小程序API有如下几种:
1、wx.openBluetoothAdapter(Object object) 初始化蓝牙设备
2、wx.getBluetoothAdapterState(Object object) 获取本机蓝牙适配器状态
3、wx.startBluetoothDevicesDiscovery(Object object) 开始搜寻附近的蓝牙外围设备
4、wx.onBluetoothDeviceFound(function callback) 监听寻找到新设备的事件
5、wx.onBluetoothAdapterStateChange(function callback) 监听蓝牙适配器状态变化事件
6、wx.createBLEConnection(Object object) 连接低功耗蓝牙设备
7、wx.stopBluetoothDevicesDiscovery(Object object) 停止搜寻附近的蓝牙外围设备(连接成功后调用)
8、wx.getBLEDeviceServices(Object object) 获取蓝牙设备所有服务(service)
9、wx.getBLEDeviceCharacteristics(Object object) 获取蓝牙设备某个服务中所有特征值(characteristic)
10、wx.notifyBLECharacteristicValueChange(Object object) 启用低功耗蓝牙设备特征值变化时的 notify 功能
11、wx.onBLECharacteristicValueChange(function callback) 监听低功耗蓝牙设备的特征值变化事件
12、wx.writeBLECharacteristicValue(Object object) 向低功耗蓝牙设备特征值中写入二进制数据。注意:必须设备的特征值支持 write 才可以成功调用
小程序项目结构如下:
小程序中内嵌H5网页是这样的:
view页面:
<view class="container">
<web-view src="{
{url}}"></web-view>
</view>
js页面:
const app = getApp()
Page({
data: {
url: 'http://www.baidu.com' //你自己的页面
},
onLoad: function (options) {
if(options.url!="" && options.url!=null){
this.setData({
url: options.url //根据业务需求动态改变显示页面
})
}
}
})
第一步:打开蓝牙,初始化蓝牙设备信息
wx.openBluetoothAdapter({
success: (res) => {
console.log('第一步、蓝牙初始化成功', res)
},
fail: (res) => {
console.log("第一步、蓝牙初始化失败", res);
wx.showToast({
title: '蓝牙初始化失败', icon: 'none' })
}
})
第二步:获取本机蓝牙适配器状态(可根据自己的业务需求来做处理,此处不做处理)
wx.getBluetoothAdapterState({
success: function (res) {
console.log(res)
}
})
第三步:开始搜寻附近的蓝牙外围设备
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
powerLevel: "high", //加快搜索速度
success: function (res) {
console.log(res)
that.setData({
searching: true,
devicesList: []
})
}
})
第四步:连接蓝牙打印机(点击事件连接)
<block wx:for="{
{devicesList}}" wx:key="deviceId">
<view class="list-item" id="{
{item.deviceId}}" bindtap="Connect">
<view style="display:flex;flex-direction:column;width:80%">
<text style="font-size:medium;word-break:break-all">设备名称: {
{
item.name}}</text>
<text style="font-size:x-small;color:gray;word-break:break-all">设备ID: {
{
item.deviceId}}</text>
<text style="font-size:x-small;color:gray;word-break:break-all">信号强度RSSI: {
{
item.RSSI}}</text>
</view>
<image style="width:36px;height:36px" mode="aspectFit" src="/pages/images/bluetooth.png"></image>
</view>
</block>
Connect: function (e) {
var that = this
var advertisData, name
console.log(e.currentTarget.id)
for (var i = 0; i < that.data.devicesList.length; i++) {
if (e.currentTarget.id == that.data.devicesList[i].deviceId) {
name = that.data.devicesList[i].name
advertisData = that.data.devicesList[i].advertisData
}
}
wx.showLoading({
title: '连接蓝牙设备中...',
})
wx.createBLEConnection({
deviceId: e.currentTarget.id,
success: function (res) {
console.log(res)
wx.hideLoading()
wx.showToast({
title: '连接成功',
icon: 'success',
duration: 1000
})
wx.setStorage({
data: e.currentTarget.id,
key: 'deviceId',
})
wx.stopBluetoothDevicesDiscovery({
success :function(res) {
console.log("停止搜索结果:",res);
}
})
},
fail: function (res) {
console.log(res)
wx.hideLoading()
wx.showModal({
title: '提示',
content: '连接失败',
showCancel: false
})
}
})
},
第五步、获取蓝牙设备所有服务(service)
wx.getBLEDeviceServices({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId,
success (res) {
console.log('device services:', res.services)
}
})
第六步、 获取蓝牙设备某个服务中所有特征值(characteristic)
wx.getBLEDeviceCharacteristics({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId,
success (res) {
console.log('device getBLEDeviceCharacteristics:', res.characteristics)
}
})
第七步,启用notify成功
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId,
success (res) {
console.log('notifyBLECharacteristicValueChange success', res.errMsg)
}
})
第八步:向低功耗蓝牙设备特征值中写入二进制数据
wx.writeBLECharacteristicValue({
deviceId: _readDeviceId, //设备deviceId
serviceId: _serviceId, //设备service_id
characteristicId:_characteristicId, //设备write特征值
value: TempBuffer, //写入数据
success: function (res) {
console.log('writeBLECharacteristicValue success ->'+i, res)
},
fail: function (res) {
console.log('writeBLECharacteristicValue fail', res)
}
})
第九步:监听低功耗蓝牙设备的特征值变化事件
wx.onBLECharacteristicValueChange(function(res) {
console.log(`characteristic ${
res.characteristicId} has changed, now is ${
res.value}`)
console.log(ab2hex(res.value))
})
核心代码如下:
var _deviceId = "";
var _serviceId = "";
var _characteristicId = "";
var _readDeviceId = "";
var _readServiceId = "";
var _readCharacteristicId = "";
wx.createBLEConnection({
deviceId: deviceId, //打印机Id
success:function(res){
console.log("蓝牙连接成功",res);
wx.getBLEDeviceServices({
// 第五步、获取蓝牙设备所有服务(service)。
deviceId: deviceId,
success: (res) => {
console.log('蓝牙设备所有服务', res)
for (var i = 0; i < res.services.length; i++) {
if (res.services[i].isPrimary) {
var sId = res.services[i].uuid;
wx.getBLEDeviceCharacteristics({
// 第六步、 获取蓝牙设备某个服务中所有特征值(characteristic)
deviceId, serviceId:sId,
success: (res) => {
console.log("获取蓝牙设备某个服务中所有特征值(characteristic)",res)
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i]
if (item.properties.write) {
_deviceId = deviceId
_serviceId = sId
_characteristicId = item.uuid
}
if (item.properties.notify) {
_readDeviceId = deviceId
_readServiceId = sId
_readCharacteristicId = item.uuid
}
}
wx.onBLECharacteristicValueChange(function (res) {
console.log("第七步,读取蓝牙的值", res.value);
})
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: _readDeviceId,
serviceId: _readServiceId,
characteristicId: _readCharacteristicId,
success(res) {
console.log('第七步,启用notify成功', res.errMsg)
for(var k=0;k<2;k++){
//连续打2次
var sendData ="你好,这是测试数据";
let buffer = that.gbkToArray(sendData);
var length = buffer.byteLength;
console.log("length:",length);
var num= Math.ceil(length/20); //最多执行 num次
for(var i=0;i<num;i++){
//对buffer进行分包,最大不超过20字节
let TempBuffer;
if(((i+1)*20)<length){
TempBuffer = buffer.slice(i*20,(i+1)*20);
}else{
TempBuffer = buffer.slice(i*20,length);
}
that.sleep(0.02); //延迟200ms
//写入设备
wx.writeBLECharacteristicValue({
deviceId: _readDeviceId, //设备deviceId
serviceId: _serviceId, //设备service_id
characteristicId:_characteristicId, //设备write特征值
value: TempBuffer, //写入数据
success: function (res) {
console.log('writeBLECharacteristicValue success ->'+i, res)
},
fail: function (res) {
console.log('writeBLECharacteristicValue fail', res)
}
})
}
}
wx.reLaunch({
url: '/pages/index/index?url=http://www.baidu.com',
})
}
})
}
})
}
}
},
fail(res) {
console.log('蓝牙设备所有服务失败', res) }
})
},
fail(res) {
wx.showToast({
title: '蓝牙连接失败,请返回上一层,稍候再试!', icon: 'none' }) }
})
解决中文乱码的问题:
网上有一些现成的库,https://github.com/inexorabletash/text-encoding
下载截图中这两个js,并导入到小程序中,用法如下:
import {
TextEncoder } from '../comm/encoding';
gbkToArray:function(content){
var _encoder = new TextEncoder("gb2312", {
NONSTANDARD_allowLegacyEncoding: true});
// content 需要打印的字符串
const val = _encoder.encode(content);
//console.log("gbkToArryval",val);
return val.buffer;
}
补充 js:
sleep:function(delay) {
var start = (new Date()).getTime();
while ((new Date()).getTime() - start < delay) {
continue;
}
},
至此,小程序连接蓝牙打印机打印已完成。由于时间关系,写得比较笼统,有任何问题,欢迎留言交流。谢谢!