BluetoothTool.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. //#ifdef APP-PLUS
  2. let BluetoothAdapter = plus.android.importClass(
  3. "android.bluetooth.BluetoothAdapter"
  4. );
  5. let Intent = plus.android.importClass("android.content.Intent");
  6. let IntentFilter = plus.android.importClass("android.content.IntentFilter");
  7. let BluetoothDevice = plus.android.importClass(
  8. "android.bluetooth.BluetoothDevice"
  9. );
  10. let UUID = plus.android.importClass("java.util.UUID");
  11. let Toast = plus.android.importClass("android.widget.Toast");
  12. //连接串口设备的 UUID
  13. let MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
  14. let invoke = plus.android.invoke;
  15. let btAdapter = BluetoothAdapter.getDefaultAdapter();
  16. let activity = plus.android.runtimeMainActivity();
  17. let btSocket = null;
  18. let btInStream = null;
  19. let btOutStream = null;
  20. let setIntervalId = 0;
  21. let btFindReceiver = null; //蓝牙搜索广播接收器
  22. let btStatusReceiver = null; //蓝牙状态监听广播
  23. //#endif
  24. /**
  25. * 构造对象
  26. */
  27. var blueToothTool = {
  28. state: {
  29. bluetoothEnable: false, //蓝牙是否开启
  30. bluetoothState: "", //当前蓝牙状态
  31. discoveryDeviceState: false, //是否正在搜索蓝牙设备
  32. readThreadState: false, //数据读取线程状态
  33. },
  34. options: {
  35. /**
  36. * 监听蓝牙状态回调
  37. * @param {String} state
  38. */
  39. listenBTStatusCallback: function (state) {},
  40. /**
  41. * 搜索到新的蓝牙设备回调
  42. * @param {Device} newDevice
  43. */
  44. discoveryDeviceCallback: function (newDevice) {},
  45. /**
  46. * 蓝牙搜索完成回调
  47. */
  48. discoveryFinishedCallback: function () {},
  49. /**
  50. * 接收到数据回调
  51. * @param {Array} dataByteArr
  52. */
  53. readDataCallback: function (dataByteArr) {},
  54. /**
  55. * 蓝牙连接中断回调
  56. * @param {Exception} e
  57. */
  58. connExceptionCallback: function (e) {},
  59. },
  60. init(setOptions) {
  61. Object.assign(this.options, setOptions);
  62. this.state.bluetoothEnable = this.getBluetoothStatus();
  63. this.listenBluetoothStatus();
  64. },
  65. shortToast(msg) {
  66. Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();
  67. },
  68. /**
  69. * 是否支持蓝牙
  70. * @return {boolean}
  71. */
  72. isSupportBluetooth() {
  73. if (btAdapter != null) {
  74. return true;
  75. }
  76. return false;
  77. },
  78. /**
  79. * 获取蓝牙的状态
  80. * @return {boolean} 是否已开启
  81. */
  82. getBluetoothStatus() {
  83. if (btAdapter != null) {
  84. return btAdapter.isEnabled();
  85. }
  86. return false;
  87. },
  88. /**
  89. * 打开蓝牙
  90. * @param activity
  91. * @param requestCode
  92. */
  93. turnOnBluetooth() {
  94. if (btAdapter == null) {
  95. shortToast("没有蓝牙");
  96. return;
  97. }
  98. if (!btAdapter.isEnabled()) {
  99. if (activity == null) {
  100. shortToast("未获取到activity");
  101. return;
  102. } else {
  103. let intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  104. let requestCode = 1;
  105. activity.startActivityForResult(intent, requestCode);
  106. return;
  107. }
  108. } else {
  109. shortToast("蓝牙已经打开");
  110. }
  111. },
  112. /**
  113. * 关闭蓝牙
  114. */
  115. turnOffBluetooth() {
  116. if (btAdapter != null && btAdapter.isEnabled()) {
  117. btAdapter.disable();
  118. }
  119. if (btFindReceiver != null) {
  120. try {
  121. activity.unregisterReceiver(btFindReceiver);
  122. } catch (e) {}
  123. btFindReceiver = null;
  124. }
  125. this.state.bluetoothEnable = false;
  126. this.cancelDiscovery();
  127. closeBtSocket();
  128. if (btAdapter != null && btAdapter.isEnabled()) {
  129. btAdapter.disable();
  130. shortToast("蓝牙关闭成功");
  131. } else {
  132. shortToast("蓝牙已经关闭");
  133. }
  134. },
  135. /**
  136. * 获取已经配对的设备
  137. * @return {Array} connetedDevices
  138. */
  139. getPairedDevices() {
  140. let pairedDevices = [];
  141. //蓝牙连接android原生对象,是一个set集合
  142. let pairedDevicesAndroid = null;
  143. if (btAdapter != null && btAdapter.isEnabled()) {
  144. pairedDevicesAndroid = btAdapter.getBondedDevices();
  145. } else {
  146. shortToast("蓝牙未开启");
  147. }
  148. if (!pairedDevicesAndroid) {
  149. return pairedDevices;
  150. }
  151. //遍历连接设备的set集合,转换为js数组
  152. let it = invoke(pairedDevicesAndroid, "iterator");
  153. while (invoke(it, "hasNext")) {
  154. let device = invoke(it, "next");
  155. pairedDevices.push({
  156. name: invoke(device, "getName"),
  157. address: invoke(device, "getAddress"),
  158. });
  159. }
  160. return pairedDevices;
  161. },
  162. /**
  163. * 发现设备
  164. */
  165. discoveryNewDevice() {
  166. if (btFindReceiver != null) {
  167. try {
  168. activity.unregisterReceiver(btFindReceiver);
  169. } catch (e) {
  170. console.error(e);
  171. }
  172. btFindReceiver = null;
  173. this.cancelDiscovery();
  174. }
  175. let Build = plus.android.importClass("android.os.Build");
  176. //6.0以后的如果需要利用本机查找周围的wifi和蓝牙设备, 申请权限
  177. if (Build.VERSION.SDK_INT >= 6.0) {
  178. }
  179. let options = this.options;
  180. btFindReceiver = plus.android.implements(
  181. "io.dcloud.android.content.BroadcastReceiver",
  182. {
  183. onReceive: function (context, intent) {
  184. plus.android.importClass(context);
  185. plus.android.importClass(intent);
  186. let action = intent.getAction();
  187. if (BluetoothDevice.ACTION_FOUND == action) {
  188. // 找到设备
  189. let device = intent.getParcelableExtra(
  190. BluetoothDevice.EXTRA_DEVICE
  191. );
  192. let newDevice = {
  193. name: plus.android.invoke(device, "getName"),
  194. address: plus.android.invoke(device, "getAddress"),
  195. };
  196. options.discoveryDeviceCallback &&
  197. options.discoveryDeviceCallback(newDevice);
  198. }
  199. if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED == action) {
  200. // 搜索完成
  201. cancelDiscovery();
  202. options.discoveryFinishedCallback &&
  203. options.discoveryFinishedCallback();
  204. }
  205. },
  206. }
  207. );
  208. let filter = new IntentFilter();
  209. filter.addAction(BluetoothDevice.ACTION_FOUND);
  210. filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
  211. activity.registerReceiver(btFindReceiver, filter);
  212. btAdapter.startDiscovery(); //开启搜索
  213. this.state.discoveryDeviceState = true;
  214. },
  215. /**
  216. * 蓝牙状态监听
  217. * @param {Activity} activity
  218. */
  219. listenBluetoothStatus() {
  220. if (btStatusReceiver != null) {
  221. try {
  222. activity.unregisterReceiver(btStatusReceiver);
  223. } catch (e) {
  224. console.error(e);
  225. }
  226. btStatusReceiver = null;
  227. }
  228. btStatusReceiver = plus.android.implements(
  229. "io.dcloud.android.content.BroadcastReceiver",
  230. {
  231. onReceive: (context, intent) => {
  232. plus.android.importClass(context);
  233. plus.android.importClass(intent);
  234. let action = intent.getAction();
  235. switch (action) {
  236. case BluetoothAdapter.ACTION_STATE_CHANGED:
  237. let blueState = intent.getIntExtra(
  238. BluetoothAdapter.EXTRA_STATE,
  239. 0
  240. );
  241. let stateStr = "";
  242. switch (blueState) {
  243. case BluetoothAdapter.STATE_TURNING_ON:
  244. stateStr = "STATE_TURNING_ON";
  245. break;
  246. case BluetoothAdapter.STATE_ON:
  247. this.state.bluetoothEnable = true;
  248. stateStr = "STATE_ON";
  249. break;
  250. case BluetoothAdapter.STATE_TURNING_OFF:
  251. stateStr = "STATE_TURNING_OFF";
  252. break;
  253. case BluetoothAdapter.STATE_OFF:
  254. stateStr = "STATE_OFF";
  255. this.state.bluetoothEnable = false;
  256. break;
  257. }
  258. this.state.bluetoothState = stateStr;
  259. this.options.listenBTStatusCallback &&
  260. this.options.listenBTStatusCallback(stateStr);
  261. break;
  262. }
  263. },
  264. }
  265. );
  266. let filter = new IntentFilter();
  267. filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
  268. activity.registerReceiver(btStatusReceiver, filter);
  269. // 首次连接 状态回调
  270. if (this.state.bluetoothEnable) {
  271. this.options.listenBTStatusCallback &&
  272. this.options.listenBTStatusCallback("STATE_ON");
  273. }
  274. },
  275. /**
  276. * 根据蓝牙地址,连接设备
  277. * @param {Stirng} address
  278. * @return {Boolean}
  279. */
  280. connDevice(address, callback) {
  281. let InputStream = plus.android.importClass("java.io.InputStream");
  282. let OutputStream = plus.android.importClass("java.io.OutputStream");
  283. let BluetoothSocket = plus.android.importClass(
  284. "android.bluetooth.BluetoothSocket"
  285. );
  286. this.cancelDiscovery();
  287. if (btSocket != null) {
  288. this.closeBtSocket();
  289. }
  290. this.state.readThreadState = false;
  291. try {
  292. let device = invoke(btAdapter, "getRemoteDevice", address);
  293. btSocket = invoke(device, "createRfcommSocketToServiceRecord", MY_UUID);
  294. } catch (e) {
  295. console.error(e);
  296. shortToast("连接失败,获取Socket失败!");
  297. callback(false);
  298. return false;
  299. }
  300. try {
  301. invoke(btSocket, "connect");
  302. if (!btSocket.isConnected()) {
  303. this.shortToast("连接失败");
  304. callback(false);
  305. try {
  306. btSocket.close();
  307. btSocket = null;
  308. } catch (e1) {
  309. console.error(e1);
  310. }
  311. return false;
  312. }
  313. this.readData(); //读数据
  314. this.shortToast("连接成功");
  315. callback(true);
  316. } catch (e) {
  317. console.error(e);
  318. this.shortToast("连接失败");
  319. callback(false);
  320. try {
  321. btSocket.close();
  322. btSocket = null;
  323. } catch (e1) {
  324. console.error(e1);
  325. }
  326. return false;
  327. }
  328. return true;
  329. },
  330. /**
  331. * 断开连接设备
  332. * @param {Object} address
  333. * @return {Boolean}
  334. */
  335. disConnDevice() {
  336. if (btSocket != null) {
  337. this.closeBtSocket();
  338. }
  339. this.state.readThreadState = false;
  340. this.shortToast("断开连接成功");
  341. },
  342. /**
  343. * 断开连接设备
  344. * @param {Object} address
  345. * @return {Boolean}
  346. */
  347. closeBtSocket() {
  348. this.state.readThreadState = false;
  349. if (!btSocket) {
  350. return;
  351. }
  352. try {
  353. btSocket.close();
  354. } catch (e) {
  355. console.error(e);
  356. btSocket = null;
  357. }
  358. },
  359. /**
  360. * 取消发现
  361. */
  362. cancelDiscovery() {
  363. if (btAdapter.isDiscovering()) {
  364. btAdapter.cancelDiscovery();
  365. }
  366. if (btFindReceiver != null) {
  367. activity.unregisterReceiver(btFindReceiver);
  368. btFindReceiver = null;
  369. }
  370. this.state.discoveryDeviceState = false;
  371. },
  372. /**
  373. * 读取数据
  374. * @param {Object} activity
  375. * @param {Function} callback
  376. * @return {Boolean}
  377. */
  378. readData() {
  379. if (!btSocket) {
  380. this.shortToast("请先连接蓝牙设备!");
  381. return false;
  382. }
  383. try {
  384. btInStream = invoke(btSocket, "getInputStream");
  385. btOutStream = invoke(btSocket, "getOutputStream");
  386. } catch (e) {
  387. console.error(e);
  388. this.shortToast("创建输入输出流失败!");
  389. this.closeBtSocket();
  390. return false;
  391. }
  392. this.read();
  393. this.state.readThreadState = true;
  394. return true;
  395. },
  396. /**
  397. * 模拟java多线程读取数据
  398. */
  399. read() {
  400. let setTimeCount = 0;
  401. clearInterval(setIntervalId);
  402. setIntervalId = setInterval(() => {
  403. setTimeCount++;
  404. if (this.state.readThreadState) {
  405. let t = new Date().getTime();
  406. //心跳检测
  407. if (setTimeCount % 20 == 0) {
  408. try {
  409. btOutStream.write([0b00]);
  410. } catch (e) {
  411. this.state.readThreadState = false;
  412. this.options.connExceptionCallback &&
  413. this.options.connExceptionCallback(e);
  414. }
  415. }
  416. let dataArr = [];
  417. while (invoke(btInStream, "available") !== 0) {
  418. let data = invoke(btInStream, "read");
  419. dataArr.push(data);
  420. let ct = new Date().getTime();
  421. if (ct - t > 100) {
  422. break;
  423. }
  424. }
  425. if (dataArr.length > 0) {
  426. this.options.readDataCallback &&
  427. this.options.readDataCallback(dataArr);
  428. }
  429. }
  430. }, 40);
  431. },
  432. /**
  433. * 发送数据
  434. * @param {String} dataStr
  435. * @return {Boolean}
  436. */
  437. sendData(dataStr) {
  438. if (!btOutStream) {
  439. this.shortToast("创建输出流失败!");
  440. return;
  441. }
  442. let bytes = invoke(dataStr, "getBytes", "gbk");
  443. try {
  444. btOutStream.write(bytes);
  445. } catch (e) {
  446. return false;
  447. }
  448. return true;
  449. },
  450. sendByteData(byteData) {
  451. if (!btOutStream) {
  452. this.shortToast("创建输出流失败!");
  453. return;
  454. }
  455. try {
  456. btOutStream.write(byteData);
  457. } catch (e) {
  458. return false;
  459. }
  460. return true;
  461. },
  462. };
  463. module.exports = blueToothTool;