一丶封装小程序蓝牙连接
// wx_ble_api.js
/**
* @description
* 连接蓝牙低功耗设备。
* 若小程序在之前已有搜索过某个蓝牙设备,并成功建立连接,
* 可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需再次进行搜索操作。
* @param {
* deviceId 蓝牙设备 id
* timeout 超时时间,单位 ms,不填表示不会超时
* }
* @returns {Promise<any>}
*/
export function createBLEConnection({
deviceId,
timeout
}) {
return new Promise((resolve, reject) =>
wx.createBLEConnection({
deviceId,
timeout,
success: resolve,
fail: reject,
})
);
}
/**
* @description
* 断开与蓝牙低功耗设备的连接。
* @param {
* deviceId 蓝牙设备 id
* }
* @returns {Promise<any>}
*/
export function closeBLEConnection() {
return new Promise((resolve, reject) =>
wx.closeBLEConnection({
deviceId: wx.getStorageSync('wx_ble_deviceId'),
success: resolve,
fail: reject
})
);
}
/**
* @description
* 向蓝牙低功耗设备特征值中写入二进制数据。注意:必须设备的特征支持 write 才可以成功调用。
* @param {
* deviceId 蓝牙设备 id
* serviceId 蓝牙特征对应服务的 UUID
* characteristicId 蓝牙特征的 UUID
* value 蓝牙设备特征对应的二进制值
* }
* @returns {Promise<any>}
*/
export function writeBLECharacteristicValue({
deviceId,
serviceId,
characteristicId,
value,
}) {
return new Promise((resolve, reject) =>
wx.writeBLECharacteristicValue({
...arguments[0],
success: resolve,
fail: reject,
})
);
}
/**
* @description
* 读取蓝牙低功耗设备特征值的二进制数据。注意:必须设备的特征支持 read 才可以成功调用
* @param {
* deviceId 蓝牙设备 id
* serviceId 蓝牙特征对应服务的 UUID
* characteristicId 蓝牙特征的 UUID
* }
* @returns {Promise<any>}
*/
export function readBLECharacteristicValue({
deviceId,
serviceId,
characteristicId,
}) {
return new Promise((resolve, reject) =>
wx.readBLECharacteristicValue({
serviceId,
deviceId,
characteristicId,
success: resolve,
fail: reject,
})
);
}
/**
* @description
* 获取蓝牙低功耗设备所有服务 (service)
* @param {
* deviceId 蓝牙设备 id
* }
* @returns {Promise<any>}
*/
export function getBLEDeviceServices({
deviceId
}) {
return new Promise((resolve, reject) =>
wx.getBLEDeviceServices({
deviceId,
success: (res) => {
const {
services
} = res;
console.log("device services:", services);
resolve({
services
});
},
fail: reject,
})
);
}
/**
* @description
* 获取蓝牙低功耗设备某个服务中所有特征 (characteristic)
* @param {
* deviceId 蓝牙设备 id
* serviceId 蓝牙特征对应服务的 UUID
* }
* @returns {Promise<any>}
*/
export function getBLEDeviceCharacteristics({
deviceId,
serviceId
}) {
return new Promise((resolve, reject) =>
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
const {
characteristics
} = res;
console.log("device getBLEDeviceCharacteristics:", characteristics);
resolve({
characteristics,
serviceId
});
},
fail: reject,
})
);
}
/**
* @description
* 开始搜寻附近的蓝牙外围设备。
* @param {
* serviceId 蓝牙特征对应服务的 UUID
* }
* @returns {Promise<any>}
*/
export function startBlueToothDevicesDiscovery() {
return new Promise((resolve, reject) =>
wx.startBluetoothDevicesDiscovery({
...arguments[0],
success: resolve,
fail: reject,
})
);
}
/**
* @description
* 停止搜索附近的蓝牙外围设备。
* @param {}
* @returns {Promise<any>}
*/
export function stopBlueToothDevicesDiscovery() {
return new Promise((resolve, reject) =>
wx.stopBluetoothDevicesDiscovery({
success: resolve,
fail: reject
})
);
}
/**
* @description
* 初始化蓝牙模块。iOS 上开启主机/从机(外围设备)模式时需分别调用一次,并指定对应的 mode
* @param {}
* @returns {Promise<any>}
*/
export function openBlueToothAdapter() {
let isBugPhone = false;
try {
const {
model
} = wx.getSystemInfoSync();
isBugPhone =
model.indexOf("iPhone 6") !== -1 || model.indexOf("iPhone 7") !== -1;
} catch (e) {
console.error("wx.getSystemInfoSync() error", e);
}
return (openBlueToothAdapter = function() {
return new Promise((resolve, reject) => {
if (!isBugPhone) {
wx.openBluetoothAdapter({
success: resolve,
fail: reject
});
} else {
setTimeout(() => {
wx.openBluetoothAdapter({
success: resolve,
fail: reject
});
}, 150);
}
});
})();
}
/**
* @description
* 关闭蓝牙模块。调用该方法将断开所有已建立的连接并释放系统资源。建议在使用蓝牙流程后,与 wx.openBluetoothAdapter 成对调用。
* @param {}
* @returns {Promise<any>}
*/
export function closeBlueToothAdapter() {
return new Promise((resolve, reject) =>
wx.closeBluetoothAdapter({
success: resolve,
fail: reject
})
);
}
/**
* @description
* 根据主服务 UUID 获取已连接的蓝牙设备。
* @param {
* serviceId 蓝牙特征对应服务的 UUID
* }
* @returns {Promise<any>}
*/
export function getConnectedBlueToothDevices({
services
}) {
return new Promise((resolve, reject) =>
wx.getConnectedBluetoothDevices({
services,
success: resolve,
fail: reject,
})
);
}
/**
* @description
* 监听蓝牙低功耗设备的特征值变化事件。
* @param {
* function listener 蓝牙低功耗设备的特征值变化事件的监听函数
* }
* @returns
*/
export function onBLECharacteristicValueChange(cb) {
wx.onBLECharacteristicValueChange(cb);
}
/**
* @description
* 监听蓝牙适配器状态变化事件
* @param {
* function listener 蓝牙适配器状态变化事件的监听函数
* }
* @returns
*/
export function onBluetoothAdapterStateChange(cb) {
wx.onBluetoothAdapterStateChange(cb);
}
/**
* @description
* 监听蓝牙低功耗连接状态改变事件。包括开发者主动连接或断开连接,设备丢失,连接异常断开等等
* @param {
* function listener 蓝牙低功耗连接状态改变事件的监听函数
* }
* @returns
*/
export function onBLEConnectionStateChange(cb) {
wx.onBLEConnectionStateChange(cb);
}
/**
* @description
* 监听搜索到新设备的事件
* @param {
* function listener 搜索到新设备的事件的监听函数
* }
* @returns
*/
export function onBlueToothDeviceFound(cb) {
wx.onBluetoothDeviceFound(cb);
}
/**
* @description
* 启用蓝牙低功耗设备特征值变化时的 notify 功能,订阅特征。注意:必须设备的特征支持 notify 或者 indicate 才可以成功调用
* @param {
* deviceId 蓝牙设备 id
* serviceId 蓝牙特征对应服务的 UUID
* characteristicId 蓝牙特征的 UUID
* state 是否启用 notify
* }
* @returns {Promise<any>}
*/
export function notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId,
state,
}) {
return new Promise((resolve, reject) =>
wx.notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId,
state,
success: resolve,
fail: reject,
})
);
}
/**
* @description
* 获取在蓝牙模块生效期间所有搜索到的蓝牙设备。包括已经和本机处于连接状态的设备
* @param {}
* @returns {Promise<any>}
*/
export function getBlueToothDevices() {
return new Promise((resolve, reject) =>
wx.getBluetoothDevices({
success: resolve,
fail: reject
})
);
}
/**
* @description
* 获取本机蓝牙适配器状态
* @param {}
* @returns {Promise<any>}
*/
export function getBlueToothAdapterState() {
return new Promise((resolve, reject) =>
wx.getBluetoothAdapterState({
success: resolve,
fail: reject
})
);
}
/**
* 注册读写notify监听,该事件要发生在连接上设备之后
* @param deviceId 已连接的设备id
* @param targetServiceUUID 目标蓝牙服务UUID
* @param targetCharacteristics 目标蓝牙服务对应的特征值,包括writeCharacteristicId, notifyCharacteristicId, readCharacteristicId
* @returns {Promise<{serviceId, characteristicId: *, deviceId: *}>}
*/
export async function notifyBLE({
deviceId,
targetServiceUUID,
targetCharacteristics,
}) {
const {
characteristics,
serviceId
} = await findTargetServiceByUUID({
deviceId,
targetServiceUUID,
});
const {
writeCharacteristicId,
notifyCharacteristicId,
readCharacteristicId,
} = targetCharacteristics;
let characteristicId = "";
const notifyItem = characteristics.find(
({
uuid
}) => uuid === notifyCharacteristicId
);
if (notifyItem) {
await notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId: notifyCharacteristicId,
state: true,
});
console.warn("已注册notify事件 characteristicId:", notifyCharacteristicId);
}
const readItem = characteristics.find(
({
uuid
}) => uuid === readCharacteristicId
);
if (readItem) {
await readBLECharacteristicValue({
deviceId,
serviceId,
characteristicId: readCharacteristicId,
});
console.warn("本次读特征值是 characteristicId:", readCharacteristicId);
}
const writeItem = characteristics.find(
({
uuid
}) => uuid === writeCharacteristicId
);
if (writeItem) {
characteristicId = writeCharacteristicId;
console.warn("本次写特征值是 characteristicId:", writeCharacteristicId);
}
return {
serviceId,
characteristicId
};
}
/**
* @description
* 获取本机蓝牙适配器状态
* @param {
* deviceId 已连接的设备id
* targetServiceUUID 目标蓝牙服务UUID
* }
* @returns {Promise<any>}
*/
async function findTargetServiceByUUID({
deviceId,
targetServiceUUID
}) {
const {
services
} = await getBLEDeviceServices({
deviceId
});
for (const {
isPrimary,
uuid
} of services) {
if (isPrimary && uuid.toUpperCase() === targetServiceUUID) {
console.log('即将建立通信的服务uuid:', uuid);
return await getBLEDeviceCharacteristics({
deviceId,
serviceId: uuid
});
}
}
}
二丶连接蓝牙
// 连接的设备ID
const deviceId = "xx:xx:xx";
// 表端服务ID
const servicesId = "xxx-xxx-xx";
// notify数据的特征值
const notifyCharacteristicId = "xxx-xxx-xx";
// 写入数据的特征值
const writeCharacteristicId = "xxx-xxx-xx";
async function bleConnect() {
await openBlueToothAdapter();
// 扫描设备
findDevices();
}
async function findDevices() {
await startBlueToothDevicesDiscovery();
// 定时关闭什么时候停止扫描
setTimeout(async () => {
await stopBlueToothDevicesDiscovery();
const { devices } = await getBlueToothDevices();
// devices 就是扫描出来的所有设备
// ios已连接的设备没有展示,安卓可以展示已连接的。
// 设备列表展示后点击后连接
}, 3000);
}
async function connectDevice() {
await createBLEConnection({
deviceId: deviceId,
});
// 连接这个设备的服务,该服务ID由表端开发提供
connectServices();
}
async function connectServices() {
// 获取蓝牙设备所有服务(service)。
await getBLEDeviceServices({
deviceId: deviceId,
});
//获取对应服务的所有特征值
await getBLEDeviceCharacteristics({
deviceId: deviceId,
serviceId: servicesId,
});
// 启用低功耗蓝牙设备特征值变化时的 notify 功能,订阅特征值。
// 注意:必须设备的特征值支持 notify 或者 indicate 才可以成功调用。 另外,必须先启用 notifyBLECharacteristicValueChange 才能监听到设备 characteristicValueChange 事件
await notifyBLECharacteristicValueChange({
deviceId: deviceId,
serviceId: servicesId,
characteristicId: notifyCharacteristicId,
state: true,
});
// 这步做完就连接成功,可以监听对应特征值的数据了
watchNotify();
}
function watchNotify() {
onBLECharacteristicValueChange((res) => {
// 监听数据返回转成二进制
let hex = arrayBufferToHex(res.value).toUpperCase();
console.log(hex);
});
}
// ArrayBuffer转16进制字符串示例
function arrayBufferToHex(buffer) {
let hexArr = Array.prototype.map.call(new Uint8Array(buffer), function (bit) {
return ("00" + bit.toString(16)).slice(-2);
});
return hexArr.join("");
}
// 写入数据给表端writeCharacteristicId
function writeInstruct(data) {
// data = [0x01,0x02....]
let buffer = new ArrayBuffer(data.length);
let dataViewLast = new DataView(buffer);
for (let i = 0; i < data.length; i++) {
dataViewLast.setUint8(i, data[i]);
}
const value = dataViewLast.buffer;
writeBLECharacteristicValue({
// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
deviceId: deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId: servicesId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId: writeCharacteristicId,
// 这里的value是ArrayBuffer类型
value: value,
});
}