/** * 初始化参数 */ //#ifdef APP-PLUS 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 MY_UUID = UUID.fromString("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 setIntervalId = 0; let btFindReceiver = null; //蓝牙搜索广播接收器 let btStatusReceiver = null; //蓝牙状态监听广播 //#endif /** * 构造对象 */ var blueToothTool = { state : { bluetoothEnable: false, //蓝牙是否开启 bluetoothState: "", //当前蓝牙状态 discoveryDeviceState: false, //是否正在搜索蓝牙设备 readThreadState: false, //数据读取线程状态 }, options : { /** * 监听蓝牙状态回调 * @param {String} state */ listenBTStatusCallback: function(state) {}, /** * 搜索到新的蓝牙设备回调 * @param {Device} newDevice */ discoveryDeviceCallback: function(newDevice) {}, /** * 蓝牙搜索完成回调 */ discoveryFinishedCallback: function() {}, /** * 接收到数据回调 * @param {Array} dataByteArr */ readDataCallback: function(dataByteArr) {}, /** * 蓝牙连接中断回调 * @param {Exception} e */ connExceptionCallback: function(e) {} }, init(setOptions) { Object.assign(this.options, setOptions); this.state.bluetoothEnable = this.getBluetoothStatus(); this.listenBluetoothStatus(); }, shortToast(msg) { Toast.makeText(activity, msg, 1000).show(); }, /** * 是否支持蓝牙 * @return {boolean} */ isSupportBluetooth() { if(btAdapter != null) { return true; } return false; }, /** * 获取蓝牙的状态 * @return {boolean} 是否已开启 */ getBluetoothStatus() { if(btAdapter != null) { return btAdapter.isEnabled(); } return false; }, /** * 打开蓝牙 * @param activity * @param requestCode */ turnOnBluetooth() { if(btAdapter == null) { this.shortToast("没有蓝牙"); return; } if(!btAdapter.isEnabled()) { if(activity == null) { this.shortToast("未获取到activity"); return; } else { let intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); let requestCode = 1; activity.startActivityForResult(intent, requestCode); return; } } else { this.shortToast("蓝牙已经打开"); } }, /** * 关闭蓝牙 */ turnOffBluetooth() { if(btAdapter != null && btAdapter.isEnabled()) { btAdapter.disable(); } if(btFindReceiver != null) { try { activity.unregisterReceiver(btFindReceiver); } catch(e) { } btFindReceiver = null; } this.state.bluetoothEnable = false; this.cancelDiscovery(); this.closeBtSocket(); if(btAdapter != null && btAdapter.isEnabled()) { btAdapter.disable(); this.shortToast("蓝牙关闭成功"); } else { this.shortToast("蓝牙已经关闭"); } }, /** * 获取已经配对的设备 * @return {Array} connetedDevices */ getPairedDevices() { let pairedDevices = []; //蓝牙连接android原生对象,是一个set集合 let pairedDevicesAndroid = null; if(btAdapter != null && btAdapter.isEnabled()) { pairedDevicesAndroid = btAdapter.getBondedDevices(); } else { this.shortToast("蓝牙未开启"); } if(!pairedDevicesAndroid) { return pairedDevices; } //遍历连接设备的set集合,转换为js数组 let it = invoke(pairedDevicesAndroid, "iterator"); while(invoke(it, "hasNext")) { let device = invoke(it, "next"); let deviceType = invoke(device, "getType"); let deviceId = invoke(device, "getAddress"); let deviceName = invoke(device, "getName"); let typeString = ""; //console.log("BluetoothDevice.DEVICE_TYPE_CLASSIC", deviceType) if(deviceType == 1) { typeString = "classic"; } else if(deviceType == 2) { typeString = "ble"; } else if(deviceType == 3) { typeString = "dual"; } else { typeString = "unknown"; } if(deviceName != null) { pairedDevices.push({ "name": deviceName, "deviceId": deviceId, "type": typeString }); } } return pairedDevices; }, /** * 发现设备 */ discoveryNewDevice() { if(btFindReceiver != null) { try { activity.unregisterReceiver(btFindReceiver); } catch(e) { console.error(e); } btFindReceiver = null; this.cancelDiscovery(); } let Build = plus.android.importClass("android.os.Build"); //6.0以后的如果需要利用本机查找周围的wifi和蓝牙设备, 申请权限 if(Build.VERSION.SDK_INT >= 6.0){ } let options = this.options 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 deviceType = invoke(device, "getType"); let deviceId = invoke(device, "getAddress"); let deviceName = invoke(device, "getName"); let typeString = ""; //console.log("BluetoothDevice.DEVICE_TYPE_CLASSIC", deviceType) if(deviceType == 1) { typeString = "classic"; } else if(deviceType == 2) { typeString = "ble"; } else if(deviceType == 3) { typeString = "dual"; } else { typeString = "unknown"; } if(deviceName != null) { let newDevice = { "name": deviceName, "deviceId": deviceId, "type": typeString }; 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(); //开启搜索 this.state.discoveryDeviceState = true; }, /** * 蓝牙状态监听 * @param {Activity} activity */ 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": (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: this.state.bluetoothEnable = true; stateStr = "STATE_ON"; break; case BluetoothAdapter.STATE_TURNING_OFF: stateStr = "STATE_TURNING_OFF"; break; case BluetoothAdapter.STATE_OFF: stateStr = "STATE_OFF"; this.state.bluetoothEnable = false; break; } this.state.bluetoothState = stateStr; this.options.listenBTStatusCallback && this.options.listenBTStatusCallback(stateStr); break; } } }); let filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); activity.registerReceiver(btStatusReceiver, filter); // 首次连接 状态回调 if(this.state.bluetoothEnable) { this.options.listenBTStatusCallback && this.options.listenBTStatusCallback('STATE_ON'); } }, /** * 根据蓝牙地址,连接设备 * @param {Stirng} address * @return {Boolean} */ connDevice(address, callback) { let InputStream = plus.android.importClass("java.io.InputStream"); let OutputStream = plus.android.importClass("java.io.OutputStream"); let BluetoothSocket = plus.android.importClass("android.bluetooth.BluetoothSocket"); this.cancelDiscovery(); if(btSocket != null) { this.closeBtSocket(); } this.state.readThreadState = false; try { let device = invoke(btAdapter, "getRemoteDevice", address); btSocket = invoke(device, "createRfcommSocketToServiceRecord", MY_UUID); } catch(e) { console.error(e); this.shortToast("连接失败,获取Socket失败!"); callback(false) return false; } try { invoke(btSocket, "connect"); this.readData(); //读数据 this.shortToast("连接经典蓝牙成功"); callback(true) } catch(e) { console.error(e); this.shortToast("连接经典蓝牙失败"); callback(false) try { btSocket.close(); btSocket = null; } catch(e1) { console.error(e1); } return false; } return true; }, /** * 断开连接设备 * @param {Object} address * @return {Boolean} */ disConnDevice() { if(btSocket != null) { this.closeBtSocket(); } this.state.readThreadState = false; this.shortToast("断开连接成功"); }, /** * 断开连接设备 * @param {Object} address * @return {Boolean} */ closeBtSocket() { this.state.readThreadState = false; if(!btSocket) { return; } try { btSocket.close(); } catch(e) { console.error(e); btSocket = null; } }, /** * 取消发现 */ cancelDiscovery() { if(btAdapter.isDiscovering()) { btAdapter.cancelDiscovery(); } if(btFindReceiver != null) { activity.unregisterReceiver(btFindReceiver); btFindReceiver = null; } this.state.discoveryDeviceState = false; }, /** * 读取数据 * @param {Object} activity * @param {Function} callback * @return {Boolean} */ readData() { if(!btSocket) { this.shortToast("请先连接蓝牙设备!"); return false; } try { btInStream = invoke(btSocket, "getInputStream"); btOutStream = invoke(btSocket, "getOutputStream"); } catch(e) { console.error(e); this.shortToast("创建输入输出流失败!"); this.closeBtSocket(); return false; } this.read(); this.state.readThreadState = true; return true; }, /** * 模拟java多线程读取数据 */ read() { let setTimeCount = 0; clearInterval(setIntervalId); setIntervalId = setInterval(()=> { setTimeCount++; if(this.state.readThreadState) { let t = new Date().getTime(); //心跳检测 if(setTimeCount % 20 == 0) { try { btOutStream.write([0b00]); } catch(e) { this.state.readThreadState = false; this.options.connExceptionCallback && this.options.connExceptionCallback(e); } } let dataArr = []; while(invoke(btInStream, "available") !== 0) { let data = invoke(btInStream, "read"); dataArr.push(data); let ct = new Date().getTime(); if(ct - t > 20) { break; } } if(dataArr.length > 0) { this.options.readDataCallback && this.options.readDataCallback(dataArr); } } }, 40); }, /** * 发送数据 * @param {String} dataStr * @return {Boolean} */ sendData(dataStr) { if(!btOutStream) { this.shortToast("创建输出流失败!"); return; } let bytes = invoke(dataStr, 'getBytes', 'gb18030'); //console.log(">>> bluetoothTool sendData -> bytes", dataStr, bytes) try { //btOutStream.write(bytes); this.sendByteData(bytes) } catch(e) { return false; } return true; }, sendByteData(byteData) { console.log("byteData", byteData) if(!btOutStream) { this.shortToast("创建输出流失败!"); return; } try { //console.log(">>> bluetoothTool sendByteData", byteData) //btOutStream.write(byteData); // 分块大小:1024-4096 字节 const CHUNK_SIZE = 4096; for(let i = 0; i < byteData.length; i += CHUNK_SIZE) { const chunk = byteData.slice(i, i + CHUNK_SIZE); btOutStream.write(chunk); // 可选:添加小延迟避免缓冲区溢出 //if(i + CHUNK_SIZE < byteData.length) { //Thread.sleep(10); // 如果需要 //} } } catch(e) { return false; } return true; } } export default blueToothTool