/** * @export * @param {string} name 微信api的名称 ,如 uniAsyncPromise("getSystemInfo",options) * @param {object} options 除了success 和 fail 的其他参数 * @returns */ export function uniAsyncPromise(name, options) { return new Promise((resolve, reject) => { uni[name]({ ...(options || {}), // ...options, success: (res) => { resolve(res); }, fail: (err) => { reject(err); } }); }); } //微信小程序向蓝牙打印机发送数据进行打印的坑: //小程序api向蓝牙打印机发送数据打印,发送的任何内容都应该要转成二进制数据,而且蓝牙打印的文本编码是GBK的,发送中文需转成GBK编码再转成二进制数据发送 //发送打印机指令也要转成二进制数据发送 //蓝牙打印机一次接收的二级制数据有限制,不同的系统不同的蓝牙设备限制可能不同,微信建议一次20个字节,需做递归分包发送 //发送完要打印的内容后,一定要发送一个打印的指令才能顺利打印 (有些指令就不需要) //一、初始化蓝牙、开始检索蓝牙设备 // { allowDuplicatesKey: true, interval: 500} export function openBlue() { return uniAsyncPromise('openBluetoothAdapter') } export function startBluetoothDevicesDiscovery(option) { console.log('开始蓝牙扫描'); uniAsyncPromise('startBluetoothDevicesDiscovery', option).then((res) => { console.log('正在搜寻蓝牙设备', res); }); } export function getConnectedBluetoothDevices(option) { console.log('开始获取已连接设备'); return uniAsyncPromise('getConnectedBluetoothDevices', option) } //二、 /** * * * @export * @param {function} getDevices uni.getBluetoothDevices的监听回调函数 */ export function onfindBlueDevices(getDevices) { //监听寻找到新设备的事件 uni.onBluetoothDeviceFound((devices)=>{ //获取在蓝牙模块生效期间所有已发现的蓝牙设备 uniAsyncPromise('getBluetoothDevices').then((res) => { getDevices && getDevices(res.devices); }); }); } /** * @export * @param {function} stopBlueDevicesDiscovery 关闭蓝牙扫描 */ export function stopBlueDevicesDiscovery() { //监听寻找到新设备的事件 console.log('停止蓝牙扫描'); return uniAsyncPromise('stopBluetoothDevicesDiscovery').then((res) => { console.log('停止搜寻蓝牙设备', res); }); } //三、连接蓝牙设备 /** * @export * @param {function} createBLEConnection * @param {number} deviceId 蓝牙设备id */ export function createBLEConnection(deviceId, sucess, fail) { //连接蓝牙设备 console.log('连接蓝牙设备', deviceId); uniAsyncPromise("createBLEConnection", { deviceId, timeout: 10000 }) .then(res => { //连接成功可选择停止搜索蓝牙 stopBlueDevicesDiscovery(); console.log('连接成功'); sucess && sucess({ res: res, }); }) .catch(res => { console.log('连接设备异常' + res); fail && fail({ res: res, }); }) /*.finally(res=>{ console.log('连接成功'); sucess && sucess({ res: res, }); });*/ } export function closeBLEConnection(deviceId) { console.log('断开蓝牙设备', deviceId); uniAsyncPromise("closeBLEConnection", { deviceId }) .then(res => { console.log('BLEDisconnect complete', res); }) .catch(res => { console.log('断开设备异常' + res); }) /*.finally(res=>{ console.log('BLEDisconnect complete', res); }); */ } //四、连接成功后, 获取蓝牙设备的service服务 // uniAsyncPromise("getBLEDeviceServices",{deviceId:""}).then(res=>{}) export function getBLEDeviceServices(deviceId, success, fail) { console.log('获取ServiceId', deviceId); //加延迟避免取不到service setTimeout(()=>{ uniAsyncPromise("getBLEDeviceServices", { deviceId:deviceId }) .then(res => { console.log('服务', res); success && success({ serviceId: res.services, }); }) .catch((res) => { //getBLEDeviceServices(deviceId, success, fail); console.log('获取ServiceId异常' + res); fail && fail({ res: res, }); }); },1000) } //五、获取的service服务可能有多个,递归获取特征值(最后要用的是能读,能写,能监听的那个值的uuid作为特征值id) /** * * * @export * @param {number} deviceId 蓝牙设备id * @param {array} services uniAsyncPromise("getBLEDeviceServices",{deviceId:""}).then(res=>{})获取的res.services * @param {function} success 成功取得有用特征值uuid的回调函数 */ export function getDeviceCharacteristics(deviceId, services, success, fail) { //services = services.slice(0); console.log('获取Characteristics', deviceId, services); if (services.length) { const serviceId = services.shift().uuid; console.log('ServceID ', serviceId); uniAsyncPromise('getBLEDeviceCharacteristics', { deviceId, serviceId, }) .then((res) => { console.log('getBLEDeviceCharacteristics', deviceId, serviceId, res); let finished = false; let write = false; let notify = false; let indicate = false; var readId; var writeId; //有斑马品牌的一款打印机中res.characteristics的所有uuid都是相同的,找所有的properties存在(notify || indicate) && write这种情况就说明这个uuid是可用的(不确保所有的打印机都能用这种方式取得uuid,在主要测试得凯盛诺打印机res.characteristic只有一个uuid,所以也能用这个方式) for (var i = 0; i < res.characteristics.length; i++) { if (!notify) { notify = res.characteristics[i].properties.notify; if (notify) readId = res.characteristics[i].uuid; } if (!indicate) { indicate = res.characteristics[i].properties.indicate; if (indicate) readId = res.characteristics[i].uuid; } if (!write) { write = res.characteristics[i].properties.write; writeId = res.characteristics[i].uuid; } if ((notify || indicate) && write) { /* 获取蓝牙特征值uuid */ success && success({ serviceId, writeId: writeId, readId: readId, }); finished = true; break; } } if (!finished) { getDeviceCharacteristics(deviceId, services, success, fail); } }) .catch((res) => { getDeviceCharacteristics(deviceId, services, success, fail); }); } else { fail && fail(); } } //六、启动notify 蓝牙监听功能 然后使用 uni.onBLECharacteristicValueChange用来监听蓝牙设备传递数据 /** * @export * @param {object} options * { deviceId,//蓝牙设备id serviceId,//服务id characteristicId,//可用特征值uuid } * @param {function} onChange 监听蓝牙设备传递数据回调函数 */ export function onGetBLECharacteristicValueChange(options, onChange = function() {}) { console.log('deviceId ', options.deviceId); console.log('serviceId ', options.serviceId); console.log('characteristicId ', options.characteristicId); uniAsyncPromise('notifyBLECharacteristicValueChange', { state: true, ...options, }).then((res) => { console.log('onBLECharacteristicValueChange '); uni.onBLECharacteristicValueChange(onChange); }); } //七、发送数据(递归分包发送) /** * @export * @param {object} options * { deviceId, serviceId, characteristicId, value [ArrayBuffer], lasterSuccess, } */ export function senBlData(deviceId, serviceId, characteristicId,uint8Array,lasterSuccess,lasterError) { console.log('************deviceId = [' + deviceId + '] serviceId = [' + serviceId + '] characteristics=[' +characteristicId+ "]") var uint8Buf = Array.from(uint8Array); function split_array(datas,size){ var result = {}; var j = 0 if(datas.length < size) { size = datas.length } for (var i = 0; i < datas.length; i += size) { result[j] = datas.slice(i, i + size) j++ } return result } var sendloop = split_array(uint8Buf, 20); console.log(sendloop.length) function realWriteData(sendloop, i) { var data = sendloop[i] if(typeof(data) == "undefined"){ lasterSuccess() return } //console.log("第【" + i + "】次写数据"+data) var buffer = new ArrayBuffer(data.length) var dataView = new DataView(buffer) for (var j = 0; j < data.length; j++) { dataView.setUint8(j, data[j]); } uni.writeBLECharacteristicValue({ deviceId, serviceId, characteristicId, value: buffer, success(res) { console.log('发送成功',i) setTimeout(()=>{ realWriteData(sendloop, i + 1); },100) }, fail(e) { console.log('发送数据失败',e) lasterError() } }) } var i = 0; realWriteData(sendloop, i); } // cpcl 发送数据 export function sendDataToDevice(options) { let byteLength = options.value.byteLength; //这里默认一次20个字节发送 const speed = plus.os.name != 'Android' ? 180 : 15; //20; console.log("send data 20"); console.log(options,byteLength,options.value); if (byteLength > 0) { uniAsyncPromise('writeBLECharacteristicValue', { ...options, value: options.value.slice(0, byteLength > speed ? speed : byteLength), }) .then((res) => { if (byteLength > speed) { setTimeout(()=>{ sendDataToDevice({ ...options, value: options.value.slice(speed, byteLength), }); },50) } else { options.lasterSuccess && options.lasterSuccess(); } }) .catch((res) => { console.log(res); options.lasterError && options.lasterError(); }); } } /** * toast显示捕获的蓝牙异常 */ export function catchToast(err) { const errMsg = { 10000: '未初始化蓝牙模块', 10001: '蓝牙未打开,请打开蓝牙开关', 10002: '没有找到指定设备', 10003: '连接失败', 10004: '没有找到指定服务', 10005: '没有找到指定特征值', 10006: '当前连接已断开', 10007: '当前特征值不支持此操作', 10008: '系统上报异常', 10009: '系统版本低于 4.3 不支持BLE', 10012: '连接超时,请重试' }; let coode = err.errCode ? err.errCode.toString() : ''; let msg = errMsg[coode]; plus.nativeUI.toast(msg || coode, { align: 'center', verticalAlign: 'center', duration:'long' }); }