l***@126.com
l***@126.com
  • 发布:2020-06-15 19:24
  • 更新:2021-04-22 16:42
  • 阅读:1660

【报Bug】ios发送指令【uni.writeBLECharacteristicValue】卡住不动,安卓测试正常

分类:uni-app

产品分类: uniapp/App

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: win10

HBuilderX类型: 正式

HBuilderX版本号: 2.7.9

手机系统: iOS

手机系统版本号: iOS 13.4

手机厂商: 苹果

手机机型: iphone6plus、iphone8

页面类型: vue

打包方式: 离线

项目创建方式: HBuilderX

示例代码:

import {
isAndroid,
loadingTool
} from './common.js';

import {
deviceConfigList
} from './bluetooth_config.js';

let bluetoothTool = null;
if (isAndroid) {
//#ifdef APP-PLUS
bluetoothTool = new BluetoothToolClassic();
//#endif
}

//每个包最大数据内容
let MAX_PACKAGE_NUM = 20;
let _bluetoothOpenFlag = false;
let _readDataFlag = false;
let _readDataArray = [];

let _callback_success;
let _callback_fail;

String.prototype.replaceAll = function(s1,s2){
return this.replace(new RegExp(s1,"gm"),s2);
}

/**

  • 连接设备
  • @param {Object} deviceId
  • @param {Object} name
  • @param {Object} successFn
  • */
    function connectionToDevice(deviceId, name, successFn){
    loadingTool.setMsg("蓝牙连接中...");
    //2秒内未完成则显示连接中提示
    setTimeout(() => { loadingTool.start() }, 2000);

    //check设备是否为经典蓝牙
    let isClassic = _checkDeviceIsClassic(name);
    //获取设备配置信息
    let device = getDeviceConfig(name);

    //传统蓝牙
    if (isClassic) {
    _initBluetooth(() => {
    // 连接传统蓝牙设备(安卓)
    if (bluetoothTool.connDevice(deviceId, device.serviceId, successFn)) {
    //蓝牙连接成功,设置回调监听函数
    _connectionSuccessCallback(deviceId, device);
    } else {
    failFn()
    };
    });
    } else {
    _initBluetooth(() => {
    //连接ble蓝牙设备
    _connectionBle(deviceId, device, successFn);
    });
    }
    }

/**

  • 关闭设备连接
  • @param {Object} deviceId
  • @param {Object} name
  • @param {Object} sucessFn
    */
    function closeConnection(deviceId, name , sucessFn){
    //check设备是否为经典蓝牙
    let isClassic = _checkDeviceIsClassic(name);

    _initBluetooth(()=> {
    //传统蓝牙
    if (isClassic) {
    // 连接传统蓝牙设备(安卓)
    let result = bluetoothTool.disConnDevice();
    _bluetoothOpenFlag = false;
    _readDataFlag = false;
    result && sucessFn && sucessFn();
    } else {
    uni.closeBLEConnection({
    deviceId,
    success() {
    console.log("close closeBLEConnection success!" + deviceId)
    },
    complete() {
    uni.closeBluetoothAdapter({
    success(res) {
    console.log("close closeBluetoothAdapter!")
    sucessFn && sucessFn()
    }
    });
    _bluetoothOpenFlag = false;
    _readDataFlag = false;
    }
    });
    }
    });
    }

/**

  • 根据蓝牙设备名称获取设备配置信息
  • @param {Object} name
  • */
    function getDeviceConfig (name){
    if(! name){
    return null;
    }

    var lName = name.toLowerCase();
    for (var i = 0; i < deviceConfigList.length; i++) {
    if (lName.indexOf(deviceConfigList[i].deviceName) >= 0) {
    return deviceConfigList[i];
    }
    }
    console.log("Can't find this device! name:" + name);
    return null;
    }

/**

  • 搜索蓝牙设备
  • @param {Object} addDevicesProc
  • @param {Object} completeFn
  • @param {Object} timeout
    */
    function searchBluetoothDevice(addDevicesProc, completeFn, timeout) {
    //蓝牙初始化完毕后,开启搜索
    _initBluetooth(()=> {
    uni.startBluetoothDevicesDiscovery({
    success(res) {
    console.log(JSON.stringify(res))
    uni.onBluetoothDeviceFound(function(res) {
    let deviceArray = [];
    res.devices.forEach(function(item){
    let tmp = getDeviceConfig(item.name);
    if(tmp){
    tmp.deviceId = item.deviceId;
    deviceArray.push(tmp);
    }
    });

                if (deviceArray.length > 0) {  
                    addDevicesProc && addDevicesProc(deviceArray);  
                }  
            });  
        },  
        fail(res) {  
            console.log(JSON.stringify(res))  
            _doWithRet(res, completeFn)  
        }  
    });  
    
    //指定搜索时间后,自动停止搜索设备  
    setTimeout(() => {  
        uni.getBluetoothAdapterState({  
            complete(res) {  
                console.log(JSON.stringify(res))  
                //正在搜索设备的话,就停止搜索  
                if (res.discovering == true) {  
                    uni.stopBluetoothDevicesDiscovery({  
                        success(res) {  
                            completeFn && completeFn();  
                        }  
                    });  
                }  
            },  
            fail(ret) {  
                _doWithRet(ret, completeFn);  
            }  
        });  
    }, timeout);  

    });
    }

/**

  • 停止搜索蓝牙设备
    */
    function stopBluetoothDevicesDiscovery() {
    _initBluetooth(()=> {
    uni.stopBluetoothDevicesDiscovery({
    success: e => {
    console.log('停止搜索蓝牙设备:' + e.errMsg);
    },
    fail: e => {
    console.log('停止搜索蓝牙设备失败,错误码:' + e.errCode);
    }
    });
    });
    }

/**

  • 向指定设备发送指令数据
  • @param {Object} deviceId
  • @param {Object} name
  • @param {Object} sendData
  • @param {Object} sucessFn
  • @param {Object} failFn
  • */
    function sendBleCommand(deviceId, name, dataInfo, sucessFn, failFn) {
    console.log("dataInfo:" + dataInfo );

    //设置成功/失败回调函数
    _callback_success = sucessFn;
    _callback_fail = failFn;

    _initBluetooth(()=> {
    //获取设备配置信息
    let device = getDeviceConfig(name);
    //check设备是否为经典蓝牙
    let isClassic = _checkDeviceIsClassic(name);

    console.log("send data :" + deviceId + "   " + device.serviceId + "   " + device.wcharacteristicId);  
    
    if (isClassic) {  
        // 连接传统蓝牙设备(安卓)  
        if (bluetoothTool.connDevice(deviceId, '') && bluetoothTool.sendData(dataInfo)) {  
            //sucessFn && sucessFn();  
        } else {  
            failFn && failFn();  
        }  
    } else {  
    
        uni.getBLEDeviceServices({  
          // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接  
          deviceId: deviceId,  
          success(res) {  
            console.log('device services:', res.services)  
    
            // setTimeout(()=>{  
                //分包发送数据(20字节以内)  
                let packageArray = getSendDataArray(dataInfo);  
    
                _sendData(packageArray, 0, deviceId, device, isClassic);  
    
            // }, 1000);  
    
          }  
        })  
    }  

    });
    }

/**

  • 发送蓝牙数据信息
  • @param {Object} dataArray
  • @param {Object} index
  • @param {Object} deviceId
  • @param {Object} device
  • @param {Object} isClassic
  • */
    function _sendData(dataArray, index, deviceId, device, isClassic){
    if(index > dataArray.length - 1){
    //数据包发送完毕后,设置监听设备发过来的数据
    _readData(deviceId, device, isClassic);
    return;
    }

    if(isClassic){
    //经典蓝牙
    bluetoothTool.sendData(dataArray[index], ()=>{_sendData(dataArray, (index+1), deviceId, device, isClassic)});
    }else{
    //低功耗蓝牙
    // uni.getBLEDeviceCharacteristics({
    // deviceId: deviceId,
    // serviceId: device.serviceId,
    // success(res) {
    // console.log('device getBLEDeviceCharacteristics:', res.characteristics)

        uni.writeBLECharacteristicValue({  
            deviceId: deviceId,  
            serviceId: device.serviceId,  
            characteristicId: device.wcharacteristicId,  
            value: hexStringToArrayBuffer(dataArray[index]),  
            success(res) {  
                console.log(JSON.stringify(res));  
                _sendData(dataArray, (index + 1), deviceId, device, isClassic );  
            },  
            fail(res) {  
                console.log(JSON.stringify(res));  
            },  
            complete(res) {  
                console.log(JSON.stringify(res));  
            }  
        });  
    
    //  }  
    // });  

    }
    }

/**

  • 读取蓝牙设备数据(经典蓝牙&低功耗蓝牙)
  • @param {Object} deviceId
  • @param {Object} device
  • @param {Object} isClassic
    */
    function _readData(deviceId, device, isClassic){
    //只需要设置一次回调函数
    if(! _readDataFlag){
    if(isClassic){
    //经典蓝牙
    bluetoothTool.readData();
    }else{
    //低功耗蓝牙
    _readDataByBle(deviceId, device);
    }
    _readDataFlag = true;
    }
    }

/**

  • 读取低功耗蓝牙设备数据
  • @param {Object} deviceId
  • @param {Object} device
  • */
    function _readDataByBle(deviceId, device){
    uni.getBLEDeviceServices({
    deviceId: deviceId,
    success(res) {
    console.log('device services:', res.services)

    uni.getBLEDeviceCharacteristics({  
        deviceId: deviceId,  
        serviceId: device.serviceId,  
      success(res) {  
        console.log('device getBLEDeviceCharacteristics:', res.characteristics)  
    
        uni.notifyBLECharacteristicValueChange({  
            state: true, // 启用 notify 功能  
            deviceId: deviceId,  
            serviceId: device.serviceId,  
            characteristicId: device.characteristicId,  
            success(res) {  
                console.log('notifyBLECharacteristicValueChange success', JSON.stringify(res))  
    
                // 必须在这里的回调才能获取  
                uni.onBLECharacteristicValueChange(function (res) {  
                    let data = _ab2hex(res.value);  
    
                    if(data.startsWith("4e") && data.length > 2){  
                        _readDataArray.splice(0, _readDataArray.length);  
                    }  
                    _readDataArray.push(data);  
    
                    if(data.endsWith("4e")){  
                        _receiveDataCallBack();  
                    }  
    
                    console.log(data)  
                });  
            }  
        });  
      }  
    });  

    }
    });

}

/**

  • 接收到完整数据包后,执行回调函数
  • */
    function _receiveDataCallBack(){
    console.log("_receiveDataCallBack:" + JSON.stringify(_readDataArray) )

    let dataInfo = "";
    let index = 0;
    for(let i = 0 ; _readDataArray.length ; i++ ){
    dataInfo = dataInfo + _readDataArray[i];
    if(_readDataArray[i].endsWith("4e")){
    index = i + 1;
    break ;
    }
    }
    //删除解析后的数据包
    _readDataArray.splice(0, index);

    //字符转义
    dataInfo = _decodeBleData(dataInfo);

    //数据格式问题,直接返回不做处理
    if(dataInfo.length < 22){
    return ;
    }

    let dataCode = dataInfo.substring(18, (dataInfo.length - 4));
    let receiveDataInfo = hexToString(dataCode);

    _callback_success && _callback_success(receiveDataInfo);
    _callback_fail && _callback_fail();

}

/**

  • 初始化蓝牙模块
  • */
    function _initBluetooth(successFn){
    if(_bluetoothOpenFlag === true){
    successFn && successFn();
    return ;
    }
    //在页面加载时候初始化蓝牙适配器
    uni.openBluetoothAdapter({
    success: e => {
    console.log('初始化蓝牙成功:' + e.errMsg);
    _bluetoothOpenFlag = true;

        uni.getBluetoothAdapterState({  
            success(res) {  
                console.log(JSON.stringify(res));  
                successFn && successFn();  
            },  
            fail(res) {  
                //_doWithRet(res);  
            }  
        });  
    },  
    fail: e => {  
        console.log('初始化蓝牙失败,错误码:' + (e.errCode || e.errMsg));  
    }  

    });
    }

/**

  • 连接ble蓝牙
  • */
    function _connectionBle(deviceId, device, successFn) {
    console.log('蓝牙连接中:' + deviceId);
    //初始化蓝牙模块后执行设备连接
    _initBluetooth(()=> {
    //先看是否已连接
    uni.getConnectedBluetoothDevices({
    success(res) {
    console.log(JSON.stringify(res));
    if (res.devices) {
    for (var i = 0; i < res.devices.length; i++) {
    if (res.devices[i].deviceId == deviceId) {
    //蓝牙已经链接上了,不做任何处理
    loadingTool.close();
    return ;
    }
    }
    }

            //连接蓝牙设备  
            uni.createBLEConnection({  
                deviceId: deviceId,  
                timeout: 3000, //bug:timeout设置无效,且连不上也success  
                success(res) {  
                    console.log("conn success:" + JSON.stringify(res));  
                    successFn && successFn();  
                    //蓝牙连接成功,设置回调监听函数  
                    _connectionSuccessCallback(deviceId, device);  
                },  
                fail(res) {  
                    loadingTool.close();  
                    _doWithRet(res)  
                },  
                complete(ret) {  
                    loadingTool.close();  
                }  
            });  
        },  
        fail(res) {  
            _connectionFail();  
        }  
    });  

    });
    }

/**

  • 蓝牙设备连接成功后,设置相应的回调函数
  • @param {Object} deviceId
  • @param {Object} device
  • */
    function _connectionSuccessCallback(deviceId, device){
    loadingTool.close();

    //check设备是否为经典蓝牙
    let isClassic = _checkDeviceIsClassic(device.deviceName);

    if (isClassic) {
    //经典蓝牙设备独立处理
    bluetoothTool.setDisconnChangeCallback();
    }else{
    //蓝牙连接成功,设置回调监听函数
    _setBluetoothCallback(deviceId, device);
    }

    //设置监听设备发过来的数据
    //_readData(deviceId, device);

}

function _connectionFail(){
loadingTool.close()
}

function _setBluetoothCallback(deviceId, device, disConnFn){
//初始化蓝牙模块后执行设备callback设置
_initBluetooth(()=> {
console.log("-----_setBluetoothCallback--------")

    uni.onBluetoothAdapterStateChange(function(res) {  
        if (res.available == false) {  
            closeConnection();  
        }  
    });  
    uni.onBLEConnectionStateChange(function(res) {  
        if (res.connected == false && res.deviceId == deviceId) {  
            uni.showToast({  
                icon: 'none',  
                title: '连接已断开',  
                duration: 2000  
            });  
            closeConnection();  
        }  
    });  

    console.log("-----_setBluetoothCallback----deviceId:" + deviceId)  

});  

}

//检测设备是否为传统蓝牙(安卓手机& WOWOS、iNeck3)
function _checkDeviceIsClassic(name) {
if(!name){
return false;
}
if (isAndroid) {
const iNeck3 = name.toLowerCase().indexOf("iNeck3".toLowerCase()) != -1;
const WOWOS = name.toLowerCase().indexOf("WOWOS".toLowerCase()) != -1;
const iSeek = name.toLowerCase().indexOf("iSeek".toLowerCase()) != -1;
if (iNeck3 || WOWOS ) {
return true;
}
}
return false;
}

function _decodeBleData(data){
data = data.replaceAll("5e4d","4e");
data = data.replaceAll("5e5d","5e");
return data;
}

/**

  • 发送数据包差分处理
  • @param {Object} data
    */
    function getSendDataArray(data){
    let resultArray = [];

    let dataHex = strToHexCharCode(data);
    let dataLength = dataHex.length / 2;
    dataLength = dataLength.toString(16);
    for(let i = dataLength.length ; i < 4 ; i++ ){
    dataLength = "0" + dataLength;
    }

    dataHex = "01260201ffaa" + dataLength + dataHex;
    //校验和取反
    let checkCode = hexSumReverse(dataHex);
    dataHex = dataHex + checkCode;

    let dataHexTrans = "";
    for(let i = 0 ; i < dataHex.length / 2 ; i++){
    let tmp = dataHex.substring(i2, i2+2);
    if(tmp === "4e"){
    dataHexTrans += "5e4d";
    }else if(tmp === "5e"){
    dataHexTrans += "5e5d";
    }else{
    dataHexTrans += tmp;
    }
    }
    dataHexTrans = "4e" + dataHexTrans + "4e";

    let count = parseInt(dataHexTrans.length / 2 / MAX_PACKAGE_NUM);
    if(((dataHexTrans.length / 2) % MAX_PACKAGE_NUM) > 0){
    count ++;
    }

    for(let i = 0 ; i < count ; i++){
    let packInfo = "";
    if(i < count - 1){
    packInfo = dataHexTrans.substring(iMAX_PACKAGE_NUM2, iMAX_PACKAGE_NUM2 + MAX_PACKAGE_NUM 2);
    }else{
    packInfo = dataHexTrans.substring(i
    MAX_PACKAGE_NUM*2);
    }
    resultArray.push(packInfo);
    }

    return resultArray;

}

/**

  • 字符串转16进制字符( {"cmd":"GetWiFiList"} -> 7b22636d64223a22476574576946694c697374227d )
  • @param {Object} str
    */
    function strToHexCharCode(str) {
      if(str === "")
        return "";
      var hexCharCode = "";
      for(var i = 0; i < str.length; i++) {
    let tmp = (str.charCodeAt(i)).toString(16);
    if(tmp.length === 1){
    tmp = "0" + tmp;
    }
    hexCharCode += tmp;

    //hexCharCode.push((str.charCodeAt(i)).toString(16));
  }
  return hexCharCode;
}

/**

  • 16进制字符串校验和取反(1234 -> b9)
  • @param {Object} hexCharCodeStr
    */
    function hexSumReverse(hexCharCodeStr) {
      var trimedStr = hexCharCodeStr.trim();
      var rawStr = trimedStr.substr(0,2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;
      var len = rawStr.length;
      var curCharCode = 0;
      var resultStr = [];
      for(var i = 0; i < len;i = i + 2) {
    curCharCode += parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value
      }
    let checkCode = (0xFF ^ curCharCode).toString(16);
    if(checkCode.length === 1){
    checkCode = "0" + checkCode;
    }else if(checkCode.length > 2){
    checkCode = checkCode.substring(checkCode.length - 2);
    }

    //转义处理
    if(checkCode === "4e"){
    checkCode = "5e4d";
    }else if(checkCode === "5e"){
    checkCode = "5e5d";
    }

  return checkCode;
}

/**

  • 16进制转buffer 数组
  • @param {Object} str
    */
    function hexStringToArrayBuffer(str) {
    if (!str) {
    return new ArrayBuffer(0);
    }
    var buffer = new ArrayBuffer(str.length / 2);
    let dataView = new DataView(buffer)
    let ind = 0;
    for (var i = 0, len = str.length; i < len; i += 2) {
    let code = parseInt(str.substr(i, 2), 16)
    dataView.setUint8(ind, code)
    ind++
    }
    console.log(str + " " + buffer + " " + (str.length / 2) + " ind:" + ind)
    return buffer;
    }

/**

  • 处理蓝牙错误结果
  • */
    const _doWithRet = (ret, fn) => {
    var errCode = ret.errCode;;
    if (errCode == 10000) {
    uni.openBluetoothAdapter({
    success(ret) {
    console.log("初始化蓝牙适配器成功!")
    _bluetoothOpenFlag = true;
    fn && setTimeout(fn, 1000)
    },
    fail(ret) {
    uni.showToast({
    icon: 'none',
    title: '初始化蓝牙适配器失败',
    duration: 2000
    });
    }
    })
    } else if (errCode == 10001) {
    try {
    bluetoothTool.turnOnBluetooth()
    } catch (e) {
    uni.showToast({
    icon: 'none',
    title: '蓝牙已关闭,请打开蓝牙!',
    duration: 3000
    });
    }
    } else if (errCode == 10002) {
    uni.showToast({
    icon: 'none',
    title: '连接失败,请检查设备是否开启!',
    duration: 2000
    });
    fn && fn()
    } else if (errCode == 10003) {
    uni.showToast({
    icon: 'none',
    title: '连接失败',
    duration: 2000
    });
    fn && fn()
    } else if (errCode == 10004) {
    uni.showToast({
    icon: 'none',
    title: '没有找到指定服务',
    duration: 2000
    });
    fn && fn()
    } else if (errCode == -1) {
    fn()
    } else {
    uni.showToast({
    icon: 'none',
    title: '蓝牙操作异常[' + errCode + ']',
    duration: 2000
    });
    fn && fn()
    }
    }

/**

  • buffer数组转16进制
  • @param {Object} buffer
    */
    function _ab2hex(buffer) {
    const hexArr = Array.prototype.map.call(
    new Uint8Array(buffer),
    function(bit) {
    return ('00' + bit.toString(16)).slice(-2);
    }
    )
    return hexArr.join('');
    }

function _dec2utf8 (arr) {
if (typeof arr === 'string') {
return arr;
}

var unicodeString = '', _arr = arr;  
for (var i = 0; i < _arr.length; i++) {  
    var one = _arr[i].toString(2);  
    var v = one.match(/^1+?(?=0)/);  

    if (v && one.length === 8) {  
        var bytesLength = v[0].length;  
        var store = _arr[i].toString(2).slice(7 - bytesLength);  

        for (var st = 1; st < bytesLength; st++) {  
            store += _arr[st + i].toString(2).slice(2)  
        }  

        unicodeString += String.fromCharCode(parseInt(store, 2));  
        i += bytesLength - 1;  
    } else {  
        unicodeString += String.fromCharCode(_arr[i]);  
    }  
}  
return unicodeString  

};

/**

  • 16进制字符串转string
  • @param {Object} hexx
    */
    function hexToString(hexx) {
    var hex = hexx.toString();//force conversion

    var str_list = [];
    for (var i = 0; (i < hex.length && hex.substr(i, 2) !== '00'); i += 2)
    str_list.push(parseInt(hex.substr(i, 2), 16));

    return _dec2utf8(str_list);
    }

function BluetoothToolClassic() {
let BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");
let Intent = plus.android.importClass("android.content.Intent");
let IntentFilter = plus.android.importClass("android.content.IntentFilter");
let BluetoothDevice = plus.android.importClass("android.bluetooth.BluetoothDevice");
let UUID = plus.android.importClass("java.util.UUID");
let Toast = plus.android.importClass("android.widget.Toast");
//连接串口设备的 UUID
let DEFAULT_SERVICE_UUID = "00001101-0000-1000-8000-00805F9B34FB";

let invoke = plus.android.invoke;  
let btAdapter = BluetoothAdapter.getDefaultAdapter();  
let activity = plus.android.runtimeMainActivity();  

//连接设备信息  
let btSocket = null;  
let btInStream = null;  
let btOutStream = null;  
let btDevice = null;  
let setIntervalId = 0;  
let setTimeCount = 0;  
//用于接受设备传过来的数据  
let receiverData = [];  

let btFindReceiver = null; //蓝牙搜索广播接收器  
let btStatusReceiver = null; //蓝牙状态监听广播  

let state = {  
    bluetoothEnable: false, //蓝牙是否开启  
    bluetoothState: "", //当前蓝牙状态  
    discoveryDeviceState: false, //是否正在搜索蓝牙设备  
    readThreadState: false, //数据读取线程状态  
};  

let options = {  
    /**  
     * 监听蓝牙状态回调  
     * @param {String} state  
     */  
    listenBTStatusCallback: function(state) {},  
    /**  
     * 搜索到新的蓝牙设备回调  
     * @param {Device} newDevice  
     */  
    discoveryDeviceCallback: function(newDevice) {},  
    /**  
     * 蓝牙搜索完成回调  
     */  
    discoveryFinishedCallback: function() {},  
    /**  
     * 接收到数据回调  
     * @param {Array} dataByteArr  
     */  
    readDataCallback: function(data) {  
        console.log("readDataCallback:" + data)  
    },  
    /**  
     * 蓝牙连接中断回调  
     * @param {Exception} e  
     */  
    connExceptionCallback: function(e) {}  
}  

this.init = function(setOptions) {  
    Object.assign(options, setOptions);  
    state.bluetoothEnable = getBluetoothStatus();  
    listenBluetoothStatus();  
}  

function shortToast(msg) {  
    Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();  
}  

function ab2hex(buffer) {  
    const hexArr = Array.prototype.map.call(  
        new Uint8Array(buffer),  
        function(bit) {  
            return ('00' + bit.toString(16)).slice(-2);  
        }  
    )  
    return hexArr.join('');  
}  

function hexStringToArrayBuffer(str) {  
    if (!str) {  
        return new ArrayBuffer(0);  
    }  

    var buffer = new ArrayBuffer(str.length / 2);  
    let dataView = new DataView(buffer);  
    let ind = 0;  
    for (var i = 0, len = str.length; i < len; i += 2) {  
        let code = parseInt(str.substr(i, 2), 16);  
        console.log()  
        dataView.setUint8(ind, code);  
        ind++;  
    }  
    return buffer;  
}  

function hexStringToByteArray(str) {  
    if (!str) {  
        return new Array(0);  
    }  

    var buffer = new Array(str.length / 2);  
    let index = 0;  
    for (var i = 0, len = str.length; i < len; i += 2) {  
        let code = parseInt(str.substr(i, 2), 16);  
        buffer[index++] = numToByte(code);  
    }  

    return buffer;  
}  

function numToByte(num) {  
    var dataStr = '';  
    if (num > 127) {  
        dataStr = parseInt(0xFF ^ (num - 128)).toString(2);  
        return -(parseInt(dataStr.substring(1), 2) + 1);  
    } else {  
        return num;  
    }  
}  

/**  
 * 是否支持蓝牙  
 * @return {boolean}  
 */  
function isSupportBluetooth() {  
    if (btAdapter != null) {  
        return true;  
    }  
    return false;  
}  
/**  
 * 获取蓝牙的状态  
 * @return {boolean} 是否已开启  
 */  
function getBluetoothStatus() {  
    if (btAdapter != null) {  
        return btAdapter.isEnabled();  
    }  
    return false;  
}  

/**  
 * 打开蓝牙  
 * @param activity  
 * @param requestCode  
 */  
this.turnOnBluetooth = function() {  
    if (btAdapter == null) {  
        shortToast("没有蓝牙");  
        return;  
    }  
    if (!btAdapter.isEnabled()) {  
        if (activity == null) {  
            shortToast("未获取到activity");  
            return;  
        } else {  
            let intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
            let requestCode = 1;  
            activity.startActivityForResult(intent, requestCode);  
            return;  
        }  
    } else {  
        shortToast("蓝牙已经打开");  
    }  
}  

/**  
 * 关闭蓝牙  
 */  
function turnOffBluetooth() {  
    if (btAdapter != null && btAdapter.isEnabled()) {  
        btAdapter.disable();  
    }  
    if (btFindReceiver != null) {  
        try {  
            activity.unregisterReceiver(btFindReceiver);  
        } catch (e) {  

        }  
        btFindReceiver = null;  
    }  
    state.bluetoothEnable = false;  
    cancelDiscovery();  
    closeBtSocket();  

    if (btAdapter != null && btAdapter.isEnabled()) {  
        btAdapter.disable();  
        shortToast("蓝牙关闭成功");  
    } else {  
        shortToast("蓝牙已经关闭");  
    }  
}  

/**  
 * 获取已经配对的设备  
 * @return {Array} connetedDevices  
 */  
function getPairedDevices() {  
    let pairedDevices = [];  

    //蓝牙连接android原生对象,是一个set集合  
    let pairedDevicesAndroid = null;  
    if (btAdapter != null && btAdapter.isEnabled()) {  
        pairedDevicesAndroid = btAdapter.getBondedDevices();  
    } else {  
        shortToast("蓝牙未开启");  
    }  

    if (!pairedDevicesAndroid) {  
        return pairedDevices;  
    }  

    //遍历连接设备的set集合,转换为js数组  
    let it = invoke(pairedDevicesAndroid, "iterator");  
    while (invoke(it, "hasNext")) {  
        let device = invoke(it, "next");  
        pairedDevices.push({  
            "name": invoke(device, "getName"),  
            "address": invoke(device, "getAddress")  
        });  
    }  
    return pairedDevices;  
}  

/**  
 * 发现设备  
 */  
function discoveryNewDevice() {  
    if (btFindReceiver != null) {  
        try {  
            activity.unregisterReceiver(btFindReceiver);  
        } catch (e) {  
            console.error(e);  
        }  
        btFindReceiver = null;  
        cancelDiscovery();  
    }  
    let Build = plus.android.importClass("android.os.Build");  

    //6.0以后的如果需要利用本机查找周围的wifi和蓝牙设备, 申请权限  
    if (Build.VERSION.SDK_INT >= 6.0) {  

    }  

    btFindReceiver = plus.android.implements("io.dcloud.android.content.BroadcastReceiver", {  
        "onReceive": function(context, intent) {  
            plus.android.importClass(context);  
            plus.android.importClass(intent);  
            let action = intent.getAction();  

            if (BluetoothDevice.ACTION_FOUND == action) { // 找到设备  
                let device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
                let newDevice = {  
                    "name": plus.android.invoke(device, "getName"),  
                    "address": plus.android.invoke(device, "getAddress")  
                }  
                options.discoveryDeviceCallback && options.discoveryDeviceCallback(newDevice);  
            }  
            if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED == action) { // 搜索完成  
                cancelDiscovery();  
                options.discoveryFinishedCallback && options.discoveryFinishedCallback();  
            }  
        }  
    });  
    let filter = new IntentFilter();  
    filter.addAction(BluetoothDevice.ACTION_FOUND);  
    filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);  
    activity.registerReceiver(btFindReceiver, filter);  
    btAdapter.startDiscovery(); //开启搜索  
    state.discoveryDeviceState = true;  
}  

/**  
 * 蓝牙状态监听  
 * @param {Activity} activity  
 */  
function listenBluetoothStatus() {  
    if (btStatusReceiver != null) {  
        try {  
            activity.unregisterReceiver(btStatusReceiver);  
        } catch (e) {  
            console.error(e);  
        }  
        btStatusReceiver = null;  
    }  

    btStatusReceiver = plus.android.implements("io.dcloud.android.content.BroadcastReceiver", {  
        "onReceive": function(context, intent) {  
            plus.android.importClass(context);  
            plus.android.importClass(intent);  

            let action = intent.getAction();  
            switch (action) {  
                case BluetoothAdapter.ACTION_STATE_CHANGED:  
                    let blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);  
                    let stateStr = "";  
                    switch (blueState) {  
                        case BluetoothAdapter.STATE_TURNING_ON:  
                            stateStr = "STATE_TURNING_ON";  
                            break;  
                        case BluetoothAdapter.STATE_ON:  
                            state.bluetoothEnable = true;  
                            stateStr = "STATE_ON";  
                            break;  
                        case BluetoothAdapter.STATE_TURNING_OFF:  
                            stateStr = "STATE_TURNING_OFF";  
                            break;  
                        case BluetoothAdapter.STATE_OFF:  
                            stateStr = "STATE_OFF";  
                            state.bluetoothEnable = false;  
                            break;  
                    }  
                    state.bluetoothState = stateStr;  
                    options.listenBTStatusCallback && options.listenBTStatusCallback(stateStr);  
                    break;  
            }  
        }  
    });  
    let filter = new IntentFilter();  
    filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);  
    activity.registerReceiver(btStatusReceiver, filter);  
}  

this.setDisconnChangeCallback = function(disConnFn) {  
    var intervalId = setInterval(function() {  
        try {  
            if (!btSocket || !btSocket.isConnected()) {  
                clearInterval(intervalId);  
                disConnFn && disConnFn();  
            }  
        } catch (e) {  
            console.log("测试连接失败。" + e);  
        }  
    }, 1000);  
}  

/**  
 * 根据蓝牙地址,连接设备  
 * @param {Stirng} address  
 * @return {Boolean}  
 */  
this.connDevice = function(deviceId, serviceId, successFn) {  
    console.log("connDevice:" + deviceId + "        " + serviceId);  

    if (btOutStream) {  
        return true  
    }  

    try {  
        if (serviceId == '') {  
            serviceId = DEFAULT_SERVICE_UUID;  
        }  
        var serviceIdUuid = UUID.fromString(serviceId);  
        btDevice = btAdapter.getRemoteDevice(deviceId);  
        plus.android.importClass(btDevice);  
        btSocket = btDevice.createRfcommSocketToServiceRecord(serviceIdUuid);  
        console.log(serviceId)  
    } catch (e) {  
        console.log("=======" + e)  
        try {  
            btSocket = btDevice.createInsecureRfcommSocketToServiceRecord(serviceIdUuid);  
        } catch (e1) {  
            console.log("连接失败,获取Socket失败!" + e1);  
            return false;  
        }  
    }  

    plus.android.importClass(btSocket);  

    // var msg='设备蓝牙连接中...';  
    // uni.showLoading({title: msg});  
    try {  
        if (!btSocket.isConnected()) {  
            // shortToast('设备连接中');  
            btSocket.connect();  
            console.log("-------btSocket.connect()--------");  
            // msg='设备连接成功';  
            // } else {  
            //  msg='设备已连接'  
        }  
    } catch (e) {  
        console.log("连接失败。" + e);  
        // msg='设备连接失败'  
        closeBtSocket();  
        return false;  
    } finally {  
        // uni.hideLoading()  
        // shortToast(msg);  
    }  

    //连接上设备,初始化输入、输出流  
    if (btSocket.isConnected()) {  
        btInStream = invoke(btSocket, "getInputStream");  
        plus.android.importClass(btInStream);  
        btOutStream = invoke(btSocket, "getOutputStream");  
        plus.android.importClass(btOutStream);  

        state.readThreadState = true;  

        successFn && successFn();  

        readData();  
    }  

    console.log("连接成功。" + btSocket.isConnected());  
    return true;  
}  

/**  
 * 断开连接设备  
 * @param {Object} address  
 * @return {Boolean}  
 */  
this.disConnDevice = function() {  
    if (btSocket != null) {  
        closeBtSocket();  
    }  
    state.readThreadState = false;  
    // shortToast("连接已断开");  
    return true  
}  

/**  
 * 断开连接设备  
 * @param {Object} address  
 * @return {Boolean}  
 */  
function closeBtSocket() {  
    state.readThreadState = false;  
    btInStream = null;  
    btOutStream = null;  
    btDevice = null;  

    if (!btSocket) {  
        return;  
    }  
    try {  
        btSocket.close();  
    } catch (e) {  
        console.error(e);  
        btSocket = null;  
    }  
}  

/**  
 * 取消发现  
 */  
function cancelDiscovery() {  
    if (btAdapter.isDiscovering()) {  
        btAdapter.cancelDiscovery();  
    }  
    if (btFindReceiver != null) {  
        activity.unregisterReceiver(btFindReceiver);  
        btFindReceiver = null;  
    }  
    state.discoveryDeviceState = false;  
}  

/**  
 * 发送数据  
 * @param {String} dataStr  
 * @return {Boolean}  
 */  
this.sendData = function(data, successFn) {  
    if (!btOutStream) {  
        shortToast("连接已断开");  
        closeBtSocket();  
        return false;  
    }  

    try {  
        var bytesArray = hexStringToByteArray(data);  
        btOutStream.write(bytesArray);  
        btOutStream.flush();  

        //successFn && successFn();  

    } catch (e) {  
        shortToast('操作失败。' + e);  
        console.log(e);  
        return false;  
    }  
    console.log('发送指令:' + data);  
    return true;  
}  

function readData() {  
    if (!btSocket) {  
        shortToast("请先连接蓝牙设备!");  
        return false;  
    }  
    clearInterval(setIntervalId);  

    setIntervalId = setInterval(function() {  
        if (state.readThreadState) {  
            setTimeCount++;  
            //console.log("readData  : btSocket.isConnected() ==== " + btSocket.isConnected());  
            let startTime = new Date().getTime();  

            //心跳检测  
            // if(setTimeCount % 10 == 0) {  
            try {  
                btOutStream.write([0x00]);  
            } catch (e) {  
                closeBtSocket();  
                options.connExceptionCallback && options.connExceptionCallback(e);  
            }  
            // }  

            while (invoke(btInStream, "available") !== 0) {  
                let data = invoke(btInStream, "read");  
                receiverData.push(data);  
                let endTime = new Date().getTime();  
                //每次读取数据不超过20ms  
                if (endTime - startTime > 50) {  
                    break;  
                }  
            }  
            if (receiverData.length > 0) {  

                var dataArray = [];  
                for (var i = 1; i < receiverData.length; i++) {  
                    if (receiverData[i] == 78) {  
                        dataArray = receiverData.splice(0, i + 1);  
                        options.readDataCallback && options.readDataCallback(ab2hex(dataArray), dataArray);  
                    }  
                }  
            }  
        }  
    }, 2000);  
}  

}

export {
getSendDataArray,
getDeviceConfig,
closeConnection,
sendBleCommand,
connectionToDevice,
searchBluetoothDevice,
stopBluetoothDevicesDiscovery
}

操作步骤:

连接设备connectionToDevice成功后,
向设备发送指令sendBleCommand

ios卡在uni.writeBLECharacteristicValue不动,安卓正常

预期结果:

发送指令成功

实际结果:

ios卡在uni.writeBLECharacteristicValue不动,安卓正常

bug描述:

蓝牙连接成功后,通过函数sendBleCommand发送指令的时候,执行到uni.writeBLECharacteristicValue这个函数就卡住了,没有执行success、fail、complete回调函数,

ios、安卓连接设备都正常 【connectionToDevice】

发送指令的时候:
ios iPhone6p、iphone8测试都有问题,
安卓小米8测试是正常的。

2020-06-15 19:24 负责人:无 分享
已邀请:
CLP

CLP

你就不能提供个demo来吗,这么大一串,没你的设备是不是复现不了问题?

l***@126.com

l***@126.com (作者)

嗯,是啊。。没有设备。你们也测试不了。
其实就是连接成功后,发送指令【uni.writeBLECharacteristicValue】卡住不动。
安卓正常,ios不行。

8***@qq.com

8***@qq.com

我用iphone8调试,也遇到同样的问题,后面我用官方文档(如下的代码)向BLE发送一个16进制数据,也没有回调.
请求官方回复,谢谢!!

// 向蓝牙设备发送一个0x00的16进制数据
const buffer = new ArrayBuffer(1)
const dataView = new DataView(buffer)
dataView.setUint8(0, 0)
uni.writeBLECharacteristicValue({
// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId,
// 这里的value是ArrayBuffer类型
value: buffer,
success(res) {
console.log('writeBLECharacteristicValue success', res.errMsg)
}
})

3***@qq.com

3***@qq.com

请问解决没有现在我也是卡在writeBLECharacteristicValue就没响应了不报错也不成功

该问题目前已经被锁定, 无法添加新回复