bluetoolth.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /**
  2. * @export
  3. * @param {string} name 微信api的名称 ,如 uniAsyncPromise("getSystemInfo",options)
  4. * @param {object} options 除了success 和 fail 的其他参数
  5. * @returns
  6. */
  7. export function uniAsyncPromise(name, options) {
  8. return new Promise((resolve, reject) => {
  9. uni[name]({
  10. ...(options || {}),
  11. // ...options,
  12. success: (res) => {
  13. resolve(res);
  14. },
  15. fail: (err) => {
  16. reject(err);
  17. }
  18. });
  19. });
  20. }
  21. //微信小程序向蓝牙打印机发送数据进行打印的坑:
  22. //小程序api向蓝牙打印机发送数据打印,发送的任何内容都应该要转成二进制数据,而且蓝牙打印的文本编码是GBK的,发送中文需转成GBK编码再转成二进制数据发送
  23. //发送打印机指令也要转成二进制数据发送
  24. //蓝牙打印机一次接收的二级制数据有限制,不同的系统不同的蓝牙设备限制可能不同,微信建议一次20个字节,需做递归分包发送
  25. //发送完要打印的内容后,一定要发送一个打印的指令才能顺利打印 (有些指令就不需要)
  26. //一、初始化蓝牙、开始检索蓝牙设备
  27. // { allowDuplicatesKey: true, interval: 500}
  28. export function openBlue() {
  29. return uniAsyncPromise('openBluetoothAdapter')
  30. }
  31. export function startBluetoothDevicesDiscovery(option) {
  32. console.log('开始蓝牙扫描');
  33. uniAsyncPromise('startBluetoothDevicesDiscovery', option).then((res) => {
  34. console.log('正在搜寻蓝牙设备', res);
  35. });
  36. }
  37. export function getConnectedBluetoothDevices(option) {
  38. console.log('开始获取已连接设备');
  39. return uniAsyncPromise('getConnectedBluetoothDevices', option)
  40. }
  41. //二、
  42. /**
  43. *
  44. *
  45. * @export
  46. * @param {function} getDevices uni.getBluetoothDevices的监听回调函数
  47. */
  48. export function onfindBlueDevices(getDevices) {
  49. //监听寻找到新设备的事件
  50. uni.onBluetoothDeviceFound((devices)=>{
  51. //获取在蓝牙模块生效期间所有已发现的蓝牙设备
  52. uniAsyncPromise('getBluetoothDevices').then((res) => {
  53. getDevices && getDevices(res.devices);
  54. });
  55. });
  56. }
  57. /**
  58. * @export
  59. * @param {function} stopBlueDevicesDiscovery 关闭蓝牙扫描
  60. */
  61. export function stopBlueDevicesDiscovery() {
  62. //监听寻找到新设备的事件
  63. console.log('停止蓝牙扫描');
  64. return uniAsyncPromise('stopBluetoothDevicesDiscovery').then((res) => {
  65. console.log('停止搜寻蓝牙设备', res);
  66. });
  67. }
  68. //三、连接蓝牙设备
  69. /**
  70. * @export
  71. * @param {function} createBLEConnection
  72. * @param {number} deviceId 蓝牙设备id
  73. */
  74. export function createBLEConnection(deviceId, sucess, fail) {
  75. //连接蓝牙设备
  76. console.log('连接蓝牙设备', deviceId);
  77. uniAsyncPromise("createBLEConnection", {
  78. deviceId,
  79. timeout: 10000
  80. })
  81. .then(res => {
  82. //连接成功可选择停止搜索蓝牙
  83. stopBlueDevicesDiscovery();
  84. console.log('连接成功');
  85. sucess && sucess({
  86. res: res,
  87. });
  88. })
  89. .catch(res => {
  90. console.log('连接设备异常' + res);
  91. fail && fail({
  92. res: res,
  93. });
  94. })
  95. /*.finally(res=>{
  96. console.log('连接成功');
  97. sucess && sucess({
  98. res: res,
  99. });
  100. });*/
  101. }
  102. export function closeBLEConnection(deviceId) {
  103. console.log('断开蓝牙设备', deviceId);
  104. uniAsyncPromise("closeBLEConnection", {
  105. deviceId
  106. })
  107. .then(res => {
  108. console.log('BLEDisconnect complete', res);
  109. })
  110. .catch(res => {
  111. console.log('断开设备异常' + res);
  112. })
  113. /*.finally(res=>{
  114. console.log('BLEDisconnect complete', res);
  115. }); */
  116. }
  117. //四、连接成功后, 获取蓝牙设备的service服务
  118. // uniAsyncPromise("getBLEDeviceServices",{deviceId:""}).then(res=>{})
  119. export function getBLEDeviceServices(deviceId, success, fail) {
  120. console.log('获取ServiceId', deviceId);
  121. //加延迟避免取不到service
  122. setTimeout(()=>{
  123. uniAsyncPromise("getBLEDeviceServices", {
  124. deviceId:deviceId
  125. })
  126. .then(res => {
  127. console.log('服务', res);
  128. success && success({
  129. serviceId: res.services,
  130. });
  131. })
  132. .catch((res) => {
  133. //getBLEDeviceServices(deviceId, success, fail);
  134. console.log('获取ServiceId异常' + res);
  135. fail && fail({
  136. res: res,
  137. });
  138. });
  139. },1000)
  140. }
  141. //五、获取的service服务可能有多个,递归获取特征值(最后要用的是能读,能写,能监听的那个值的uuid作为特征值id)
  142. /**
  143. *
  144. *
  145. * @export
  146. * @param {number} deviceId 蓝牙设备id
  147. * @param {array} services uniAsyncPromise("getBLEDeviceServices",{deviceId:""}).then(res=>{})获取的res.services
  148. * @param {function} success 成功取得有用特征值uuid的回调函数
  149. */
  150. export function getDeviceCharacteristics(deviceId, services, success, fail) {
  151. //services = services.slice(0);
  152. console.log('获取Characteristics', deviceId, services);
  153. if (services.length) {
  154. const serviceId = services.shift().uuid;
  155. console.log('ServceID ', serviceId);
  156. uniAsyncPromise('getBLEDeviceCharacteristics', {
  157. deviceId,
  158. serviceId,
  159. })
  160. .then((res) => {
  161. console.log('getBLEDeviceCharacteristics', deviceId, serviceId, res);
  162. let finished = false;
  163. let write = false;
  164. let notify = false;
  165. let indicate = false;
  166. var readId;
  167. var writeId;
  168. //有斑马品牌的一款打印机中res.characteristics的所有uuid都是相同的,找所有的properties存在(notify || indicate) && write这种情况就说明这个uuid是可用的(不确保所有的打印机都能用这种方式取得uuid,在主要测试得凯盛诺打印机res.characteristic只有一个uuid,所以也能用这个方式)
  169. for (var i = 0; i < res.characteristics.length; i++) {
  170. if (!notify) {
  171. notify = res.characteristics[i].properties.notify;
  172. if (notify) readId = res.characteristics[i].uuid;
  173. }
  174. if (!indicate) {
  175. indicate = res.characteristics[i].properties.indicate;
  176. if (indicate) readId = res.characteristics[i].uuid;
  177. }
  178. if (!write) {
  179. write = res.characteristics[i].properties.write;
  180. writeId = res.characteristics[i].uuid;
  181. }
  182. if ((notify || indicate) && write) {
  183. /* 获取蓝牙特征值uuid */
  184. success &&
  185. success({
  186. serviceId,
  187. writeId: writeId,
  188. readId: readId,
  189. });
  190. finished = true;
  191. break;
  192. }
  193. }
  194. if (!finished) {
  195. getDeviceCharacteristics(deviceId, services, success, fail);
  196. }
  197. })
  198. .catch((res) => {
  199. getDeviceCharacteristics(deviceId, services, success, fail);
  200. });
  201. } else {
  202. fail && fail();
  203. }
  204. }
  205. //六、启动notify 蓝牙监听功能 然后使用 uni.onBLECharacteristicValueChange用来监听蓝牙设备传递数据
  206. /**
  207. * @export
  208. * @param {object} options
  209. * {
  210. deviceId,//蓝牙设备id
  211. serviceId,//服务id
  212. characteristicId,//可用特征值uuid
  213. }
  214. * @param {function} onChange 监听蓝牙设备传递数据回调函数
  215. */
  216. export function onGetBLECharacteristicValueChange(options, onChange = function() {}) {
  217. console.log('deviceId ', options.deviceId);
  218. console.log('serviceId ', options.serviceId);
  219. console.log('characteristicId ', options.characteristicId);
  220. uniAsyncPromise('notifyBLECharacteristicValueChange', {
  221. state: true,
  222. ...options,
  223. }).then((res) => {
  224. console.log('onBLECharacteristicValueChange ');
  225. uni.onBLECharacteristicValueChange(onChange);
  226. });
  227. }
  228. //七、发送数据(递归分包发送)
  229. /**
  230. * @export
  231. * @param {object} options
  232. * {
  233. deviceId,
  234. serviceId,
  235. characteristicId,
  236. value [ArrayBuffer],
  237. lasterSuccess,
  238. }
  239. */
  240. export function senBlData(deviceId, serviceId, characteristicId,uint8Array,lasterSuccess,lasterError) {
  241. console.log('************deviceId = [' + deviceId + '] serviceId = [' + serviceId + '] characteristics=[' +characteristicId+ "]")
  242. var uint8Buf = Array.from(uint8Array);
  243. function split_array(datas,size){
  244. var result = {};
  245. var j = 0
  246. if(datas.length < size) {
  247. size = datas.length
  248. }
  249. for (var i = 0; i < datas.length; i += size) {
  250. result[j] = datas.slice(i, i + size)
  251. j++
  252. }
  253. return result
  254. }
  255. var sendloop = split_array(uint8Buf, 20);
  256. console.log(sendloop.length)
  257. function realWriteData(sendloop, i) {
  258. var data = sendloop[i]
  259. if(typeof(data) == "undefined"){
  260. lasterSuccess()
  261. return
  262. }
  263. //console.log("第【" + i + "】次写数据"+data)
  264. var buffer = new ArrayBuffer(data.length)
  265. var dataView = new DataView(buffer)
  266. for (var j = 0; j < data.length; j++) {
  267. dataView.setUint8(j, data[j]);
  268. }
  269. uni.writeBLECharacteristicValue({
  270. deviceId,
  271. serviceId,
  272. characteristicId,
  273. value: buffer,
  274. success(res) {
  275. console.log('发送成功',i)
  276. setTimeout(()=>{
  277. realWriteData(sendloop, i + 1);
  278. },100)
  279. },
  280. fail(e) {
  281. console.log('发送数据失败',e)
  282. lasterError()
  283. }
  284. })
  285. }
  286. var i = 0;
  287. realWriteData(sendloop, i);
  288. }
  289. // cpcl 发送数据
  290. export function sendDataToDevice(options) {
  291. let byteLength = options.value.byteLength;
  292. //这里默认一次20个字节发送
  293. const speed = plus.os.name != 'Android' ? 180 : 15; //20;
  294. console.log("send data 20");
  295. console.log(options,byteLength,options.value);
  296. if (byteLength > 0) {
  297. uniAsyncPromise('writeBLECharacteristicValue', {
  298. ...options,
  299. value: options.value.slice(0, byteLength > speed ? speed : byteLength),
  300. })
  301. .then((res) => {
  302. if (byteLength > speed) {
  303. setTimeout(()=>{
  304. sendDataToDevice({
  305. ...options,
  306. value: options.value.slice(speed, byteLength),
  307. });
  308. },50)
  309. } else {
  310. options.lasterSuccess && options.lasterSuccess();
  311. }
  312. })
  313. .catch((res) => {
  314. console.log(res);
  315. options.lasterError && options.lasterError();
  316. });
  317. }
  318. }
  319. /**
  320. * toast显示捕获的蓝牙异常
  321. */
  322. export function catchToast(err) {
  323. const errMsg = {
  324. 10000: '未初始化蓝牙模块',
  325. 10001: '蓝牙未打开,请打开蓝牙开关',
  326. 10002: '没有找到指定设备',
  327. 10003: '连接失败',
  328. 10004: '没有找到指定服务',
  329. 10005: '没有找到指定特征值',
  330. 10006: '当前连接已断开',
  331. 10007: '当前特征值不支持此操作',
  332. 10008: '系统上报异常',
  333. 10009: '系统版本低于 4.3 不支持BLE',
  334. 10012: '连接超时,请重试'
  335. };
  336. let coode = err.errCode ? err.errCode.toString() : '';
  337. let msg = errMsg[coode];
  338. plus.nativeUI.toast(msg || coode, {
  339. align: 'center',
  340. verticalAlign: 'center',
  341. duration:'long'
  342. });
  343. }