bluetooth.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta charset="utf-8"/>
  5. <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
  6. <meta name="HandheldFriendly" content="true"/>
  7. <meta name="MobileOptimized" content="320"/>
  8. <title>Hello H5+</title>
  9. <script type="text/javascript" src="../js/common.js"></script>
  10. <script type="text/javascript">
  11. var bds = []; // 可连接设备列表
  12. var deviceId = null, bconnect = false;
  13. var bss = []; // 连接设备服务列表
  14. var serviceId = null;
  15. var bscs = []; // 连接设备服务对应的特征值列表
  16. var characteristicId = null;
  17. var bscws = []; // 可写特征值列表
  18. var wcharacteristicId = null;
  19. // 重设数据
  20. function resetDevices(d,s){
  21. d||(bds=[],deviceId=null,document.getElementById('deivce').value='');
  22. s||(bss=[],serviceId=null,document.getElementById('service').value='');
  23. bscs=[],bscws=[],characteristicId=null,wcharacteristicId=null,document.getElementById('characteristic').value='',document.getElementById('wcharacteristic').value='';
  24. }
  25. // 页面初始化操作
  26. document.addEventListener('plusready', function(e){
  27. // 监听蓝牙适配器状态变化
  28. plus.bluetooth.onBluetoothAdapterStateChange(function(e){
  29. outLine('onBluetoothAdapterStateChange: '+JSON.stringify(e));
  30. });
  31. // 监听搜索到新设备
  32. plus.bluetooth.onBluetoothDeviceFound(function(e){
  33. var devices = e.devices;
  34. outLine('onBluetoothDeviceFound: '+devices.length);
  35. for(var i in devices){
  36. outLine(JSON.stringify(devices[i]));
  37. var device = devices[i];
  38. if(device.deviceId/*&&device.name&&device.name.length>0&&device.name!='null'*/){
  39. bds.push(device);
  40. }
  41. }
  42. if(!bconnect && bds.length>0){ // 默认选择最后一个
  43. var n = bds[bds.length-1].name;
  44. if(!n || n.length<=0){
  45. n = bds[bds.length-1].deviceId;
  46. }
  47. document.getElementById('deivce').value = n;
  48. deviceId = bds[bds.length-1].deviceId;
  49. }
  50. });
  51. // 监听低功耗蓝牙设备连接状态变化
  52. plus.bluetooth.onBLEConnectionStateChange(function(e){
  53. outLine('onBLEConnectionStateChange: '+JSON.stringify(e));
  54. if(deviceId == e.deviceId){ // 更新连接状态
  55. bconnect = e.connected;
  56. }
  57. });
  58. // 监听低功耗蓝牙设备的特征值变化
  59. plus.bluetooth.onBLECharacteristicValueChange(function(e){
  60. outLine('onBLECharacteristicValueChange: '+JSON.stringify(e));
  61. var value = buffer2hex(e.value);
  62. outLine('value(hex) = '+value);
  63. if(characteristicId == e.characteristicId){
  64. // 更新到页面显示
  65. document.getElementById('readvalue').value = value;
  66. }else if(wcharacteristicId == e.characteristicId){
  67. plus.nativeUI.toast(value);
  68. }
  69. });
  70. }, false);
  71. function buffer2hex(value){
  72. var t='';
  73. if(value){
  74. var v=new Uint8Array(value);
  75. for(var i in v){
  76. t += '0x'+v[i].toString(16)+' ';
  77. }
  78. }else{
  79. t='无效值';
  80. }
  81. return t;
  82. }
  83. // 打开蓝牙
  84. function openBluetooth(){
  85. outSet('打开蓝牙适配器:');
  86. plus.bluetooth.openBluetoothAdapter({
  87. success: function(e){
  88. outLine('打开成功!');
  89. },
  90. fail: function(e){
  91. outLine('打开失败! '+JSON.stringify(e));
  92. }
  93. });
  94. }
  95. // 开始搜索蓝牙设备
  96. function startDiscovery(){
  97. outSet('开始搜索蓝牙设备:');
  98. resetDevices();
  99. plus.bluetooth.startBluetoothDevicesDiscovery({
  100. success: function(e){
  101. outLine('开始搜索成功!');
  102. },
  103. fail: function(e){
  104. outLine('开始搜索失败! '+JSON.stringify(e));
  105. }
  106. });
  107. }
  108. // 停止搜索蓝牙设备
  109. function stopDiscovery(){
  110. outSet('停止搜索蓝牙设备:');
  111. plus.bluetooth.stopBluetoothDevicesDiscovery({
  112. success: function(e){
  113. outLine('停止搜索成功!');
  114. },
  115. fail: function(e){
  116. outLine('停止搜索失败! '+JSON.stringify(e));
  117. }
  118. });
  119. }
  120. // 选择蓝牙设备
  121. function selectDevice(){
  122. if(bds.length <= 0){
  123. plus.nativeUI.toast('未搜索到有效蓝牙设备!');
  124. return;
  125. }
  126. var bts=[];
  127. for(var i in bds){
  128. var t = bds[i].name;
  129. if(!t || t.length<=0){
  130. t = bds[i].deviceId;
  131. }
  132. bts.push({title:t});
  133. }
  134. plus.nativeUI.actionSheet({title:"选择蓝牙设备",cancel:"取消",buttons:bts}, function(e){
  135. if(e.index>0){
  136. document.getElementById('deivce').value = bds[e.index-1].name;
  137. deviceId = bds[e.index-1].deviceId;
  138. outLine('选择了"'+bds[e.index-1].name+'"');
  139. }
  140. });
  141. }
  142. // 连接蓝牙设备
  143. function connectDevice(){
  144. if(!deviceId){
  145. plus.nativeUI.toast('未选择设备!');
  146. return;
  147. }
  148. outSet('连接设备: '+deviceId);
  149. plus.bluetooth.createBLEConnection({
  150. deviceId: deviceId,
  151. success: function(e){
  152. outLine('连接成功!');
  153. },
  154. fail: function(e){
  155. outLine('连接失败! '+JSON.stringify(e));
  156. }
  157. });
  158. }
  159. // 获取设备服务
  160. function getServices(){
  161. if(!deviceId){
  162. plus.nativeUI.toast('未选择设备!');
  163. return;
  164. }
  165. if(!bconnect){
  166. plus.nativeUI.toast('未连接蓝牙设备!');
  167. return;
  168. }
  169. resetDevices(true);
  170. outSet('获取蓝牙设备服务:');
  171. plus.bluetooth.getBLEDeviceServices({
  172. deviceId: deviceId,
  173. success: function(e){
  174. var services = e.services;
  175. outLine('获取服务成功! '+services.length);
  176. if(services.length>0){
  177. for(var i in services){
  178. bss.push(services[i]);
  179. outLine(JSON.stringify(services[i]));
  180. }
  181. if(bss.length>0){ // 默认选择最后一个服务
  182. document.getElementById('service').value = serviceId = bss[bss.length-1].uuid;
  183. }
  184. }else{
  185. outLine('获取服务列表为空?');
  186. }
  187. },
  188. fail: function(e){
  189. outLine('获取服务失败! '+JSON.stringify(e));
  190. }
  191. });
  192. }
  193. // 选择服务
  194. function selectService(){
  195. if(bss.length <= 0){
  196. plus.nativeUI.toast('未获取到有效蓝牙服务!');
  197. return;
  198. }
  199. var bts=[];
  200. for(var i in bss){
  201. bts.push({title:bss[i].uuid});
  202. }
  203. plus.nativeUI.actionSheet({title:"选择服务",cancel:"取消",buttons:bts}, function(e){
  204. if(e.index>0){
  205. document.getElementById('service').value = serviceId = bss[e.index-1].uuid;
  206. outLine('选择了服务: "'+serviceId+'"');
  207. }
  208. });
  209. }
  210. // 获取服务的特征值
  211. function getCharacteristics(){
  212. if(!deviceId){
  213. plus.nativeUI.toast('未选择设备!');
  214. return;
  215. }
  216. if(!bconnect){
  217. plus.nativeUI.toast('未连接蓝牙设备!');
  218. return;
  219. }
  220. if(!serviceId){
  221. plus.nativeUI.toast('未选择服务!');
  222. return;
  223. }
  224. resetDevices(true, true);
  225. outSet('获取蓝牙设备指定服务的特征值:');
  226. plus.bluetooth.getBLEDeviceCharacteristics({
  227. deviceId: deviceId,
  228. serviceId: serviceId,
  229. success: function(e){
  230. var characteristics = e.characteristics;
  231. outLine('获取特征值成功! '+characteristics.length);
  232. if(characteristics.length>0){
  233. for(var i in characteristics){
  234. var characteristic = characteristics[i];
  235. outLine(JSON.stringify(characteristic));
  236. if(characteristic.properties){
  237. if(characteristic.properties.read){
  238. bscs.push(characteristics[i]);
  239. }
  240. if(characteristic.properties.write){
  241. bscws.push(characteristics[i]);
  242. if(characteristic.properties.notify||characteristic.properties.indicate){
  243. plus.bluetooth.notifyBLECharacteristicValueChange({ //监听数据变化
  244. deviceId: deviceId,
  245. serviceId: serviceId,
  246. characteristicId: characteristic.uuid,
  247. success: function(e){
  248. outLine('notifyBLECharacteristicValueChange '+characteristic.uuid+' success.');
  249. },
  250. fail: function(e){
  251. outLine('notifyBLECharacteristicValueChange '+characteristic.uuid+' failed! '+JSON.stringify(e));
  252. }
  253. });
  254. }
  255. }
  256. }
  257. }
  258. if(bscs.length>0){ // 默认选择最后特征值
  259. document.getElementById('characteristic').value = characteristicId = bscs[bscs.length-1].uuid;
  260. }
  261. if(bscws.length>0){ // 默认选择最后一个可写特征值
  262. document.getElementById('wcharacteristic').value = wcharacteristicId = bscws[bscws.length-1].uuid;
  263. }
  264. }else{
  265. outLine('获取特征值列表为空?');
  266. }
  267. },
  268. fail: function(e){
  269. outLine('获取特征值失败! '+JSON.stringify(e));
  270. }
  271. });
  272. }
  273. // 选择特征值(读取)
  274. function selectCharacteristic(){
  275. if(bscs.length <= 0){
  276. plus.nativeUI.toast('未获取到有效可读特征值!');
  277. return;
  278. }
  279. var bts=[];
  280. for(var i in bscs){
  281. bts.push({title:bscs[i].uuid});
  282. }
  283. plus.nativeUI.actionSheet({title:'选择特征值',cancel:'取消',buttons:bts}, function(e){
  284. if(e.index>0){
  285. document.getElementById('characteristic').value = characteristicId = bscs[e.index-1].uuid;
  286. outLine('选择了特征值: "'+characteristicId+'"');
  287. }
  288. });
  289. }
  290. // 读取特征值数据
  291. function readValue(){
  292. if(!deviceId){
  293. plus.nativeUI.toast('未选择设备!');
  294. return;
  295. }
  296. if(!bconnect){
  297. plus.nativeUI.toast('未连接蓝牙设备!');
  298. return;
  299. }
  300. if(!serviceId){
  301. plus.nativeUI.toast('未选择服务!');
  302. return;
  303. }
  304. if(!characteristicId){
  305. plus.nativeUI.toast('未选择读取的特征值!');
  306. return;
  307. }
  308. outSet('读取蓝牙设备的特征值数据: ');
  309. plus.bluetooth.readBLECharacteristicValue({
  310. deviceId: deviceId,
  311. serviceId: serviceId,
  312. characteristicId: characteristicId,
  313. success: function(e){
  314. outLine('读取数据成功!');
  315. },
  316. fail: function(e){
  317. outLine('读取数据失败! '+JSON.stringify(e));
  318. }
  319. });
  320. }
  321. // 选择特征值(写入)
  322. function selectwCharacteristic(){
  323. if(bscws.length <= 0){
  324. plus.nativeUI.toast('未获取到有效可写特征值!');
  325. return;
  326. }
  327. var bts=[];
  328. for(var i in bscws){
  329. bts.push({title:bscws[i].uuid});
  330. }
  331. plus.nativeUI.actionSheet({title:'选择特征值',cancel:'取消',buttons:bts}, function(e){
  332. if(e.index>0){
  333. document.getElementById('wcharacteristic').value = wcharacteristicId = bscws[e.index-1].uuid;
  334. outLine('选择了特征值: "'+wcharacteristicId+'"');
  335. }
  336. });
  337. }
  338. // 写入特征值数据
  339. function writeValue(){
  340. if(!deviceId){
  341. plus.nativeUI.toast('未选择设备!');
  342. return;
  343. }
  344. if(!bconnect){
  345. plus.nativeUI.toast('未连接蓝牙设备!');
  346. return;
  347. }
  348. if(!serviceId){
  349. plus.nativeUI.toast('未选择服务!');
  350. return;
  351. }
  352. if(!wcharacteristicId){
  353. plus.nativeUI.toast('未选择写入的特征值!');
  354. return;
  355. }
  356. var value = document.getElementById('writevalue').value;
  357. if(!value || value==''){
  358. plus.nativeUI.toast('请输入需要写入的数据');
  359. document.getElementById('writevalue').focus();
  360. return;
  361. }
  362. // 转换为ArrayBuffer写入蓝牙
  363. str2ArrayBuffer(value, function(buffer){
  364. outSet('写入蓝牙设备的特征值数据: ');
  365. plus.bluetooth.writeBLECharacteristicValue({
  366. deviceId: deviceId,
  367. serviceId: serviceId,
  368. characteristicId: wcharacteristicId,
  369. value: buffer,
  370. success: function(e){
  371. outLine('写入数据成功!');
  372. },
  373. fail: function(e){
  374. outLine('写入数据失败! '+JSON.stringify(e));
  375. }
  376. });
  377. });
  378. }
  379. function str2ArrayBuffer(s,f) {
  380.     var b = new Blob([s],{type:'text/plain'});
  381.     var r = new FileReader();
  382.     r.readAsArrayBuffer(b);
  383.     r.onload = function(){if(f)f.call(null,r.result)}
  384. }
  385. // 断开蓝牙设备
  386. function disconnectDevice(){
  387. if(!deviceId){
  388. plus.nativeUI.toast('未选择设备!');
  389. return;
  390. }
  391. resetDevices(true);
  392. outSet('断开蓝牙设备连接:');
  393. plus.bluetooth.closeBLEConnection({
  394. deviceId: deviceId,
  395. success: function(e){
  396. outLine('断开连接成功!');
  397. },
  398. fail: function(e){
  399. outLine('断开连接失败! '+JSON.stringify(e));
  400. }
  401. });
  402. }
  403. // 关闭蓝牙
  404. function closeBluetooth(){
  405. outSet('关闭蓝牙适配器:');
  406. resetDevices();
  407. plus.bluetooth.closeBluetoothAdapter({
  408. success: function(e){
  409. outLine('关闭成功!');
  410. bconnect = false;
  411. },
  412. fail: function(e){
  413. outLine('关闭失败! '+JSON.stringify(e));
  414. }
  415. });
  416. }
  417. </script>
  418. <link rel="stylesheet" href="../css/common.css" type="text/css" charset="utf-8"/>
  419. </head>
  420. <body>
  421. <br/>
  422. <div class="button" onclick="openBluetooth()">初始化蓝牙模块</div>
  423. <div class="button" onclick="startDiscovery()">开始搜索蓝牙设备</div>
  424. <div class="button" onclick="stopDiscovery()">停止搜索蓝牙设备</div>
  425. 设备:<input id="deivce" type="text" disabled="disabled"></input>
  426. <a href="#" onclick="selectDevice()">选择设备</a>
  427. <div class="button" onclick="connectDevice()">连接蓝牙设备</div>
  428. <div class="button" onclick="getServices()">获取设备服务</div>
  429. 服务:<input id="service" type="text" disabled="disabled"></input>
  430. <a href="#" onclick="selectService()">选择服务</a>
  431. <div class="button" onclick="getCharacteristics()">获取服务的特征值</div>
  432. 读取特征值:<input id="characteristic" type="text" disabled="disabled"></input>
  433. <a href="#" onclick="selectCharacteristic()">选择</a>
  434. <div class="button" onclick="readValue()">读取特征值数据</div>
  435. 读取数据:<input id="readvalue" type="text" disabled="disabled" style="width:60%"></input>
  436. <hr/>
  437. <br/>
  438. 写入特征值:<input id="wcharacteristic" type="text" disabled="disabled"></input>
  439. <a href="#" onclick="selectwCharacteristic()">选择</a>
  440. <div class="button" onclick="writeValue()">写入特征值数据</div>
  441. 写入数据:<input id="writevalue" type="text" style="width:60%;-webkit-user-select:text" value="test"></input>
  442. <div class="button" onclick="disconnectDevice()">断开蓝牙设备</div>
  443. <div class="button" onclick="closeBluetooth()">关闭蓝牙模块</div>
  444. <div id="outpos"/>
  445. <div id="output">
  446. Bluetooth用于管理蓝牙设备,搜索附近蓝牙设备、连接实现数据通信等。
  447. </div>
  448. </body>
  449. </html>