diff --git a/components/tpx-bluetooth/nativeBlueTooth.js b/components/tpx-bluetooth/nativeBlueTooth.js
new file mode 100644
index 0000000..b15dd06
--- /dev/null
+++ b/components/tpx-bluetooth/nativeBlueTooth.js
@@ -0,0 +1,454 @@
+/**
+ * html 5+ 串口蓝牙操作
+ * 2021.04.23 uni-app版本
+ * @auth boolTrue
+ */
+
+/**
+ * 初始化参数
+ */
+//#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, Toast.LENGTH_SHORT).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) {
+ 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("蓝牙已经打开");
+ }
+ },
+ /**
+ * 关闭蓝牙
+ */
+ 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();
+ closeBtSocket();
+
+ if(btAdapter != null && btAdapter.isEnabled()) {
+ btAdapter.disable();
+ shortToast("蓝牙关闭成功");
+ } else {
+ shortToast("蓝牙已经关闭");
+ }
+ },
+ /**
+ * 获取已经配对的设备
+ * @return {Array} connetedDevices
+ */
+ 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;
+ },
+ /**
+ * 发现设备
+ */
+ 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) {
+ console.log("btFindReceiver onReceive")
+ 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(); //开启搜索
+ console.log("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);
+ 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', 'gbk');
+ try {
+ btOutStream.write(bytes);
+ } catch(e) {
+ return false;
+ }
+ return true;
+ },
+ sendByteData(byteData) {
+ if(!btOutStream) {
+ this.shortToast("创建输出流失败!");
+ return;
+ }
+ try {
+ btOutStream.write(byteData);
+ } catch(e) {
+ return false;
+ }
+ return true;
+ }
+}
+
+export default blueToothTool
\ No newline at end of file
diff --git a/components/tpx-bluetooth/tpx-bluetooth-native.vue b/components/tpx-bluetooth/tpx-bluetooth-native.vue
new file mode 100644
index 0000000..eb252bd
--- /dev/null
+++ b/components/tpx-bluetooth/tpx-bluetooth-native.vue
@@ -0,0 +1,359 @@
+
+
+
+
+
+
+
+ {{searchLoading?'搜索中...':'搜索周边设备'}}
+
+
+ 停止搜索
+
+
+
+
+ 连接信息
+
+
+
+
+ {{item.title}}
+
+
+ {{item.desc}}
+
+
+
+
+
+
+
+
+
+
+ 蓝牙设备列表
+
+
+
+ {{item.name }}
+
+
+ 信号强度: {{item.RSSI}}dBm ({{Math.max(100+item.RSSI,0)}}%)
+
+
+ deviceId:{{item.deviceId}}
+
+
+ Service数量: {{item.advertisServiceUUIDs.length || 0}}
+
+
+
+
+
+
+ 服务列表
+
+
+
+ uuid: {{item.uuid}}
+
+
+
+
+
+
+ 特征值列表
+
+
+
+ uuid: {{item.uuid}}
+
+
+
+
+ write: {{item.properties.write}}
+
+
+ notify: {{item.properties.notify}}
+
+
+ indicate: {{item.properties.indicate}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file