如果要使用的话建议用uts改写,连接蓝牙是耗时操作,使用plus对象无法通过plus.android.importClass('java.lang.Thread')将耗时操作放入子线程,会导致页面卡顿。
javascript
//经典蓝牙服务的UUID
const UUIDString = "00001101-0000-1000-8000-00805F9B34FB";
class Bluetooth {
//蓝牙类的实例
instance;
/**当前程序页面上下文 */
Activity;
/**蓝牙适配器 */
Adapter;
/**蓝牙建立的连接 */
BluetoothSocket;
/**蓝牙适配器接收器 */
BluetoothReciever;
/**蓝牙所需的权限 */
permissions = [];
/**搜索到蓝牙的回调 */
onBluetoothDeviceFoundCallBack = () => {};
/**蓝牙状态变更 */
onBluetoothConnectedChangeCallback = () => {};
/**蓝牙适配器状态变更 */
onBluetoothAdapterChangeCallback = () => {};
//初始化
constructor() {
if (Bluetooth.instance) return Bluetooth.instance;
Bluetooth.instance = this;
return Bluetooth.instance;
}
//初始化蓝牙适配器
init() {
this.Activity = plus.android.runtimeMainActivity();
const BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");
const BluetoothDevice = plus.android.importClass("android.bluetooth.BluetoothDevice");
const Intent = plus.android.importClass("android.content.Intent");
//初始化蓝牙适配器
this.Adapter = BluetoothAdapter.getDefaultAdapter();
//校验是否存在蓝牙权限
if (!this.Adapter) return showToast({ position: "top", message: "当前设备不支持蓝牙!" });
//保存this指向
//如果适配器不可用跳往设置页
if (!this.Adapter.isEnabled) {
//创建意图
const intent = new Intent(this.Adapter.ACTION_REQUEST_ENABLE);
//跳转至蓝牙设置
plus.android.invoke(this.Activity, "startActivity", intent, 1, null);
return;
}
const Manifest = plus.android.importClass("android.Manifest");
this.permissions = [
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADVERTISE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
];
//蓝牙开关变化常量
const STATE_CHANGED = BluetoothAdapter.ACTION_STATE_CHANGED;
//蓝牙连接常量
const ACTION_ACL_CONNECTED = BluetoothDevice.ACTION_ACL_CONNECTED;
//蓝牙断开连接常量
const ACTION_ACL_DISCONNECTED = BluetoothDevice.ACTION_ACL_DISCONNECTED;
//搜索到蓝牙常量
const ACTION_FOUND = BluetoothDevice.ACTION_FOUND;
//保存this指向
const that = this;
//接收广播(注意:这里广播的类需要加io.dcloud前缀,不加会出现报错无法执行)
this.BluetoothReciever = plus.android.implements("io.dcloud.android.content.BroadcastReceiver", {
//接收蓝牙发出的广播
onReceive: function (context, intent) {
//获取广播意图
const action = plus.android.invoke(intent, "getAction");
//获取蓝牙设备信息
const device = plus.android.invoke(intent, "getParcelableExtra", "android.bluetooth.device.extra.DEVICE");
//获取蓝牙设备名称
const deviceName = device.getName();
if (!deviceName) return;
//获取蓝牙设备id
const deviceId = device.getAddress();
switch (action) {
//蓝牙开关变化
case STATE_CHANGED:
//获取蓝牙广播状态
const EXTRA_STATE = plus.android.getAttribute(new BluetoothAdapter(), "EXTRA_STATE");
//广播状态码
const code = plus.android.invoke(intent, "getIntExtra", EXTRA_STATE, -1);
switch (code) {
case BluetoothAdapter.STATE_OFF:
that.onBluetoothAdapterChangeCallback({ state: false });
break;
case BluetoothAdapter.STATE_ON:
that.onBluetoothAdapterChangeCallback({ state: true });
break;
}
break;
//蓝牙连接成功
case ACTION_ACL_CONNECTED:
that.onBluetoothConnectedChangeCallback({ name: deviceName, deviceId, status: true });
break;
//蓝牙断开连接成功
case ACTION_ACL_DISCONNECTED:
//蓝牙断开则把建立的socket置空
that.BluetoothSocket = null;
that.onBluetoothConnectedChangeCallback({ name: deviceName, deviceId, status: false });
break;
//搜索到蓝牙
case ACTION_FOUND:
if (!deviceName) return;
that.onBluetoothDeviceFoundCallBack({ name: deviceName, deviceId });
break;
}
}
});
//创建意图过滤器,添加需要监听的蓝牙广播动作
const IntentFilter = plus.android.newObject("android.content.IntentFilter");
// 监听蓝牙开关状态变化(核心广播)
plus.android.invoke(IntentFilter, "addAction", STATE_CHANGED);
// 监听蓝牙设备连接成功
plus.android.invoke(IntentFilter, "addAction", ACTION_ACL_CONNECTED);
// 监听蓝牙设备断开连接
plus.android.invoke(IntentFilter, "addAction", ACTION_ACL_DISCONNECTED);
// 监听搜索到的蓝牙
plus.android.invoke(IntentFilter, "addAction", ACTION_ACL_DISCONNECTED);
//搜索到蓝牙
plus.android.invoke(IntentFilter, "addAction", ACTION_FOUND);
//注册广播接收器
plus.android.invoke(this.Activity, "registerReceiver", this.BluetoothReciever, IntentFilter);
//蓝牙提示语
console.info("蓝牙广播接收器注册成功");
}
//获取已连接蓝牙列表
getBondedDevices() {
return new Promise((resolve, reject) => {
//获取已配对列表
const devices = this.Adapter.getBondedDevices();
const iterator = plus.android.invoke(devices, "iterator");
plus.android.importClass(iterator);
const list = [];
while (iterator.hasNext()) {
const device = iterator.next();
const name = plus.android.invoke(device, "getName");
const deviceId = plus.android.invoke(device, "getAddress");
list.push({ name, deviceId });
}
resolve(list);
});
}
//搜索蓝牙
discoverDevices(callback) {
plus.android.requestPermissions(
this.permissions,
({ granted }) => {
console.log("请求权限", granted);
this.onBluetoothDeviceFoundCallBack = callback;
//当前是否正在搜索
const isDiscovering = plus.android.invoke(this.Adapter, "isDiscovering");
//如果正在搜索,先停止再重新搜索
if (isDiscovering) {
this.stopDiscover();
}
//开始搜索蓝牙
plus.android.invoke(this.Adapter, "startDiscovery");
//三秒后停止搜索
setTimeout(() => {
this.stopDiscover();
}, 3000);
},
() => {}
);
}
//蓝牙状态变更
onBluetoothConnectedChange(callback) {
this.onBluetoothConnectedChangeCallback = callback;
}
//蓝牙状态变更
onBluetoothAdapterChange(callback) {
this.onBluetoothAdapterChangeCallback = callback;
}
//停止搜索
stopDiscover() {
if (!this.Adapter || !this.BluetoothReciever) return console.log({ message: "蓝牙适配器未开启!" });
plus.android.invoke(this.Adapter, "cancelDiscovery");
}
//连接蓝牙
connectDevice(id) {
return new Promise((resolve, reject) => {
plus.android.requestPermissions(
this.permissions,
({ granted }) => {
console.log("请求权限", granted);
try {
//停止扫描
const isDiscovering = plus.android.invoke(this.Adapter, "isDiscovering");
//判断是否正在扫描附近的蓝牙
if (isDiscovering) {
plus.android.invoke(this.Adapter, "cancelDiscovery");
}
//如果已连接先关闭
if (this.BluetoothSocket) {
plus.android.invoke(this.BluetoothSocket, "close");
this.BluetoothSocket = null;
}
//蓝牙设备
if (!id) return reject({ message: "蓝牙参数错误!" });
//获取远程蓝牙信号
const device = plus.android.invoke(this.Adapter, "getRemoteDevice", id);
//筛选可用的设备UUID
const UUID = plus.android.importClass("java.util.UUID");
const uuid = UUID.fromString(UUIDString);
this.BluetoothSocket = device.createRfcommSocketToServiceRecord(uuid);
plus.android.invoke(this.BluetoothSocket, "connect");
resolve();
} catch (error) {
console.error("连接蓝牙出现了错误", error);
this.BluetoothSocket = null;
reject({ code: -1, message: "连接超时或设备未开启!" });
}
},
(err) => reject(err)
);
});
}
//断开蓝牙
disconnectDevice(id) {
return new Promise((resolve, reject) => {
try {
//获取当前连接的蓝牙
const device = plus.android.invoke(this.Adapter, "getRemoteDevice", id);
const UUID = plus.android.importClass("java.util.UUID");
const uuid = UUID.fromString(UUIDString);
//获取蓝牙建立的连接
const socket = plus.android.invoke(device, "createInsecureRfcommSocketToServiceRecord", uuid);
//当前蓝牙是否已连接
const isConnected = plus.android.invoke(device, "isConnected");
//如果未连接直接阻断
if (!socket || !isConnected) return showToast({ position: "top", message: "当前蓝牙未连接!" });
//关闭输入流
const inputStream = plus.android.invoke(socket, "getInputStream");
plus.android.invoke(inputStream, "close");
//关闭输出流
const outputStream = plus.android.invoke(socket, "getOutputStream");
plus.android.invoke(outputStream, "close");
//断开建立的连接
plus.android.invoke(socket, "close");
resolve();
} catch (error) {
reject(error);
}
});
}
/**
* 发送数据
* @param {*} byte[] 二进制字节数组
* @returns
*/
sendDataToBluetooth(bytes) {
return new Promise(async (resolve, reject) => {
try {
if (!this.BluetoothSocket) return showToast({ position: "top", message: "连接已断开,请重新连接!" });
//生成输出流;
const outputStream = plus.android.invoke(this.BluetoothSocket, "getOutputStream");
//字节长度
const byteLength = bytes.byteLength;
const blob = new Int8Array(bytes);
//当前字节索引
let currentSize = 0;
//切片大小
const chunkSize = 2048;
//子线程实现方法
while (currentSize < byteLength) {
const chunk = blob.slice(currentSize, currentSize + chunkSize);
//发送数据
plus.android.invoke(outputStream, "write", [...chunk]);
//当前索引自增
currentSize += chunkSize;
}
resolve();
} catch (error) {
console.error("发送失败", error);
reject(error);
}
});
}
}
/**
* 创建蓝牙实例
* @returns
*/
export const createBluetooth = () => {
return new Bluetooth();
};
页面中使用
javascript
<template>
<div class="page">
<van-button @click="discover">搜索蓝牙</van-button>
<van-button @click="sendData">发送数据</van-button>
<ul class="container">
<li v-for="item in list" :key="item.deviceId" @click="connect(item.deviceId)">
{{ item.name }}
</li>
</ul>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { getBinary, getTextBinary, getQrCode } from "@/api/common";
import { createBluetooth } from "@/system/bluetooth";
const list = ref([]);
const bluetooth = createBluetooth();
onMounted(() => {
bluetooth.init();
});
//搜索蓝牙
const discover = () => {
bluetooth.discoverDevices((device) => {
const same = list.value.find((el) => el.deviceId === device.deviceId);
if (same) return;
list.value.push(device);
});
};
//连接蓝牙
const connect = (id) => {
bluetooth.connectDevice(id);
};
//发送数据
const sendData = async () => {
const res = await getBinary(); //请求打印数据
bluetooth.sendDataToBluetooth(res);
};
bluetooth.onBluetoothConnectedChange((res) => console.log("蓝牙连接状态变更了", res));
bluetooth.onBluetoothAdapterChange(({ state }) => console.info("蓝牙开关变更了", state));
</script>
<style scoped lang="scss">
.page {
padding-top: 50px;
display: flex;
flex-direction: column;
width: 100%;
height: 100vh;
overflow-y: scroll;
.van-button {
flex-shrink: 0;
}
.container {
width: 100%;
flex: 1;
overflow-y: scroll;
li {
width: 100%;
height: 40px;
text-align: center;
overflow: hidden;
}
}
}
</style>