ouu-nfc.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. // 包路径
  2. const package_NdefRecord = 'android.nfc.NdefRecord';
  3. const package_NdefMessage = 'android.nfc.NdefMessage';
  4. const package_TECH_DISCOVERED = 'android.nfc.action.TECH_DISCOVERED';
  5. const package_Intent = 'android.content.Intent';
  6. const package_Activity = 'android.app.Activity';
  7. const package_PendingIntent = 'android.app.PendingIntent';
  8. const package_IntentFilter = 'android.content.IntentFilter';
  9. const package_NfcAdapter = 'android.nfc.NfcAdapter';
  10. const package_Ndef = 'android.nfc.tech.Ndef';
  11. const package_NdefFormatable = 'android.nfc.tech.NdefFormatable';
  12. const package_Parcelable = 'android.os.Parcelable';
  13. const package_String = 'java.lang.String';
  14. let NfcAdapter;
  15. let NdefRecord;
  16. let NdefMessage;
  17. let Uri;
  18. let readyWriteData = false;
  19. let readyRead = false;
  20. let readySetPwd = false;
  21. let readyDelPwd = false;
  22. let readyGetNfcState = false;
  23. let readyWriteAndLock = false;
  24. let noNFC = false;
  25. let techListsArray = [
  26. ['android.nfc.tech.IsoDep'],
  27. ['android.nfc.tech.NfcA'],
  28. ['android.nfc.tech.NfcB'],
  29. ['android.nfc.tech.NfcF'],
  30. ['android.nfc.tech.Nfcf'],
  31. ['android.nfc.tech.NfcV'],
  32. ['android.net.Uri'],
  33. ['android.nfc.tech.NdefFormatable'],
  34. ['android.nfc.tech.MifareClassi'],
  35. ['android.nfc.tech.MifareUltralight']
  36. ];
  37. let UriPrefixMap = [];
  38. UriPrefixMap[0x00] = '';
  39. UriPrefixMap[0x01] = 'http://www.';
  40. UriPrefixMap[0x02] = 'https://www.';
  41. UriPrefixMap[0x03] = 'http://';
  42. UriPrefixMap[0x04] = 'https://';
  43. UriPrefixMap[0x05] = 'tel:';
  44. UriPrefixMap[0x06] = 'mailto:';
  45. UriPrefixMap[0x07] = 'ftp://anonymous:anonymous@';
  46. UriPrefixMap[0x08] = 'ftp://ftp.';
  47. UriPrefixMap[0x09] = 'ftps://';
  48. let writeUri = 'http://www.beswell.com'; // 要写入的数据
  49. let readResult = ''; // NFC读取到的数据
  50. let pwdBytes = [1, 2, 3, 4]; // 待写入的密码
  51. let pwdDefault = [0xFF, 0xFF, 0xFF, 0xFF] // 清除密码后设置的默认值
  52. export default {
  53. listenNFCStatus: function() {
  54. let that = this;
  55. try {
  56. let main = plus.android.runtimeMainActivity();
  57. let Intent = plus.android.importClass('android.content.Intent');
  58. let Activity = plus.android.importClass('android.app.Activity');
  59. let PendingIntent = plus.android.importClass('android.app.PendingIntent');
  60. let IntentFilter = plus.android.importClass('android.content.IntentFilter');
  61. Uri = plus.android.importClass('android.net.Uri');
  62. NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');
  63. let nfcAdapter = NfcAdapter.getDefaultAdapter(main);
  64. if (nfcAdapter == null) {
  65. uni.showToast({
  66. title: '设备不支持NFC!',
  67. icon: 'none'
  68. })
  69. noNFC = true;
  70. return;
  71. }
  72. if (!nfcAdapter.isEnabled()) {
  73. uni.showToast({
  74. title: '请在系统设置中先启用NFC功能!',
  75. icon: 'none'
  76. });
  77. noNFC = true;
  78. return;
  79. } else {
  80. noNFC = false;
  81. }
  82. let intent = new Intent(main, main.getClass());
  83. intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
  84. let pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);
  85. let ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");
  86. ndef.addDataType("*/*");
  87. let intentFiltersArray = [ndef];
  88. plus.globalEvent.addEventListener('newintent', function() {
  89. console.log('newintent running');
  90. // 监听 NFC
  91. setTimeout(()=>{
  92. that.nfcRuning()
  93. }, 100);
  94. });
  95. plus.globalEvent.addEventListener('pause', function(e) {
  96. console.log('pause running');
  97. if (nfcAdapter) {
  98. //关闭前台调度系统
  99. //恢复默认状态
  100. nfcAdapter.disableForegroundDispatch(main);
  101. }
  102. });
  103. plus.globalEvent.addEventListener('resume', function(e) {
  104. console.log('resume running');
  105. if (nfcAdapter) {
  106. //开启前台调度系统
  107. nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray,
  108. techListsArray);
  109. }
  110. });
  111. nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);
  112. } catch (e) {
  113. console.error(e);
  114. }
  115. },
  116. nfcRuning: function() {
  117. NdefRecord = plus.android.importClass("android.nfc.NdefRecord");
  118. NdefMessage = plus.android.importClass("android.nfc.NdefMessage");
  119. let main = plus.android.runtimeMainActivity();
  120. let intent = main.getIntent();
  121. // let intent = plus.android.invoke(main, 'getIntent');
  122. let that = this;
  123. console.log("action type:" + intent.getAction());
  124. if (package_TECH_DISCOVERED == intent.getAction()) {
  125. if (readyWriteData) {
  126. that.write(intent);
  127. readyWriteData = false;
  128. } else if (readyRead) {
  129. that.read(intent);
  130. readyRead = false;
  131. } else if (readySetPwd) {
  132. that.setPassword(intent);
  133. readySetPwd = false;
  134. } else if (readyDelPwd) {
  135. that.delPassword(intent);
  136. readyDelPwd = false;
  137. } else if (readyGetNfcState) {
  138. that.getState(intent);
  139. readyGetNfcState = false;
  140. } else if (readyWriteAndLock) {
  141. let result = that.write(intent);
  142. if (result == 999) { // 已设置密码保护
  143. readyWriteAndLock = false;
  144. return
  145. }
  146. setTimeout(()=>{
  147. that.setPassword(intent)
  148. }, 100);
  149. readyWriteAndLock = false;
  150. } else {
  151. that.read(intent);
  152. readyRead = false;
  153. }
  154. }
  155. },
  156. write(intent) {
  157. try {
  158. toast('请勿移开标签 正在写入...');
  159. console.log("NFC写入内容 writeUri = " + writeUri);
  160. // let textBytes = plus.android.invoke(writeUri, "getBytes");
  161. let uri = Uri.parse(writeUri)
  162. let message = new NdefMessage([new NdefRecord.createUri(uri)]);
  163. console.log("==== message ===>", message)
  164. let Ndef = plus.android.importClass('android.nfc.tech.Ndef');
  165. let NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');
  166. let tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  167. let MifareUltralight = plus.android.importClass('android.nfc.tech.MifareUltralight');
  168. let mfc = MifareUltralight.get(tag);
  169. if (mfc != null) {
  170. mfc.connect();
  171. let responseAuth0 = mfc.readPages(0x29)
  172. console.log("responseAuth0=" + JSON.stringify(responseAuth0));
  173. if (responseAuth0[3] == 0x00) {
  174. toast('已设置密码保护,无法写入数据');
  175. return 999;
  176. }
  177. mfc.close();
  178. }
  179. let ndef = Ndef.get(tag);
  180. if (ndef != null) {
  181. // 待写入的数据长度
  182. let size = message.toByteArray().length;
  183. ndef.connect();
  184. if (!ndef.isWritable()) {
  185. ndef.close();
  186. toast('tag不允许写入!');
  187. return;
  188. }
  189. if (ndef.getMaxSize() < size) {
  190. ndef.close();
  191. toast('文件大小超出容量!');
  192. return;
  193. }
  194. ndef.writeNdefMessage(message);
  195. ndef.close();
  196. toast('写入数据成功!');
  197. return;
  198. } else {
  199. let format = NdefFormatable.get(tag);
  200. if (format != null) {
  201. try {
  202. format.connect();
  203. format.format(message);
  204. format.close();
  205. toast('格式化tag并且写入message');
  206. return;
  207. } catch (e) {
  208. toast('格式化tag失败.');
  209. return;
  210. }
  211. } else {
  212. toast('Tag不支持NDEF');
  213. return;
  214. }
  215. }
  216. } catch (e) {
  217. toast('写入失败');
  218. console.log("error=" + e);
  219. }
  220. },
  221. read(intent) {
  222. toast('请勿移开标签正在读取数据');
  223. let that = this;
  224. // NFC id
  225. let bytesId = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
  226. let nfc_id = that.byteArrayToHexString(bytesId);
  227. // console.log('nfc_id: ' + nfc_id);
  228. // let Parcelable = plus.android.importClass("android.os.Parcelable");
  229. // tmp add
  230. // let Tag = plus.android.importClass('android.nfc.Tag');
  231. // let Ndef = plus.android.importClass('android.nfc.tech.Ndef');
  232. // let tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  233. // let ndef = Ndef.get(tag);
  234. // let nfc_type = that.byteArrayToHexString(ndef.getType());
  235. // console.log('nfc_type:"' + nfc_type + '"')
  236. let rawmsgs = intent.getParcelableArrayExtra("android.nfc.extra.NDEF_MESSAGES");
  237. // let rawmsgs = plus.android.invoke(intent, 'getParcelableArrayExtra', 'android.nfc.extra.NDEF_MESSAGES');
  238. // let rawmsgs = intent.getParcelableArrayExtra();
  239. if (rawmsgs != null && rawmsgs.length > 0) {
  240. // console.log('rawmsgs:"' + JSON.stringify(rawmsgs) + '"')
  241. let records = rawmsgs[0].getRecords();
  242. // let records = plus.android.invoke(rawmsgs[0], 'getRecords');
  243. let tnf = records[0].getTnf();
  244. // let tnf = plus.android.invoke(records[0], 'getTnf');
  245. // console.log('tnf = ' + JSON.stringify(tnf))
  246. // console.log('TNF_WELL_KNOWN = ' + JSON.stringify(NdefRecord.TNF_WELL_KNOWN))
  247. // console.log('TNF_ABSOLUTE_URI = ' + JSON.stringify(NdefRecord.TNF_ABSOLUTE_URI))
  248. let recordType = records[0].getType();
  249. // console.log('recordType = ' + JSON.stringify(recordType))
  250. // console.log('RTD_URI = ' + JSON.stringify(NdefRecord.RTD_URI))
  251. let result = records[0].getPayload();
  252. let data = ''
  253. if (tnf.__UUID__ == NdefRecord.TNF_WELL_KNOWN.value) {
  254. console.log('tnf == TNF_WELL_KNOWN')
  255. if (recordType == NdefRecord.RTD_URI) { // URI based on payload
  256. // 在URI Record Payload中,第一个字节指明URI的ID码,对应 UriPrefixMap
  257. console.log('recordType == NdefRecord.RTD_URI')
  258. // console.log('result[0]:"' + result[0] + '"')
  259. let uriPrefix = UriPrefixMap[result[0]]
  260. console.log('uriPrefix:"' + uriPrefix + '"')
  261. result.shift() // 去除URI的ID码
  262. data = plus.android.newObject("java.lang.String", result);
  263. data = uriPrefix + data
  264. }
  265. // } else if (tnf.__UUID__ == NdefRecord.TNF_ABSOLUTE_URI.value) {
  266. // console.log('tnf == TNF_ABSOLUTE_URI')
  267. } else {
  268. console.log('tnf:"' + tnf + '"')
  269. data = plus.android.newObject("java.lang.String", result);
  270. }
  271. // console.log('result:"' + result + '"')
  272. // console.log('NFC 数据:"' + data + '"')
  273. // toast('NFC 数据:' + data);
  274. // plus.runtime.openURL(data, function(res) {
  275. // console.log("打开浏览器路径失败!----", res);
  276. // });
  277. // return data;
  278. readResult = {
  279. id: nfc_id,
  280. data: data
  281. };
  282. } else {
  283. // toast('没有读取到数据');
  284. readResult = {
  285. id: nfc_id,
  286. data: ''
  287. };
  288. }
  289. console.log('NFC 数据:' + JSON.stringify(readResult));
  290. uni.$emit('NfcRead', readResult)
  291. },
  292. setPassword(intent) {
  293. try {
  294. toast('请勿移开标签 正在设置密码...');
  295. let MifareUltralight = plus.android.importClass('android.nfc.tech.MifareUltralight');
  296. let tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  297. let mfc = MifareUltralight.get(tag);
  298. if (mfc != null) {
  299. mfc.connect();
  300. // let response = plus.android.invoke(mfc, 'transceive', [0x1B, pwdDefault[0], pwdDefault[1], pwdDefault[2], pwdDefault[3]])
  301. // // let response = mfc.transceive([0x1B, pwdDefault[0], pwdDefault[1], pwdDefault[2], pwdDefault[3]])
  302. // console.log("询问登录 response=" + JSON.stringify(response));
  303. //pack置为默认
  304. mfc.writePage(0x2C, [0x00, 0x00, 0x00, 0x00])
  305. // set PWD: 设置密码为用户设置的密码
  306. mfc.writePage(0x2B, pwdBytes)
  307. // 设置Auth0 auth0实际控制是否启用密码保护 设置为00表示从第0页开始提供保护
  308. // let responseAuth0 = mfc.readPages(0x29)
  309. // console.log("responseAuth0=" + JSON.stringify(responseAuth0));
  310. mfc.writePage(0x29, [0x04, 0x00, 0x00, 0x00])
  311. mfc.close();
  312. toast('设置密码成功!');
  313. return;
  314. } else {
  315. toast('Tag不支持MifareUltralight');
  316. return;
  317. }
  318. } catch (e) {
  319. toast('设置密码失败');
  320. console.log("设置密码失败 error=" + e);
  321. }
  322. },
  323. delPassword(intent) {
  324. try {
  325. toast('请勿移开标签 正在清除密码...');
  326. let MifareUltralight = plus.android.importClass('android.nfc.tech.MifareUltralight');
  327. let tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  328. let mfc = MifareUltralight.get(tag);
  329. // let mfc2 = plus.android.invoke(MifareUltralight, 'get', tag) // to do
  330. if (mfc != null) {
  331. mfc.connect();
  332. //js不支持无符号整数,无法传输大于0X7F的值
  333. // mfc.writePage(0x08, [0x01, 0x02, 0x03, 0x04])
  334. // mfc.writePage(0x09, [0x7D, 0x7E, 0x7F, (0x80>>>0)])
  335. // mfc.writePage(0x0A, [0x80>>>0, 0x81>>>0, 0xFE>>>0, 0xFF>>>0])
  336. // return
  337. //用用户设置的密码询问登录
  338. // let response = plus.android.invoke(mfc, 'transceive', [0x1B, pwdBytes[0], pwdBytes[1], pwdBytes[2], pwdBytes[3]])
  339. let response = mfc.transceive([0x1B, pwdBytes[0], pwdBytes[1], pwdBytes[2], pwdBytes[3]])
  340. console.log("询问登录 response=" + JSON.stringify(response));
  341. if (response != null) {
  342. // if (response[0] == 0x00 && response[1] == 0x00) {
  343. if (response == '0,0') {
  344. console.log("密码校验正确");
  345. } else {
  346. mfc.close();
  347. console.log("密码校验失败");
  348. toast('密码校验失败');
  349. return
  350. }
  351. } else {
  352. mfc.close();
  353. console.log("询问登录 response 无效");
  354. toast('密码验证失败 或 未设置密码');
  355. return
  356. }
  357. //pack置为默认
  358. mfc.writePage(0x2C, [0x00, 0x00, 0x00, 0x00])
  359. // set PWD: 设置密码为默认密码
  360. mfc.writePage(0x2B, pwdDefault)
  361. // set AUTHLIM:
  362. //将AUTHLIM(第42页,字节0,位2-0)设置为失败的最大密码验证尝试次数
  363. mfc.writePage(0x2A, [0x00, 0x05, 0x00, 0x00])
  364. // 设置Auth0 auth0实际控制是否启用密码保护 设置为FF表示禁用密码保护
  365. // let responseAuth0 = mfc.readPages(0x29)
  366. // console.log("responseAuth0=" + JSON.stringify(responseAuth0));
  367. // mfc.writePage(0x29, [0x04, 0x00, 0x00, 0xFF])
  368. //js不支持无符号整数,无法传输大于0X7F的值
  369. mfc.writePage(0x29, [0x04, 0x00, 0x00, 0x7F])
  370. mfc.close();
  371. toast('清除密码成功!');
  372. return;
  373. } else {
  374. toast('Tag不支持MifareUltralight');
  375. return;
  376. }
  377. } catch (e) {
  378. toast('清除密码失败');
  379. console.log("清除密码失败 error=" + e);
  380. }
  381. },
  382. getState(intent) {
  383. try {
  384. toast('请勿移开标签 正在获取NFC状态...');
  385. let MifareUltralight = plus.android.importClass('android.nfc.tech.MifareUltralight');
  386. let tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  387. let mfc = MifareUltralight.get(tag);
  388. if (mfc != null) {
  389. mfc.connect();
  390. let responseAuth0 = mfc.readPages(0x29)
  391. console.log("responseAuth0=" + JSON.stringify(responseAuth0));
  392. if (responseAuth0[3] == 0x00) {
  393. toast('已设置密码保护');
  394. } else if (responseAuth0[3] == 0x7F || responseAuth0[3] == 0xFF || responseAuth0[3] == -1) {
  395. toast('尚未设置密码保护');
  396. } else {
  397. toast('NFC状态未知:' + JSON.stringify(responseAuth0));
  398. }
  399. mfc.close();
  400. return;
  401. } else {
  402. toast('Tag不支持MifareUltralight');
  403. return;
  404. }
  405. } catch (e) {
  406. toast('获取NFC状态失败');
  407. console.log("获取NFC状态失败 error=" + e);
  408. }
  409. },
  410. byteArrayToHexString: function(inarray) { // converts byte arrays to string
  411. let i, j, inn;
  412. let hex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
  413. let out = "";
  414. for (j = 0; j < inarray.length; ++j) {
  415. inn = inarray[j] & 0xff;
  416. i = (inn >>> 4) & 0x0f;
  417. out += hex[i];
  418. i = inn & 0x0f;
  419. out += hex[i];
  420. }
  421. return out;
  422. },
  423. writeData: function() {
  424. if (noNFC) {
  425. toast('请检查设备是否支持并开启 NFC 功能!');
  426. return;
  427. }
  428. // 监听事件,触发条件
  429. readyWriteData = true;
  430. toast('请将NFC标签靠近!');
  431. },
  432. readData: function() {
  433. if (noNFC) {
  434. toast('请检查设备是否支持并开启 NFC 功能!');
  435. return;
  436. }
  437. // 监听事件,触发条件
  438. readyRead = true;
  439. toast('请将NFC标签靠近!');
  440. },
  441. setPwdData: function() {
  442. if (noNFC) {
  443. toast('请检查设备是否支持并开启 NFC 功能!');S
  444. return;
  445. }
  446. // 监听事件,触发条件
  447. readySetPwd = true;
  448. toast('请将NFC标签靠近!');
  449. },
  450. delPwdData: function() {
  451. if (noNFC) {
  452. toast('请检查设备是否支持并开启 NFC 功能!');
  453. return;
  454. }
  455. // 监听事件,触发条件
  456. readyDelPwd = true;
  457. toast('请将NFC标签靠近!');
  458. },
  459. getNfcState: function() {
  460. if (noNFC) {
  461. toast('请检查设备是否支持并开启 NFC 功能!');
  462. return;
  463. }
  464. // 监听事件,触发条件
  465. readyGetNfcState = true;
  466. toast('请将NFC标签靠近!');
  467. },
  468. writeAndLock: function() {
  469. if (noNFC) {
  470. toast('请检查设备是否支持并开启 NFC 功能!');
  471. return;
  472. }
  473. // 监听事件,触发条件
  474. readyWriteAndLock = true;
  475. toast('请将NFC标签靠近!');
  476. },
  477. // 输入文本改变
  478. inputChanage: function(res) {
  479. console.log("正在编辑写入数据...", res)
  480. writeUri = res
  481. }
  482. }
  483. function toast(content) {
  484. uni.showToast({
  485. title: content,
  486. icon: 'none'
  487. })
  488. }