UNPKG

mcblekit

Version:

该微信小程序开源代码库用于管理微信小程序中的蓝牙功能。支持初始化蓝牙适配器、扫描和连接蓝牙设备、获取设备服务和特征、监听特征值变化、读写特征值以及断开连接等操作。通过设置不同的监听器,可灵活处理蓝牙连接状态变化、设备发现、服务和特征发现等事件,适用于需要与蓝牙设备进行数据交互的微信小程序开发场景。This WeChat mini program open-source code library is used to manage the Bluetooth function in WeChat mini

633 lines (596 loc) 20.9 kB
/** * MCBleKit.js. * MCBleKit * * Created by Morgan Chen on 2025/4/8. * https://github.com/Json031 */ var util = require('./MCUtil.js'); var mcrssi = require('./MCrssi.js'); var mcTimeout = require('./MCTimeout.js'); let ScanDeviceTimeout = 35000;//扫描蓝牙超时时间,单位毫秒 let ConnectDeviceTimeout = 60000;//连接蓝牙超时时间,单位毫秒 var __instance = (function () { var instance; return function (newInstance) { if (newInstance) instance = newInstance; return instance; }; })(); function MCBleKit() { //MTU最大传输单元(Maximum Transmission Unit) this.bleMTU = 169; //蓝牙名称 this.blueName = ""; //服务id,eg: ['1910','180A'] this.serviceIds = []; // 连接中 this.connecting = false; // 连接状态 this.connected = false; // 服务列表 this.services = []; // 是否弹出蓝牙提示 this.blealert = false; // 发现的蓝牙外设列表 this.devices = []; // 当前连接的蓝牙外设 this.bleDevice = null; this.onBleCharacteristicValueReceivedListener = function () {}; this.errorOccurListener = function () {}; this.connectedStatusChangeListener = function () {}; this.connectingStatusChangeListener = function () {}; this.bluetoothDeviceFoundListener = function () {}; this.stopDiscoverListener = function () {}; this.startDiscoverListener = function () {}; // 发现服务通知 this.serviceListener = function () {}; // rssi通知 this.rssiListener = function () {}; // 发现服务特征通知 this.characteristicListener = function () {}; } MCBleKit.prototype.onErrorOccured = function (errorOccurListener) { if (typeof errorOccurListener!== 'function') { errorOccurListener = function () {}; } this.errorOccurListener = errorOccurListener; }; MCBleKit.prototype.onConnectedStatusChange = function (connectedStatusChangeListener) { if (typeof connectedStatusChangeListener!== 'function') { connectedStatusChangeListener = function () {}; } this.connectedStatusChangeListener = connectedStatusChangeListener; }; MCBleKit.prototype.onConnectingStatusChange = function (connectingStatusChangeListener) { if (typeof connectingStatusChangeListener!== 'function') { connectingStatusChangeListener = function () {}; } this.connectingStatusChangeListener = connectingStatusChangeListener; }; MCBleKit.prototype.bluetoothDeviceFound = function (bluetoothDeviceFoundListener) { if (typeof bluetoothDeviceFoundListener!== 'function') { bluetoothDeviceFoundListener = function () {}; } this.bluetoothDeviceFoundListener = bluetoothDeviceFoundListener; }; MCBleKit.prototype.stopDiscover = function (stopDiscoverListener) { if (typeof stopDiscoverListener!== 'function') { stopDiscoverListener = function () {}; } this.stopDiscoverListener = stopDiscoverListener; }; MCBleKit.prototype.startDiscover = function (startDiscoverListener) { if (typeof startDiscoverListener!== 'function') { startDiscoverListener = function () {}; } this.startDiscoverListener = startDiscoverListener; }; MCBleKit.prototype.onServicesFound = function (serviceListener) { if (typeof serviceListener!== 'function') { serviceListener = function () {}; } this.serviceListener = serviceListener; }; MCBleKit.prototype.onRssiChangesFound = function (rssiListener) { if (typeof rssiListener!== 'function') { rssiListener = function () {}; } this.rssiListener = rssiListener; }; MCBleKit.prototype.onCharacteristicFound = function (characteristicListener) { if (typeof characteristicListener!== 'function') { characteristicListener = function () {}; } this.characteristicListener = characteristicListener; }; Object.defineProperty(MCBleKit.prototype, 'connected', { set: function (value) { if (this._connected!== value) { this._connected = value; if (typeof this.connectedStatusChangeListener === 'function') { this.connectedStatusChangeListener(value); } } } }); Object.defineProperty(MCBleKit.prototype, 'connecting', { set: function (value) { if (this._connecting!== value) { this._connecting = value; if (typeof this.connectingStatusChangeListener === 'function') { this.connectingStatusChangeListener(value); } } } }); MCBleKit.getInstance = function (serviceIds, blueName) { if (serviceIds === undefined) { serviceIds = []; } if (__instance()) return __instance(); var mcblekit = new MCBleKit(); mcblekit.serviceIds = serviceIds; mcblekit.blueName = blueName; mcblekit.watchBleStatus(); mcblekit.openBluetoothAdapter(); mcblekit.onBLECharacteristicValueChange(); return __instance(mcblekit); }; MCBleKit.getSampleInstance = function (blueName) { return MCBleKit.getInstance([], blueName); }; // 初始化蓝牙 MCBleKit.prototype.openBluetoothAdapter = function () { var that = this; wx.openBluetoothAdapter({ success: function (res) { console.log('初始化蓝牙成功', res); that.startBluetoothDevicesDiscovery(); }, fail: function (res) { console.log('初始化蓝牙失败', res); that.errorOccurListener(res); if (util.containsIgnoreCase(res.errMsg, "already opened")) { that.getBluetoothAdapterState(); } else { /** * 初始化处理 */ that.bleAlert(); } } }); }; //获取蓝牙适配器状态 MCBleKit.prototype.getBluetoothAdapterState = function () { var that = this; wx.getBluetoothAdapterState({ success: function (res) { if (res.adapterState!== undefined) { /** * 开始扫描 */ if (!res.adapterState.discovering &&!that.connected) { console.log('available'); } if (!res.adapterState.available) { that.bleAlert(); } } else if (res.discovering!== undefined) { /** * 开始扫描 */ if (!res.discovering &&!that.connected) { console.log('available'); } if (!res.available) { that.bleAlert(); } } }, fail: function (res) { that.errorOccurListener(res); } }); this.startBluetoothDevicesDiscovery(); }; // 开始扫描 MCBleKit.prototype.startBluetoothDevicesDiscovery = function () { const that = this // 安卓系统需要定位权限 const deviceInfo = wx.getDeviceInfo() // 仅在安卓系统检查定位权限 if (deviceInfo.platform === 'android') { wx.getSetting({ success(res) { if (!res.authSetting['scope.userLocation']) { wx.authorize({ scope: 'scope.userLocation', success() { // 定位权限已获取,可以进行蓝牙扫描 mcTimeout.withTimeout(that.startScan(), ScanDeviceTimeout, '设备扫描超时') }, fail() { wx.showModal({ title: '提示', content: '请您打开定位或检查微信是否授权定位,用于连接设备', confirmColor: '#00b6b5', showCancel: false, success(res) { // 引导用户到设置页面 wx.openSetting(); } }) } }); } else { // 定位权限已获取,可以进行蓝牙扫描 mcTimeout.withTimeout(that.startScan(), ScanDeviceTimeout, '设备扫描超时') } } }); } else { // iOS系统不需要定位权限 mcTimeout.withTimeout(this.startScan(), ScanDeviceTimeout, '设备扫描超时') } }; MCBleKit.prototype.startScan = function () { return new Promise((resolve, reject) => { if (util.isEmptyStr(this.blueName)) { reject; return; } var that = this; wx.startBluetoothDevicesDiscovery({ success: function (res) { resolve; console.log('🔍 开始扫描设备', res) that.onBluetoothDeviceFound(); that.startDiscoverListener(); }, fail: function (res) { reject; console.log('❌ 扫描设备失败', res) if (res.errCode === 10004) { wx.showToast({ title: '当前设备不支持蓝牙', icon: 'none', }) } console.log('startBluetoothDevicesDiscovery fail' + res.errMsg); } }); }) }; //连接设备 // 获取所有已发现的设备 MCBleKit.prototype.onBluetoothDeviceFound = function () { var that = this; wx.onBluetoothDeviceFound(function (res) { var bluetoothDataList = that.devices; res.devices.forEach(function (item) { bluetoothDataList.push(item); if (util.isEqualIgnoreCase(item.localName, that.blueName)) { //连接 that.bleDevice = item; that.stopBluetoothDevicesDiscovery(); that.connectToBluetoothDevice(); } }); that.devices = bluetoothDataList; that.bluetoothDeviceFoundListener(that.devices); }); }; MCBleKit.prototype.stopBluetoothDevicesDiscovery = function () { var that = this; // 停止扫描 wx.stopBluetoothDevicesDiscovery({ success: function (res) { if (util.containsIgnoreCase(res.errMsg, 'ok')) { that.stopDiscoverListener(); } }, fail: function (res) { that.errorOccurListener(res); } }); }; MCBleKit.prototype.connectToBluetoothDevice = function () { mcTimeout.withTimeout(this.connectDeviceWithTimeout(), ConnectDeviceTimeout, '连接设备超时') }; MCBleKit.prototype.connectDeviceWithTimeout = function () { return new Promise((resolve, reject) => { if (util.isNullObject(this.bleDevice)) { reject; return; } if (this.connected) { reject; return; } if (this.connecting) { reject; return; } this.connecting = true; // 连接外设 var that = this; wx.createBLEConnection({ deviceId: this.bleDevice.deviceId, success: function (res) { resolve; console.log('连接设备成功', res); that.connected = true; wx.setBLEMTU({ deviceId: that.bleDevice.deviceId, mtu: that.bleMTU, success: function (res) { console.log('setBLEMTU succ'); }, fail: function (err) { that.errorOccurListener(err); console.log('setBLEMTU fail' + JSON.stringify(err)); } }); that.getBLEDeviceServices(); that.getRssi(); }, fail: function (res) { reject; console.log('❌ 连接设备失败', res) if (res.errno == 1509001 && res.errCode == 10003 && util.containsIgnoreCase(res.errMsg, 'status:133')) { wx.openBluetoothAdapter({ success: function (res) { console.log('初始化蓝牙成功', res); var coTimer = setInterval(function () { that.connectToBluetoothDevice(); clearInterval(coTimer); }, 1000); }, fail: function (res) { that.errorOccurListener(res); console.log('初始化蓝牙失败', res); } }); return; } if (res.errno == 1509007) { that.getBLEDeviceServices(); } console.log('连接失败', res); //超时情况不提示 if (!util.containsIgnoreCase(res.errMsg, 'connect time out')) { that.errorOccurListener(res); wx.showToast({ title: '连接失败:' + res.errno, icon: 'none' }); } } }); }); } /** * 获取信号强度 */ MCBleKit.prototype.getRssi = async function () { var that = this; try { const rssi = await mcrssi.getDeviceRSSI(this.bleDevice.deviceId) console.log('📶 设备信号强度:', rssi) that.rssiListener(rssi); } catch (err) { console.error('读取 RSSI 出错', err) } } /** * 获取Services */ MCBleKit.prototype.getBLEDeviceServices = function () { // 获取service var that = this; wx.getBLEDeviceServices({ deviceId: this.bleDevice.deviceId, success: function (res) { that.services = res.services; that.serviceListener(res.services); for (var i = 0; i < res.services.length; i++) { if (that.serviceIds.length <= 0) { //未指定serviceId,全部获取 that.getBLEDeviceCharacteristics(res.services[i].uuid); } else { //指定serviceId for (var j = 0; j < that.serviceIds.length; j++) { if (util.containsIgnoreCase(res.services[i].uuid, that.serviceIds[j])) { that.getBLEDeviceCharacteristics(res.services[i].uuid); break; } } } } }, fail: function (res) { if (res.errCode == 10004) { wx.showModal({ // title: '系统未获取到蓝牙服务,是否重试?', title: '系统未获取到蓝牙服务,请尝试关闭蓝牙并重启后再试', showCancel: false, content: '', complete: function (res) { if (res.cancel) { } if (res.confirm) { that.globalData.connecting = false; wx.closeBLEConnection({ deviceId: that.globalData.deviceId, success: function (res) {}, fail: function (res) {} }); } } }); } else { that.errorOccurListener(res); wx.showToast({ title: '系统获取蓝牙服务失败' + res.errCode, icon: 'none' }); } } }); }; // 获取characteristic MCBleKit.prototype.getBLEDeviceCharacteristics = function (serviceId) { var that = this; wx.getBLEDeviceCharacteristics({ deviceId: this.bleDevice.deviceId, serviceId: serviceId, success: function (res) { /** * 获取characteristics */ that.characteristicListener(serviceId, res); }, fail: function (res) { that.errorOccurListener(res); console.log("getBLEDeviceCharacteristics fail", res); } }); }; MCBleKit.prototype.notifyBLECharacteristicValueChange = function (serviceId, notifyCharacteristicsId) { // notify characteristic var that = this; wx.notifyBLECharacteristicValueChange({ state: true, deviceId: this.bleDevice.deviceId, serviceId: serviceId, characteristicId: notifyCharacteristicsId, type: 'notification', success: function (res) { if (res.errCode == 0) { console.log("notifyBLECharacteristic success"); } else { wx.showToast({ title: res.errMsg, icon: 'none' }); } }, fail: function (res) { that.errorOccurListener(res); } }); }; MCBleKit.prototype.readCharacteristicValue = function (serviceId, characteristicId) { wx.readBLECharacteristicValue({ deviceId: this.bleDevice.deviceId, serviceId: serviceId, characteristicId: characteristicId, success: function (res) { console.log('readBLECharacteristicValue:', res); } }); }; MCBleKit.prototype.onBleCharacteristicValueReceived = function (onBleCharacteristicValueReceivedListener) { if (typeof onBleCharacteristicValueReceivedListener!== 'function') { onBleCharacteristicValueReceivedListener = function () {}; } this.onBleCharacteristicValueReceivedListener = onBleCharacteristicValueReceivedListener; }; MCBleKit.prototype.onBLECharacteristicValueChange = function () { var that = this; wx.onBLECharacteristicValueChange(function (res) { that.onBleCharacteristicValueReceivedListener(res); }); }; // 断开连接 MCBleKit.prototype.closeBLEConnection = function () { var that = this; this.stopBluetoothDevicesDiscovery(); wx.closeBLEConnection({ deviceId: this.bleDevice.deviceId, success: function (res) { console.log('断开连接成功', res); }, fail: function (res) { that.errorOccurListener(res); console.log('断开连接失败', res); } }); this.connecting = false; this.connected = false; this.blueName = ""; this.services = []; this.blealert = false; this.devices = []; this.bleDevice = null; this.serviceIds = []; }; // 监听蓝牙状态 MCBleKit.prototype.watchBleStatus = function () { var that = this; wx.onBLEConnectionStateChange(function (result) { if (!result.connected) { that.connecting = false; that.connected = false; } else { that.connected = result.connected; } }); wx.onBluetoothAdapterStateChange(function (res) { if (that.connected &&!res.available) { that.connected = false; } if (!that.connected) { that.connecting = false; } }); }; //蓝牙不可用友情提示 MCBleKit.prototype.bleAlert = function () { var that = this; if (!this.blealert) { //设置已弹框提示开启蓝牙 this.blealert = true; wx.showModal({ title: '提示', content: '请您打开蓝牙或检查微信是否授权蓝牙,用于连接设备', confirmColor: '#00b6b5', showCancel: false, success: function (res) { //设置未弹框提示开启蓝牙 that.blealert = false; } }); var myTimer = setInterval(function () { //设置未弹框提示开启蓝牙 that.blealert = false; clearInterval(myTimer); }, 3000); } }; //数据交互, MCBleKit.prototype.writeValue = function (data, writeType, serviceId, characteristicsId) { // OTA发送 var that = this; wx.writeBLECharacteristicValue({ deviceId: this.bleDevice.deviceId, serviceId: serviceId, characteristicId: characteristicsId, value: data, writeType: writeType, success: function (res) { console.log('写入成功', res); }, fail: function (res) { console.log('发送失败' + res.errMsg); if (res.errCode == 10006) { that.getBluetoothAdapterState(); } else { that.closeBLEConnection(); } } }); }; module.exports = MCBleKit;