在移动设备和物联网(IoT)设备日益普及的今天,蓝牙技术已经成为我们日常生活中不可或缺的一部分。特别是在需要低功耗、短距离通信的应用场景中,低功耗蓝牙(BLE, Bluetooth Low Energy)因其节能特性而受到广泛关注。本文将详细介绍低功耗蓝牙连接的工作原理、优势以及如何实现一个完整的低功耗蓝牙连接过程。
BLE 的核心特点:
-
低功耗:相比传统蓝牙,BLE 在待机状态下几乎不消耗电量。
-
低成本:BLE 芯片成本较低,适合大规模部署。
-
快速连接:BLE 设备之间的连接速度非常快,通常在几毫秒内完成。
-
小数据包传输:适用于少量数据的频繁传输。
二、BLE 连接的基本流程
BLE 连接主要包括以下几个步骤:
-
扫描(Scanning)
- 中心设备(Central Device)主动扫描周围广播的外围设备(Peripheral Device)。
- 外围设备通过广播信道发送广告包(Advertising Packet),包含设备名称、服务 UUID 等信息。
-
连接建立(Connection Establishment)
- 中心设备选择目标外围设备后,发起连接请求。
- 双方协商连接参数,如连接间隔、超时时间等。
-
服务发现(Service Discovery)
- 连接成功后,中心设备会查询外围设备提供的服务(Services)和特征值(Characteristics)。
-
数据交互(Data Exchange)
- 通过读写特征值或使用通知机制进行数据交换。
-
断开连接(Disconnection)
-
当不再需要通信时,任一方可以主动断开连接以节省能耗。
三、代码实践
1. 页面结构与 UI 设计
该页面提供了一个用户界面,允许用户搜索并选择附近的 BLE 设备进行打印操作。UI 包含标题、提示信息、设备列表等元素。
<template>
<div class="bluetooth-container">
<h2 class="bluetooth-title">请选择蓝牙设备进行打印</h2>
<p class="bluetooth-hint">推荐使用低功耗蓝牙打印机,推荐型号:p_11</p>
<div class="bluetooth-list">
<div class="bluetooth-header">
<div class="device-name">设备名称</div>
<div class="device-status">设备状态</div>
</div>
<div v-for="(item, index) in matchDevice" :key="index" class="bluetooth-item" @click="handlePrint(item.id, index)">
<div class="device-name">{{ item.name }}</div>
<div class="device-status">{{ item.device_status === 1 ? "可用" : "不可用" }}</div>
</div>
</div>
</div>
</template>
2. BLE 初始化与权限申请
初始化蓝牙模块
async initBluetooth() { console.log('开始初始化蓝牙模块---->',); this.blueToothTip = "初始化蓝牙模块--------"; var _this = this; // 打开蓝牙 plus.bluetooth.openBluetoothAdapter({ success: function(e) { _this.blueToothTip = "蓝牙打开成功... "; }, fail: function(e) { _this.blueToothTip = "蓝牙打开失败,请手动操作..."; _this.loading = false; }, // 打开蓝牙完成回调函数 complete(e) { if (!e.errCode) { _this.blueToothTip = "初始化完成..."; _this.blueToothTip = "开始搜索设备..."; // 开始搜索设备 _this.searchDevices(); } else if (e.errCode == 10001) { _this.$toast({ icon: "none", title: "请打开手机蓝牙" }); } else { _this.$toast({ icon: "none", title: e.errMsg }); } } }); },
3.Android 权限请求
由于 Android 对位置权限有严格限制,BLE 搜索必须先获取 ACCESS_COARSE_LOCATION 权限:
requestAndroidPermission(permissionID) {
return new Promise((resolve, reject) => {
plus.android.requestPermissions([permissionID], function(resultObj) {
// 处理授权结果
});
});
}
4. 搜索 BLE 设备
searchDevices(address = "C8:47:54:BD:33:A8", index) {
plus.bluetooth.startBluetoothDevicesDiscovery({
success: function(e) {
console.log("搜索设备成功");
},
fail: function(e) {
console.error("搜索设备失败");
},
complete: async (e) => {
if (!e.errCode) {
let main = plus.android.runtimeMainActivity();
let IntentFilter = plus.android.importClass("android.content.IntentFilter");
let BluetoothDevice = plus.android.importClass("android.bluetooth.BluetoothDevice");
let receiver = plus.android.implements("io.dcloud.android.content.BroadcastReceiver", {
onReceive: function(context, intent) {
if (intent.getAction() == "android.bluetooth.adapter.action.DISCOVERY_FINISHED") {
main.unregisterReceiver(receiver);
console.log("搜索结束");
} else {
let device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getName()) {
let obj = {
id: device.getAddress(),
name: device.getName(),
device_status: device.getName() == "P11_PRINTER" ? 1 : 0
};
this.matchDevice.push(obj);
}
}
}
});
let filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
main.registerReceiver(receiver, filter);
}
}
});
}
5. BLE 打印逻辑实现
连接设备并发送打印指令
async handlePrint(deviceMac, index) {
const UUID = plus.android.importClass("java.util.UUID");
const uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
const BAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter").getDefaultAdapter();
const device = BAdapter.getRemoteDevice(deviceMac);
const bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(uuid);
await bluetoothSocket.connect();
const outputStream = bluetoothSocket.getOutputStream();
const writer = new OutputStreamWriter(outputStream, "GBK");
// 发送打印命令
await writer.write("\x1B\x45\x01"); // 加粗
await writer.write("车牌号:" + this.vehicleItem.licensePlate + "\r\n");
await writer.write("停车地点:路侧test" + this.vehicleItem.berthNumber + "\r\n");
await writer.write("入场时间:" + this.vehicleItem.entryTime + "\r\n");
await writer.write("离场时间:" + this.vehicleItem.exitTime + "\r\n");
await writer.write("需要缴费:" + this.vehicleItem.fee + "\r\n");
await writer.flush();
bluetoothSocket.close();
}
这个是我连接的小票机(美恒通联系他客户可以给到项目测试源码,但是那个是小程序版本的),而且目前市场上也可以下载到美恒通官网提供的打印软件apk,问客户是否有apk版本的demo代码,他们说没有。
这里电脑跑的是小程序版本,手机跑的是自己的项目
这是打印出来的效果,还是支持打印二维码的,如上图。