vite-uni-dev-tool 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/README.md +8 -0
  2. package/dist/const.cjs +1 -1
  3. package/dist/const.d.ts +1 -0
  4. package/dist/const.d.ts.map +1 -1
  5. package/dist/const.js +1 -1
  6. package/dist/core.d.ts.map +1 -1
  7. package/dist/core.js +2 -2
  8. package/dist/i18n/locales/en.cjs +1 -1
  9. package/dist/i18n/locales/en.d.ts +5 -0
  10. package/dist/i18n/locales/en.d.ts.map +1 -1
  11. package/dist/i18n/locales/en.js +1 -1
  12. package/dist/i18n/locales/zh-Hans.cjs +1 -1
  13. package/dist/i18n/locales/zh-Hans.d.ts +5 -0
  14. package/dist/i18n/locales/zh-Hans.d.ts.map +1 -1
  15. package/dist/i18n/locales/zh-Hans.js +1 -1
  16. package/dist/modules/devIntercept/index.cjs +9 -9
  17. package/dist/modules/devIntercept/index.d.ts +1 -1
  18. package/dist/modules/devIntercept/index.d.ts.map +1 -1
  19. package/dist/modules/devIntercept/index.js +9 -9
  20. package/dist/modules/devStore/index.cjs +1 -1
  21. package/dist/modules/devStore/index.d.ts.map +1 -1
  22. package/dist/modules/devStore/index.js +1 -1
  23. package/dist/plugins/uniDevTool/transform/transformMain.cjs +3 -3
  24. package/dist/plugins/uniDevTool/transform/transformMain.d.ts +2 -1
  25. package/dist/plugins/uniDevTool/transform/transformMain.d.ts.map +1 -1
  26. package/dist/plugins/uniDevTool/transform/transformMain.js +3 -3
  27. package/dist/plugins/uniDevTool/transform/transformVue.cjs +31 -25
  28. package/dist/plugins/uniDevTool/transform/transformVue.d.ts +2 -1
  29. package/dist/plugins/uniDevTool/transform/transformVue.d.ts.map +1 -1
  30. package/dist/plugins/uniDevTool/transform/transformVue.js +30 -24
  31. package/dist/plugins/uniDevTool/uniDevTool.cjs +3 -3
  32. package/dist/plugins/uniDevTool/uniDevTool.d.ts +3 -1
  33. package/dist/plugins/uniDevTool/uniDevTool.d.ts.map +1 -1
  34. package/dist/plugins/uniDevTool/uniDevTool.js +3 -3
  35. package/dist/type.d.ts +3 -0
  36. package/dist/type.d.ts.map +1 -1
  37. package/dist/v3/DevTool/components/BluetoothList/BluetoothItem.vue +199 -199
  38. package/dist/v3/DevTool/components/BluetoothList/BluetoothTool.vue +730 -730
  39. package/dist/v3/DevTool/components/BluetoothList/index.vue +167 -167
  40. package/dist/v3/DevTool/components/CaptureScreen/index.vue +109 -109
  41. package/dist/v3/DevTool/components/ConsoleList/ConsoleItem.vue +230 -225
  42. package/dist/v3/DevTool/components/ConsoleList/RunJSInput.vue +247 -247
  43. package/dist/v3/DevTool/components/ConsoleList/index.vue +171 -171
  44. package/dist/v3/DevTool/components/ConsoleList/staticTips.ts +1145 -1145
  45. package/dist/v3/DevTool/components/DevToolTitle/index.vue +24 -24
  46. package/dist/v3/DevTool/components/DevToolWindow/DevToolOverlay.vue +197 -197
  47. package/dist/v3/DevTool/components/DevToolWindow/hooks/dataUtils.ts +48 -48
  48. package/dist/v3/DevTool/components/DevToolWindow/hooks/useDevToolData.ts +387 -387
  49. package/dist/v3/DevTool/components/DevToolWindow/hooks/useDevToolHandlers.ts +629 -629
  50. package/dist/v3/DevTool/components/DevToolWindow/hooks/useDevToolOverlay.ts +201 -197
  51. package/dist/v3/DevTool/components/ElEvent/ElEventItem.vue +105 -105
  52. package/dist/v3/DevTool/components/ElEvent/index.vue +106 -106
  53. package/dist/v3/DevTool/components/Instance/components/InstanceTreeNode.vue +265 -265
  54. package/dist/v3/DevTool/components/Instance/flatten.ts +226 -226
  55. package/dist/v3/DevTool/components/Instance/index.vue +94 -94
  56. package/dist/v3/DevTool/components/Instance/registry.ts +49 -49
  57. package/dist/v3/DevTool/components/Instance/transformTree.ts +375 -375
  58. package/dist/v3/DevTool/components/Instance/transformTreeCtx.ts +268 -268
  59. package/dist/v3/DevTool/components/Instance/typing.d.ts +43 -43
  60. package/dist/v3/DevTool/components/InstanceDetail/index.vue +485 -485
  61. package/dist/v3/DevTool/components/JsonDetail/index.vue +70 -70
  62. package/dist/v3/DevTool/components/NFCList/NFCItem.vue +112 -112
  63. package/dist/v3/DevTool/components/NFCList/NFCTool.vue +454 -454
  64. package/dist/v3/DevTool/components/NFCList/const.ts +56 -56
  65. package/dist/v3/DevTool/components/NFCList/index.vue +94 -94
  66. package/dist/v3/DevTool/components/NetworkList/InterceptConfig.vue +624 -624
  67. package/dist/v3/DevTool/components/NetworkList/InterceptItem.vue +140 -140
  68. package/dist/v3/DevTool/components/NetworkList/NetworkDetail.vue +287 -287
  69. package/dist/v3/DevTool/components/NetworkList/NetworkIntercept.vue +88 -88
  70. package/dist/v3/DevTool/components/NetworkList/NetworkItem.vue +163 -163
  71. package/dist/v3/DevTool/components/NetworkList/NetworkSend.vue +589 -589
  72. package/dist/v3/DevTool/components/NetworkList/const.ts +4 -4
  73. package/dist/v3/DevTool/components/NetworkList/hooks/useNetworkForm.ts +86 -86
  74. package/dist/v3/DevTool/components/NetworkList/index.vue +160 -160
  75. package/dist/v3/DevTool/components/NetworkList/utils.ts +101 -101
  76. package/dist/v3/DevTool/components/Performance/index.vue +498 -498
  77. package/dist/v3/DevTool/components/Performance/modules/PerformanceMetrics.vue +153 -153
  78. package/dist/v3/DevTool/components/Performance/modules/usePerformanceChart.ts +460 -460
  79. package/dist/v3/DevTool/components/Performance/modules/usePerformanceData.ts +258 -258
  80. package/dist/v3/DevTool/components/PiniaList/index.vue +93 -93
  81. package/dist/v3/DevTool/components/RunJS/index.vue +148 -148
  82. package/dist/v3/DevTool/components/ScanCodeList/ScanCodeItem.vue +97 -97
  83. package/dist/v3/DevTool/components/ScanCodeList/index.vue +100 -100
  84. package/dist/v3/DevTool/components/SettingButton/index.vue +45 -45
  85. package/dist/v3/DevTool/components/SettingList/index.vue +218 -218
  86. package/dist/v3/DevTool/components/SettingList/modules/SettingBarrage.vue +304 -304
  87. package/dist/v3/DevTool/components/SettingList/modules/SettingDevTool.vue +212 -212
  88. package/dist/v3/DevTool/components/SettingList/modules/SettingInfo.vue +157 -157
  89. package/dist/v3/DevTool/components/SettingList/modules/SettingLanguage.vue +74 -74
  90. package/dist/v3/DevTool/components/SettingList/modules/SettingLog.vue +230 -230
  91. package/dist/v3/DevTool/components/SettingList/typing.d.ts +2 -2
  92. package/dist/v3/DevTool/components/SourceCode/Line.vue +127 -127
  93. package/dist/v3/DevTool/components/SourceCode/parseCode.ts +609 -609
  94. package/dist/v3/DevTool/components/StorageList/index.vue +174 -174
  95. package/dist/v3/DevTool/components/TransferList/TransferDetail.vue +268 -268
  96. package/dist/v3/DevTool/components/VuexList/index.vue +84 -84
  97. package/dist/v3/DevTool/index.vue +1 -0
  98. package/dist/v3/components/AppTransition/index.vue +176 -176
  99. package/dist/v3/components/AutoSizer/index.vue +192 -192
  100. package/dist/v3/components/AutoSizer/index1.vue +184 -184
  101. package/dist/v3/components/AutoSizer/utils.ts +49 -49
  102. package/dist/v3/components/Barrage/BarrageItem.vue +137 -137
  103. package/dist/v3/components/Barrage/index.vue +202 -202
  104. package/dist/v3/components/CircularButton/index.vue +84 -84
  105. package/dist/v3/components/CustomSwiper/CustomSwiperItem.vue +49 -49
  106. package/dist/v3/components/CustomSwiper/index.vue +104 -104
  107. package/dist/v3/components/DevErrorBoundary/index.vue +380 -0
  108. package/dist/v3/components/Empty/index.vue +29 -29
  109. package/dist/v3/components/FilterSelect/index.vue +179 -179
  110. package/dist/v3/components/JsonPretty/components/Brackets/index.vue +27 -27
  111. package/dist/v3/components/JsonPretty/components/Carets/index.vue +59 -59
  112. package/dist/v3/components/JsonPretty/components/CheckController/index.vue +136 -136
  113. package/dist/v3/components/JsonPretty/components/TreeNode/index.vue +387 -387
  114. package/dist/v3/components/JsonPretty/hooks/useClipboard.ts +21 -21
  115. package/dist/v3/components/JsonPretty/hooks/useError.ts +21 -21
  116. package/dist/v3/components/JsonPretty/type.ts +127 -127
  117. package/dist/v3/components/JsonPretty/utils/index.ts +169 -169
  118. package/dist/v3/components/MovableContainer/index.vue +8 -4
  119. package/dist/v3/components/Pick/index.vue +322 -322
  120. package/dist/v3/components/Tag/index.vue +113 -113
  121. package/dist/v3/components/VirtualList/AutoSize.vue +40 -40
  122. package/dist/v3/components/VirtualList/index.vue +416 -416
  123. package/dist/v3/hooks/useBluetooth/index.ts +561 -561
  124. package/dist/v3/hooks/useContainerStyle.ts +153 -153
  125. package/dist/v3/hooks/useNFC/index.ts +107 -107
  126. package/dist/v3/hooks/useNFC/typing.d.ts +396 -396
  127. package/dist/v3/hooks/useNFC/useNFCAndroid.ts +966 -966
  128. package/dist/v3/hooks/useNFC/useNFCMpWeiXin.ts +812 -812
  129. package/dist/v3/hooks/useNFC/utils.ts +754 -754
  130. package/dist/v3/hooks/useRequest/index.ts +586 -586
  131. package/dist/v3/hooks/useRequest/utils.ts +267 -267
  132. package/dist/v3/hooks/useScanCode/index.ts +206 -206
  133. package/dist/v3/hooks/useWebsocket/index.ts +253 -253
  134. package/dist/v3/styles/theme.ts +12 -12
  135. package/package.json +9 -1
@@ -1,812 +1,812 @@
1
- import { onMounted, onUnmounted, ref } from 'vue';
2
- import {
3
- arrayNumberToArrayBuffer,
4
- byteToString,
5
- createUriNdefRecord,
6
- formatCardInfo,
7
- generateWSCBytesForAndroid,
8
- getReadWriteStandard,
9
- getSakHex,
10
- getSakType,
11
- getTnfDescription,
12
- getTypeDescription,
13
- parseAtqa,
14
- parseUniversalTLV,
15
- parseVCardPayload,
16
- stringToArrayBuffer,
17
- transformArrayBuffer,
18
- wifiTLVConfig,
19
- } from './utils';
20
-
21
- export default function useNFCMpWeiXin(
22
- listener: NFC.Listener,
23
- _options?: NFC.NfcOption,
24
- ): NFC.NfcResult {
25
- /** 是否支持 nfc */
26
- const isSupportNFC = ref<boolean | undefined>(false);
27
- /** 是否监听中 */
28
- const isListening = ref<boolean>(false);
29
- /**
30
- * 是否已连接
31
- * 需要手动维护,调用connect()后连接 调用close()后断开 ,实际nfc 断开之后是无法监听到的, isConnected 已经被废弃掉了
32
- */
33
- const isConnected = ref<boolean>(false);
34
- /** nfc 数据 */
35
- const data = ref<NFC.Result>({
36
- id: new ArrayBuffer(0),
37
- techs: [],
38
- byteArray: [],
39
- hexArray: [],
40
- hexNumberArray: [],
41
- hexString: '',
42
- });
43
-
44
- /** nfc 适配器 */
45
- let nfcAdapter: NFC.Adapter;
46
-
47
- /** nfc 实例 */
48
- let nfcInstance: NFC.Instance | undefined;
49
-
50
- /** ndef 写入方式比较特殊,需要特殊处理 */
51
- const isNdef = ref(false);
52
-
53
- let maxTransceiveLength = 0;
54
-
55
- const _checkInterval: any = null;
56
-
57
- /**
58
- * 初始化 nfc adapter
59
- *
60
- * @return {*}
61
- */
62
- async function initNfcAdapter() {
63
- await checkHCEState();
64
-
65
- if (!isSupportNFC.value) return;
66
-
67
- nfcAdapter = wx.getNFCAdapter();
68
-
69
- nfcAdapter.onDiscovered(innerListener);
70
- }
71
-
72
- function getAtqa(nfcInstance: NFC.Instance): Promise<NFC.Atqa> {
73
- return new Promise((resolve, reject) => {
74
- if (!nfcInstance.getAtqa) {
75
- reject({ errMsg: '不支持获取 atqa' });
76
- }
77
- nfcInstance?.getAtqa?.({
78
- success: (res) => {
79
- resolve(res);
80
- },
81
- fail: (err) => {
82
- reject(err);
83
- },
84
- });
85
- });
86
- }
87
-
88
- function getMaxTransceiveLength(
89
- nfcInstance: NFC.Instance,
90
- ): Promise<NFC.MaxTransceiveLength> {
91
- return new Promise((resolve, reject) => {
92
- if (nfcInstance.getMaxTransceiveLength) {
93
- nfcInstance?.getMaxTransceiveLength?.({
94
- success: (res) => {
95
- resolve(res);
96
- },
97
- fail: (err) => {
98
- reject(err);
99
- },
100
- });
101
- } else {
102
- reject({ errMsg: '不支持获取 maxTransceiveLength' });
103
- }
104
- });
105
- }
106
-
107
- function getSak(nfcInstance: NFC.Instance): Promise<NFC.Sak> {
108
- return new Promise((resolve, reject) => {
109
- if (!nfcInstance.getMaxTransceiveLength) {
110
- reject({ errMsg: '不支持获取 sak' });
111
- }
112
-
113
- nfcInstance?.getSak?.({
114
- success: (res) => {
115
- resolve(res);
116
- },
117
- fail: (err) => {
118
- reject(err);
119
- },
120
- });
121
- });
122
- }
123
-
124
- /**
125
- * 检查HCE状态
126
- *
127
- * @return {*}
128
- */
129
- function checkHCEState() {
130
- return new Promise((resolve, reject) => {
131
- wx.getHCEState({
132
- success: (res: any) => {
133
- isSupportNFC.value = true;
134
- resolve(res);
135
- },
136
- fail: (err: any) => {
137
- isSupportNFC.value = false;
138
- reject(err);
139
- },
140
- });
141
- });
142
- }
143
-
144
- /**
145
- * 启用HCE
146
- *
147
- * @return {*}
148
- */
149
- function startHCE() {
150
- if (!isSupportNFC.value) {
151
- uni.showToast({
152
- title: '设备不支持 NFC',
153
- icon: 'none',
154
- });
155
- return Promise.reject({
156
- errMsg: '设备不支持 NFC',
157
- });
158
- }
159
-
160
- // 前置校验
161
- if (!nfcAdapter) {
162
- uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
163
- return Promise.reject({
164
- errMsg: '请先初始化 NFC 适配器',
165
- });
166
- }
167
-
168
- if (isListening.value) {
169
- uni.showToast({ title: 'NFC 监听已开启,无需重复操作', icon: 'none' });
170
- return Promise.reject({
171
- errMsg: 'NFC 监听已开启,无需重复操作',
172
- });
173
- }
174
- nfcAdapter.startDiscovery();
175
- isListening.value = true;
176
- uni.showToast({
177
- title: '开始监听NFC',
178
- icon: 'none',
179
- });
180
- return Promise.resolve({
181
- errMsg: '开始监听NFC',
182
- });
183
- }
184
-
185
- /**
186
- * 停用HCE
187
- *
188
- * @return {*}
189
- */
190
- function stopHCE() {
191
- // 前置校验
192
- if (!isSupportNFC.value) {
193
- uni.showToast({
194
- title: '设备不支持 NFC',
195
- icon: 'none',
196
- });
197
- return Promise.reject({
198
- errMsg: '设备不支持 NFC',
199
- });
200
- }
201
-
202
- // 前置校验
203
- if (!nfcAdapter) {
204
- uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
205
- return Promise.reject({
206
- errMsg: '请先初始化 NFC 适配器',
207
- });
208
- }
209
-
210
- if (!isListening.value) {
211
- uni.showToast({ title: 'NFC 监听已关闭,无需重复操作', icon: 'none' });
212
- return Promise.reject({
213
- errMsg: 'NFC 监听已关闭,无需重复操作',
214
- });
215
- }
216
-
217
- nfcAdapter.stopDiscovery();
218
- isListening.value = false;
219
- uni.showToast({
220
- title: '停止监听NFC',
221
- icon: 'none',
222
- });
223
- return Promise.resolve({
224
- errMsg: '停止监听NFC',
225
- });
226
- }
227
-
228
- function getInstance(techs: NFC.NfcType[], needNdef?: boolean) {
229
- let type = 'Ndef';
230
- if (needNdef) {
231
- type = 'Ndef';
232
- } else {
233
- type = techs.filter((tech) => tech != 'Ndef' && tech != 'NDEF')?.[0];
234
- }
235
-
236
- switch (type) {
237
- case 'NFC-A':
238
- return nfcAdapter.getNfcA();
239
- case 'NFC-B':
240
- return nfcAdapter.getNfcB();
241
- case 'NFC-F':
242
- return nfcAdapter.getNfcF();
243
- case 'NFC-V':
244
- return nfcAdapter.getNfcV();
245
- case 'MIFARE Classic':
246
- return nfcAdapter.getMifareClassic();
247
- case 'MIFARE Ultralight':
248
- return nfcAdapter.getMifareUltralight();
249
- case 'Ndef':
250
- isNdef.value = true;
251
- return nfcAdapter.getNdef();
252
- case 'ISO-DEP':
253
- return nfcAdapter.getIsoDep();
254
- default:
255
- return undefined;
256
- }
257
- }
258
-
259
- // function checkConnected() {
260
- // checkInterval = setInterval(async () => {
261
- // if (!nfcAdapter) {
262
- // isConnected.value = false;
263
- // clearInterval(checkInterval);
264
- // return;
265
- // }
266
-
267
- // if (!nfcInstance) {
268
- // isConnected.value = false;
269
- // clearInterval(checkInterval);
270
- // return;
271
- // }
272
- // try {
273
- // // TODO: 检测是否连接成功
274
- // // await connect();
275
-
276
- // isConnected.value = true;
277
- // } catch (error) {
278
- // console.log('error: ', error);
279
- // isConnected.value = false;
280
- // clearInterval(checkInterval);
281
- // }
282
- // }, options?.checkConnectedDelay ?? 500);
283
- // }
284
-
285
- /**
286
- * 读取监听
287
- *
288
- * @param {*} res
289
- */
290
- async function innerListener(res: NFC.Data) {
291
- const transform = transformArrayBuffer(res?.id);
292
-
293
- nfcInstance = getInstance(res.techs, true);
294
-
295
- if (res.techs.includes('NFC-A')) {
296
- const nfcA = nfcAdapter.getNfcA();
297
- try {
298
- const atqa = await getAtqa(nfcA);
299
- const atqaInfo = parseAtqa(atqa.atqa);
300
- data.value.atqa = atqa.atqa;
301
- data.value.uidType = atqaInfo?.uidType;
302
- data.value.storageSize = atqaInfo?.storageSize;
303
- data.value.manufacturer = atqaInfo?.manufacturer;
304
- data.value.cardFeatures = atqaInfo?.cardFeatures;
305
- data.value.reserved = atqaInfo?.reserved;
306
- } catch (_error) {
307
- // ignore error
308
- }
309
-
310
- try {
311
- const sak = await getSak(nfcA);
312
- const sakType = getSakType(sak.sak);
313
- const sakHex = getSakHex(sak.sak);
314
- data.value.sak = sak.sak;
315
- data.value.sakType = sakType;
316
- data.value.sakHex = sakHex;
317
- } catch (_error) {
318
- // ignore error
319
- }
320
- }
321
-
322
- if (nfcInstance) {
323
- await connect();
324
-
325
- data.value.readWriteStandard = getReadWriteStandard(res.techs);
326
- if (!isNdef.value) {
327
- const maxTransceive = await getMaxTransceiveLength(nfcInstance);
328
- maxTransceiveLength = maxTransceive.length;
329
- data.value.maxTransceiveLength = maxTransceiveLength;
330
- } else {
331
- const otherInstance = getInstance(res.techs);
332
- const maxTransceive = await getMaxTransceiveLength(otherInstance);
333
- maxTransceiveLength = maxTransceive.length;
334
- data.value.maxTransceiveLength = maxTransceiveLength;
335
- }
336
-
337
- const messages =
338
- res.messages?.map((message) => {
339
- const records = message.records.map((item) => {
340
- const typeByte = transformArrayBuffer(
341
- item.type as any as ArrayBuffer,
342
- ).byteArray;
343
- const type = byteToString(typeByte);
344
-
345
- const idByte = transformArrayBuffer(
346
- item.id as any as ArrayBuffer,
347
- ).byteArray;
348
- const id = byteToString(idByte);
349
- const tnf = item.tnf?.toString() as NFC.Tnf;
350
-
351
- const payloadByte = transformArrayBuffer(
352
- item.payload as any as ArrayBuffer,
353
- ).byteArray;
354
-
355
- const typeDescription = getTypeDescription(type, payloadByte);
356
-
357
- let payload: any = byteToString(payloadByte);
358
- if (type === 'application/vnd.wfa.wsc') {
359
- payload = parseUniversalTLV(payloadByte, wifiTLVConfig);
360
- } else if (type === 'text/vcard') {
361
- payload = parseVCardPayload(payload);
362
- }
363
-
364
- return {
365
- id,
366
- tnf,
367
- tnfDescription: getTnfDescription(tnf),
368
- type,
369
- typeDescription,
370
- payload,
371
- };
372
- });
373
-
374
- return {
375
- ...message,
376
- records,
377
- };
378
- }) ?? [];
379
-
380
- data.value = {
381
- ...data.value,
382
- ...res,
383
- ...transform,
384
- messages,
385
- };
386
-
387
- isConnected.value = true;
388
-
389
- listener?.(data.value);
390
- // checkConnected();
391
- // 可将该行去除
392
- uni?.__dev_tool_nfc_collection__?.(data.value);
393
- }
394
- }
395
-
396
- /**
397
- * 移除监听读取消息
398
- *
399
- * @return {*}
400
- */
401
- function offHCEMessage() {
402
- if (!isSupportNFC.value) {
403
- uni.showToast({ title: '设备不支持 NFC,无需移除监听', icon: 'none' });
404
- return { errMsg: 'success' };
405
- }
406
- isConnected.value = false;
407
- nfcAdapter.offDiscovered(innerListener);
408
-
409
- uni.showToast({ title: 'NFC 监听已移除', icon: 'none' });
410
- return { errMsg: 'success' };
411
- }
412
-
413
- /**
414
- * 连接 nfc
415
- *
416
- * @return {*}
417
- */
418
- function connect(): Promise<{ errMsg: string }> {
419
- return new Promise((resolve, reject) => {
420
- if (!isSupportNFC.value) {
421
- uni.showToast({ title: '设备不支持 NFC', icon: 'none' });
422
- reject({
423
- errMsg: '设备不支持 NFC',
424
- });
425
- }
426
-
427
- if (!isListening.value) {
428
- uni.showToast({ title: '请先开启前台调度监听', icon: 'none' });
429
- reject({
430
- errMsg: '请先开启前台调度监听',
431
- });
432
- }
433
-
434
- if (!nfcInstance) {
435
- uni.showToast({ title: '请先靠近 NFC 标签', icon: 'none' });
436
- reject({
437
- errMsg: '请先靠近 NFC 标签',
438
- });
439
- }
440
-
441
- nfcInstance?.connect?.({
442
- success: (res) => {
443
- resolve(res);
444
- isConnected.value = true;
445
- uni.showToast({
446
- title: 'NFC 连接成功',
447
- icon: 'none',
448
- });
449
- resolve({
450
- errMsg: 'NFC 连接成功',
451
- });
452
- },
453
- fail: (err) => {
454
- if (err.errMsg === 'connect:fail:Tech already connected') {
455
- resolve(err);
456
- isConnected.value = true;
457
- } else {
458
- reject(err);
459
- isConnected.value = false;
460
- nfcInstance = undefined;
461
- uni.showToast({
462
- title: 'NFC 连接失败',
463
- icon: 'none',
464
- });
465
- }
466
- },
467
- });
468
- });
469
- }
470
-
471
- /**
472
- * 断开 nfc
473
- *
474
- * @return {*}
475
- */
476
- function close(): Promise<{ errMsg: string }> {
477
- return new Promise((resolve, reject) => {
478
- if (!isSupportNFC.value) {
479
- reject({
480
- errMsg: '不支持NFC',
481
- });
482
- }
483
-
484
- if (!nfcInstance) {
485
- reject({
486
- errMsg: '未读取到NFC卡',
487
- });
488
- }
489
-
490
- nfcInstance?.close?.({
491
- success: (_res) => {
492
- isConnected.value = false;
493
- nfcInstance = undefined;
494
- resolve({
495
- errMsg: 'NFC 断开成功',
496
- });
497
-
498
- uni.showToast({ title: 'NFC 连接已关闭', icon: 'none' });
499
- },
500
- fail: (err) => {
501
- reject(err);
502
- uni.showToast({ title: 'NFC 连接关闭失败', icon: 'none' });
503
- },
504
- });
505
- });
506
- }
507
-
508
- async function transceive(data: ArrayBuffer) {
509
- return new Promise((resolve, reject) => {
510
- if (!isSupportNFC.value) {
511
- reject({
512
- errMsg: '不支持NFC',
513
- });
514
- return;
515
- }
516
-
517
- if (!nfcInstance) {
518
- reject({
519
- errMsg: '未读取到NFC卡',
520
- });
521
- return;
522
- }
523
- nfcInstance?.transceive?.({
524
- data,
525
- success: (res) => {
526
- resolve(res);
527
- },
528
- fail: (err) => {
529
- reject(err);
530
- },
531
- });
532
- });
533
- }
534
-
535
- async function writeNdefMessage(data: NFC.NdefData) {
536
- return new Promise((resolve, reject) => {
537
- if (!isSupportNFC.value) {
538
- reject({
539
- errMsg: '不支持NFC',
540
- });
541
- } else if (!nfcInstance) {
542
- reject({
543
- errMsg: '未读取到NFC卡',
544
- });
545
- } else {
546
- nfcInstance?.writeNdefMessage?.({
547
- ...data,
548
- success: (res) => {
549
- resolve(res);
550
- },
551
- fail: (err) => {
552
- reject(err);
553
- },
554
- });
555
- }
556
- });
557
- }
558
-
559
- /**
560
- * 写入数据
561
- *
562
- * 支持以以下类型
563
- * ISO-DEP
564
- * MIFARE Classic
565
- * MIFARE Ultralight
566
- * NFC-A
567
- * NFC-B
568
- * NFC-F
569
- * NFC-V
570
- *
571
- * @param {*} data
572
- * @return {*}
573
- */
574
- async function write(data: ArrayBuffer) {
575
- try {
576
- // 连接 nfc
577
- await connect();
578
- uni.showToast({
579
- title: '开始写入数据, 请勿断开连接',
580
- icon: 'none',
581
- });
582
- // 写入数据
583
-
584
- const result = await transceive(data);
585
-
586
- uni.showToast({
587
- title: '数据写入成功',
588
- icon: 'none',
589
- });
590
- // 断开 nfc
591
- await close();
592
- return Promise.resolve({
593
- errMsg: '数据写入成功',
594
- data: result,
595
- });
596
- } catch (error) {
597
- return Promise.reject({
598
- errMsg: '数据写入失败',
599
- error,
600
- });
601
- }
602
- }
603
-
604
- /**
605
- * 写入数据
606
- * 支持以以下类型
607
- * Ndef
608
- *
609
- * @param {NFC.NdefData} data
610
- */
611
- async function writeNdef(data: NFC.NdefRecord[]) {
612
- if (!isNdef.value) {
613
- uni.showToast({
614
- title: 'NFC 标签不支持 NDEF',
615
- icon: 'none',
616
- });
617
- return Promise.reject({
618
- errMsg: 'NFC 标签不支持 NDEF',
619
- });
620
- }
621
-
622
- if (!nfcInstance) {
623
- uni.showToast({
624
- title: '请先建立连接',
625
- icon: 'none',
626
- });
627
- return Promise.reject({
628
- errMsg: '请先建立连接',
629
- });
630
- }
631
-
632
- if (!isConnected.value) {
633
- uni.showToast({
634
- title: '请先建立连接',
635
- icon: 'none',
636
- });
637
- return Promise.reject({
638
- errMsg: '请先建立连接',
639
- });
640
- }
641
-
642
- uni.showToast({
643
- title: '开始写入数据,请勿断开连接',
644
- icon: 'none',
645
- duration: 3000,
646
- });
647
-
648
- try {
649
- const records = data?.map((item) => {
650
- // const tnf = stringToArrayBuffer(item.tnf);
651
- const id = item.id ? stringToArrayBuffer(item.id) : new ArrayBuffer(0);
652
- const type = stringToArrayBuffer(item.type);
653
-
654
- return {
655
- tnf: item.tnf,
656
- type,
657
- id,
658
- payload: item.payload,
659
- };
660
- });
661
-
662
- if (maxTransceiveLength && maxTransceiveLength < records.length) {
663
- uni.showToast({
664
- title: '写入数据超出标签容量',
665
- icon: 'none',
666
- duration: 3000,
667
- });
668
- nfcInstance.close();
669
-
670
- return Promise.reject({
671
- errMsg: '写入数据超出标签容量',
672
- });
673
- }
674
-
675
- // 连接 nfc
676
- await connect();
677
- uni.showToast({
678
- title: '开始写入数据, 请勿断开连接',
679
- icon: 'none',
680
- });
681
- // 写入数据
682
-
683
- const result = await writeNdefMessage({
684
- records,
685
- });
686
-
687
- await close();
688
- uni.showToast({
689
- title: '数据写入成功',
690
- icon: 'none',
691
- duration: 3000,
692
- });
693
- return Promise.resolve({
694
- errMsg: '数据写入成功',
695
- data: result,
696
- });
697
- } catch (error) {
698
- uni.showToast({
699
- title: '数据写入失败',
700
- icon: 'none',
701
- duration: 3000,
702
- });
703
-
704
- return Promise.reject({
705
- errMsg: '数据写入失败',
706
- error,
707
- });
708
- }
709
- }
710
-
711
- /**
712
- *
713
- *
714
- * @param {string} text
715
- * @param {string} [language='zh'] 微信小程序下无效
716
- * @return {*}
717
- */
718
- async function writeNdefText(
719
- text: string,
720
- _language = 'zh',
721
- ): Promise<{ errMsg: string }> {
722
- return writeNdef([
723
- {
724
- tnf: 1,
725
- type: 'T',
726
- payload: stringToArrayBuffer(text),
727
- },
728
- ]);
729
- }
730
-
731
- function writeNdefUri(uri: string): Promise<{ errMsg: string }> {
732
- const record = createUriNdefRecord(uri);
733
- return writeNdef([record]);
734
- }
735
-
736
- function writeNdefAndroidApp(
737
- packageName: string,
738
- ): Promise<{ errMsg: string }> {
739
- return writeNdef([
740
- {
741
- tnf: 4,
742
- type: 'android.com:pkg',
743
- payload: stringToArrayBuffer(packageName),
744
- },
745
- ]);
746
- }
747
-
748
- function writeNdefWifi({
749
- ssid,
750
- password,
751
- authType,
752
- }: NFC.WSCConfig): Promise<{ errMsg: string }> {
753
- const mimeType = 'application/vnd.wfa.wsc';
754
- const wifiData = generateWSCBytesForAndroid({
755
- ssid,
756
- password,
757
- authType,
758
- });
759
- return writeNdef([
760
- {
761
- tnf: 2,
762
- type: mimeType,
763
- payload: arrayNumberToArrayBuffer(wifiData),
764
- },
765
- ]);
766
- }
767
-
768
- function writeNdefVcard(
769
- cardInfo: NFC.VCardContactInfo,
770
- ): Promise<{ errMsg: string }> {
771
- const mimeType = 'text/vcard';
772
- const cardString = formatCardInfo(cardInfo);
773
-
774
- const cardData = stringToArrayBuffer(cardString);
775
- return writeNdef([
776
- {
777
- tnf: 2,
778
- type: mimeType,
779
- payload: cardData,
780
- },
781
- ]);
782
- }
783
-
784
- onMounted(() => {
785
- initNfcAdapter();
786
- });
787
-
788
- onUnmounted(() => {
789
- stopHCE();
790
- offHCEMessage();
791
- });
792
-
793
- return {
794
- data,
795
- isNdef,
796
- isSupportNFC,
797
- isListening,
798
- isConnected,
799
- nfcInstance,
800
- startHCE,
801
- stopHCE,
802
- connect,
803
- close,
804
- write,
805
- writeNdef,
806
- writeNdefText,
807
- writeNdefUri,
808
- writeNdefAndroidApp,
809
- writeNdefWifi,
810
- writeNdefVcard,
811
- };
812
- }
1
+ import { onMounted, onUnmounted, ref } from 'vue';
2
+ import {
3
+ arrayNumberToArrayBuffer,
4
+ byteToString,
5
+ createUriNdefRecord,
6
+ formatCardInfo,
7
+ generateWSCBytesForAndroid,
8
+ getReadWriteStandard,
9
+ getSakHex,
10
+ getSakType,
11
+ getTnfDescription,
12
+ getTypeDescription,
13
+ parseAtqa,
14
+ parseUniversalTLV,
15
+ parseVCardPayload,
16
+ stringToArrayBuffer,
17
+ transformArrayBuffer,
18
+ wifiTLVConfig,
19
+ } from './utils';
20
+
21
+ export default function useNFCMpWeiXin(
22
+ listener: NFC.Listener,
23
+ _options?: NFC.NfcOption,
24
+ ): NFC.NfcResult {
25
+ /** 是否支持 nfc */
26
+ const isSupportNFC = ref<boolean | undefined>(false);
27
+ /** 是否监听中 */
28
+ const isListening = ref<boolean>(false);
29
+ /**
30
+ * 是否已连接
31
+ * 需要手动维护,调用connect()后连接 调用close()后断开 ,实际nfc 断开之后是无法监听到的, isConnected 已经被废弃掉了
32
+ */
33
+ const isConnected = ref<boolean>(false);
34
+ /** nfc 数据 */
35
+ const data = ref<NFC.Result>({
36
+ id: new ArrayBuffer(0),
37
+ techs: [],
38
+ byteArray: [],
39
+ hexArray: [],
40
+ hexNumberArray: [],
41
+ hexString: '',
42
+ });
43
+
44
+ /** nfc 适配器 */
45
+ let nfcAdapter: NFC.Adapter;
46
+
47
+ /** nfc 实例 */
48
+ let nfcInstance: NFC.Instance | undefined;
49
+
50
+ /** ndef 写入方式比较特殊,需要特殊处理 */
51
+ const isNdef = ref(false);
52
+
53
+ let maxTransceiveLength = 0;
54
+
55
+ const _checkInterval: any = null;
56
+
57
+ /**
58
+ * 初始化 nfc adapter
59
+ *
60
+ * @return {*}
61
+ */
62
+ async function initNfcAdapter() {
63
+ await checkHCEState();
64
+
65
+ if (!isSupportNFC.value) return;
66
+
67
+ nfcAdapter = wx.getNFCAdapter();
68
+
69
+ nfcAdapter.onDiscovered(innerListener);
70
+ }
71
+
72
+ function getAtqa(nfcInstance: NFC.Instance): Promise<NFC.Atqa> {
73
+ return new Promise((resolve, reject) => {
74
+ if (!nfcInstance.getAtqa) {
75
+ reject({ errMsg: '不支持获取 atqa' });
76
+ }
77
+ nfcInstance?.getAtqa?.({
78
+ success: (res) => {
79
+ resolve(res);
80
+ },
81
+ fail: (err) => {
82
+ reject(err);
83
+ },
84
+ });
85
+ });
86
+ }
87
+
88
+ function getMaxTransceiveLength(
89
+ nfcInstance: NFC.Instance,
90
+ ): Promise<NFC.MaxTransceiveLength> {
91
+ return new Promise((resolve, reject) => {
92
+ if (nfcInstance.getMaxTransceiveLength) {
93
+ nfcInstance?.getMaxTransceiveLength?.({
94
+ success: (res) => {
95
+ resolve(res);
96
+ },
97
+ fail: (err) => {
98
+ reject(err);
99
+ },
100
+ });
101
+ } else {
102
+ reject({ errMsg: '不支持获取 maxTransceiveLength' });
103
+ }
104
+ });
105
+ }
106
+
107
+ function getSak(nfcInstance: NFC.Instance): Promise<NFC.Sak> {
108
+ return new Promise((resolve, reject) => {
109
+ if (!nfcInstance.getMaxTransceiveLength) {
110
+ reject({ errMsg: '不支持获取 sak' });
111
+ }
112
+
113
+ nfcInstance?.getSak?.({
114
+ success: (res) => {
115
+ resolve(res);
116
+ },
117
+ fail: (err) => {
118
+ reject(err);
119
+ },
120
+ });
121
+ });
122
+ }
123
+
124
+ /**
125
+ * 检查HCE状态
126
+ *
127
+ * @return {*}
128
+ */
129
+ function checkHCEState() {
130
+ return new Promise((resolve, reject) => {
131
+ wx.getHCEState({
132
+ success: (res: any) => {
133
+ isSupportNFC.value = true;
134
+ resolve(res);
135
+ },
136
+ fail: (err: any) => {
137
+ isSupportNFC.value = false;
138
+ reject(err);
139
+ },
140
+ });
141
+ });
142
+ }
143
+
144
+ /**
145
+ * 启用HCE
146
+ *
147
+ * @return {*}
148
+ */
149
+ function startHCE() {
150
+ if (!isSupportNFC.value) {
151
+ uni.showToast({
152
+ title: '设备不支持 NFC',
153
+ icon: 'none',
154
+ });
155
+ return Promise.reject({
156
+ errMsg: '设备不支持 NFC',
157
+ });
158
+ }
159
+
160
+ // 前置校验
161
+ if (!nfcAdapter) {
162
+ uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
163
+ return Promise.reject({
164
+ errMsg: '请先初始化 NFC 适配器',
165
+ });
166
+ }
167
+
168
+ if (isListening.value) {
169
+ uni.showToast({ title: 'NFC 监听已开启,无需重复操作', icon: 'none' });
170
+ return Promise.reject({
171
+ errMsg: 'NFC 监听已开启,无需重复操作',
172
+ });
173
+ }
174
+ nfcAdapter.startDiscovery();
175
+ isListening.value = true;
176
+ uni.showToast({
177
+ title: '开始监听NFC',
178
+ icon: 'none',
179
+ });
180
+ return Promise.resolve({
181
+ errMsg: '开始监听NFC',
182
+ });
183
+ }
184
+
185
+ /**
186
+ * 停用HCE
187
+ *
188
+ * @return {*}
189
+ */
190
+ function stopHCE() {
191
+ // 前置校验
192
+ if (!isSupportNFC.value) {
193
+ uni.showToast({
194
+ title: '设备不支持 NFC',
195
+ icon: 'none',
196
+ });
197
+ return Promise.reject({
198
+ errMsg: '设备不支持 NFC',
199
+ });
200
+ }
201
+
202
+ // 前置校验
203
+ if (!nfcAdapter) {
204
+ uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
205
+ return Promise.reject({
206
+ errMsg: '请先初始化 NFC 适配器',
207
+ });
208
+ }
209
+
210
+ if (!isListening.value) {
211
+ uni.showToast({ title: 'NFC 监听已关闭,无需重复操作', icon: 'none' });
212
+ return Promise.reject({
213
+ errMsg: 'NFC 监听已关闭,无需重复操作',
214
+ });
215
+ }
216
+
217
+ nfcAdapter.stopDiscovery();
218
+ isListening.value = false;
219
+ uni.showToast({
220
+ title: '停止监听NFC',
221
+ icon: 'none',
222
+ });
223
+ return Promise.resolve({
224
+ errMsg: '停止监听NFC',
225
+ });
226
+ }
227
+
228
+ function getInstance(techs: NFC.NfcType[], needNdef?: boolean) {
229
+ let type = 'Ndef';
230
+ if (needNdef) {
231
+ type = 'Ndef';
232
+ } else {
233
+ type = techs.filter((tech) => tech != 'Ndef' && tech != 'NDEF')?.[0];
234
+ }
235
+
236
+ switch (type) {
237
+ case 'NFC-A':
238
+ return nfcAdapter.getNfcA();
239
+ case 'NFC-B':
240
+ return nfcAdapter.getNfcB();
241
+ case 'NFC-F':
242
+ return nfcAdapter.getNfcF();
243
+ case 'NFC-V':
244
+ return nfcAdapter.getNfcV();
245
+ case 'MIFARE Classic':
246
+ return nfcAdapter.getMifareClassic();
247
+ case 'MIFARE Ultralight':
248
+ return nfcAdapter.getMifareUltralight();
249
+ case 'Ndef':
250
+ isNdef.value = true;
251
+ return nfcAdapter.getNdef();
252
+ case 'ISO-DEP':
253
+ return nfcAdapter.getIsoDep();
254
+ default:
255
+ return undefined;
256
+ }
257
+ }
258
+
259
+ // function checkConnected() {
260
+ // checkInterval = setInterval(async () => {
261
+ // if (!nfcAdapter) {
262
+ // isConnected.value = false;
263
+ // clearInterval(checkInterval);
264
+ // return;
265
+ // }
266
+
267
+ // if (!nfcInstance) {
268
+ // isConnected.value = false;
269
+ // clearInterval(checkInterval);
270
+ // return;
271
+ // }
272
+ // try {
273
+ // // TODO: 检测是否连接成功
274
+ // // await connect();
275
+
276
+ // isConnected.value = true;
277
+ // } catch (error) {
278
+ // console.log('error: ', error);
279
+ // isConnected.value = false;
280
+ // clearInterval(checkInterval);
281
+ // }
282
+ // }, options?.checkConnectedDelay ?? 500);
283
+ // }
284
+
285
+ /**
286
+ * 读取监听
287
+ *
288
+ * @param {*} res
289
+ */
290
+ async function innerListener(res: NFC.Data) {
291
+ const transform = transformArrayBuffer(res?.id);
292
+
293
+ nfcInstance = getInstance(res.techs, true);
294
+
295
+ if (res.techs.includes('NFC-A')) {
296
+ const nfcA = nfcAdapter.getNfcA();
297
+ try {
298
+ const atqa = await getAtqa(nfcA);
299
+ const atqaInfo = parseAtqa(atqa.atqa);
300
+ data.value.atqa = atqa.atqa;
301
+ data.value.uidType = atqaInfo?.uidType;
302
+ data.value.storageSize = atqaInfo?.storageSize;
303
+ data.value.manufacturer = atqaInfo?.manufacturer;
304
+ data.value.cardFeatures = atqaInfo?.cardFeatures;
305
+ data.value.reserved = atqaInfo?.reserved;
306
+ } catch (_error) {
307
+ // ignore error
308
+ }
309
+
310
+ try {
311
+ const sak = await getSak(nfcA);
312
+ const sakType = getSakType(sak.sak);
313
+ const sakHex = getSakHex(sak.sak);
314
+ data.value.sak = sak.sak;
315
+ data.value.sakType = sakType;
316
+ data.value.sakHex = sakHex;
317
+ } catch (_error) {
318
+ // ignore error
319
+ }
320
+ }
321
+
322
+ if (nfcInstance) {
323
+ await connect();
324
+
325
+ data.value.readWriteStandard = getReadWriteStandard(res.techs);
326
+ if (!isNdef.value) {
327
+ const maxTransceive = await getMaxTransceiveLength(nfcInstance);
328
+ maxTransceiveLength = maxTransceive.length;
329
+ data.value.maxTransceiveLength = maxTransceiveLength;
330
+ } else {
331
+ const otherInstance = getInstance(res.techs);
332
+ const maxTransceive = await getMaxTransceiveLength(otherInstance);
333
+ maxTransceiveLength = maxTransceive.length;
334
+ data.value.maxTransceiveLength = maxTransceiveLength;
335
+ }
336
+
337
+ const messages =
338
+ res.messages?.map((message) => {
339
+ const records = message.records.map((item) => {
340
+ const typeByte = transformArrayBuffer(
341
+ item.type as any as ArrayBuffer,
342
+ ).byteArray;
343
+ const type = byteToString(typeByte);
344
+
345
+ const idByte = transformArrayBuffer(
346
+ item.id as any as ArrayBuffer,
347
+ ).byteArray;
348
+ const id = byteToString(idByte);
349
+ const tnf = item.tnf?.toString() as NFC.Tnf;
350
+
351
+ const payloadByte = transformArrayBuffer(
352
+ item.payload as any as ArrayBuffer,
353
+ ).byteArray;
354
+
355
+ const typeDescription = getTypeDescription(type, payloadByte);
356
+
357
+ let payload: any = byteToString(payloadByte);
358
+ if (type === 'application/vnd.wfa.wsc') {
359
+ payload = parseUniversalTLV(payloadByte, wifiTLVConfig);
360
+ } else if (type === 'text/vcard') {
361
+ payload = parseVCardPayload(payload);
362
+ }
363
+
364
+ return {
365
+ id,
366
+ tnf,
367
+ tnfDescription: getTnfDescription(tnf),
368
+ type,
369
+ typeDescription,
370
+ payload,
371
+ };
372
+ });
373
+
374
+ return {
375
+ ...message,
376
+ records,
377
+ };
378
+ }) ?? [];
379
+
380
+ data.value = {
381
+ ...data.value,
382
+ ...res,
383
+ ...transform,
384
+ messages,
385
+ };
386
+
387
+ isConnected.value = true;
388
+
389
+ listener?.(data.value);
390
+ // checkConnected();
391
+ // 可将该行去除
392
+ uni?.__dev_tool_nfc_collection__?.(data.value);
393
+ }
394
+ }
395
+
396
+ /**
397
+ * 移除监听读取消息
398
+ *
399
+ * @return {*}
400
+ */
401
+ function offHCEMessage() {
402
+ if (!isSupportNFC.value) {
403
+ uni.showToast({ title: '设备不支持 NFC,无需移除监听', icon: 'none' });
404
+ return { errMsg: 'success' };
405
+ }
406
+ isConnected.value = false;
407
+ nfcAdapter.offDiscovered(innerListener);
408
+
409
+ uni.showToast({ title: 'NFC 监听已移除', icon: 'none' });
410
+ return { errMsg: 'success' };
411
+ }
412
+
413
+ /**
414
+ * 连接 nfc
415
+ *
416
+ * @return {*}
417
+ */
418
+ function connect(): Promise<{ errMsg: string }> {
419
+ return new Promise((resolve, reject) => {
420
+ if (!isSupportNFC.value) {
421
+ uni.showToast({ title: '设备不支持 NFC', icon: 'none' });
422
+ reject({
423
+ errMsg: '设备不支持 NFC',
424
+ });
425
+ }
426
+
427
+ if (!isListening.value) {
428
+ uni.showToast({ title: '请先开启前台调度监听', icon: 'none' });
429
+ reject({
430
+ errMsg: '请先开启前台调度监听',
431
+ });
432
+ }
433
+
434
+ if (!nfcInstance) {
435
+ uni.showToast({ title: '请先靠近 NFC 标签', icon: 'none' });
436
+ reject({
437
+ errMsg: '请先靠近 NFC 标签',
438
+ });
439
+ }
440
+
441
+ nfcInstance?.connect?.({
442
+ success: (res) => {
443
+ resolve(res);
444
+ isConnected.value = true;
445
+ uni.showToast({
446
+ title: 'NFC 连接成功',
447
+ icon: 'none',
448
+ });
449
+ resolve({
450
+ errMsg: 'NFC 连接成功',
451
+ });
452
+ },
453
+ fail: (err) => {
454
+ if (err.errMsg === 'connect:fail:Tech already connected') {
455
+ resolve(err);
456
+ isConnected.value = true;
457
+ } else {
458
+ reject(err);
459
+ isConnected.value = false;
460
+ nfcInstance = undefined;
461
+ uni.showToast({
462
+ title: 'NFC 连接失败',
463
+ icon: 'none',
464
+ });
465
+ }
466
+ },
467
+ });
468
+ });
469
+ }
470
+
471
+ /**
472
+ * 断开 nfc
473
+ *
474
+ * @return {*}
475
+ */
476
+ function close(): Promise<{ errMsg: string }> {
477
+ return new Promise((resolve, reject) => {
478
+ if (!isSupportNFC.value) {
479
+ reject({
480
+ errMsg: '不支持NFC',
481
+ });
482
+ }
483
+
484
+ if (!nfcInstance) {
485
+ reject({
486
+ errMsg: '未读取到NFC卡',
487
+ });
488
+ }
489
+
490
+ nfcInstance?.close?.({
491
+ success: (_res) => {
492
+ isConnected.value = false;
493
+ nfcInstance = undefined;
494
+ resolve({
495
+ errMsg: 'NFC 断开成功',
496
+ });
497
+
498
+ uni.showToast({ title: 'NFC 连接已关闭', icon: 'none' });
499
+ },
500
+ fail: (err) => {
501
+ reject(err);
502
+ uni.showToast({ title: 'NFC 连接关闭失败', icon: 'none' });
503
+ },
504
+ });
505
+ });
506
+ }
507
+
508
+ async function transceive(data: ArrayBuffer) {
509
+ return new Promise((resolve, reject) => {
510
+ if (!isSupportNFC.value) {
511
+ reject({
512
+ errMsg: '不支持NFC',
513
+ });
514
+ return;
515
+ }
516
+
517
+ if (!nfcInstance) {
518
+ reject({
519
+ errMsg: '未读取到NFC卡',
520
+ });
521
+ return;
522
+ }
523
+ nfcInstance?.transceive?.({
524
+ data,
525
+ success: (res) => {
526
+ resolve(res);
527
+ },
528
+ fail: (err) => {
529
+ reject(err);
530
+ },
531
+ });
532
+ });
533
+ }
534
+
535
+ async function writeNdefMessage(data: NFC.NdefData) {
536
+ return new Promise((resolve, reject) => {
537
+ if (!isSupportNFC.value) {
538
+ reject({
539
+ errMsg: '不支持NFC',
540
+ });
541
+ } else if (!nfcInstance) {
542
+ reject({
543
+ errMsg: '未读取到NFC卡',
544
+ });
545
+ } else {
546
+ nfcInstance?.writeNdefMessage?.({
547
+ ...data,
548
+ success: (res) => {
549
+ resolve(res);
550
+ },
551
+ fail: (err) => {
552
+ reject(err);
553
+ },
554
+ });
555
+ }
556
+ });
557
+ }
558
+
559
+ /**
560
+ * 写入数据
561
+ *
562
+ * 支持以以下类型
563
+ * ISO-DEP
564
+ * MIFARE Classic
565
+ * MIFARE Ultralight
566
+ * NFC-A
567
+ * NFC-B
568
+ * NFC-F
569
+ * NFC-V
570
+ *
571
+ * @param {*} data
572
+ * @return {*}
573
+ */
574
+ async function write(data: ArrayBuffer) {
575
+ try {
576
+ // 连接 nfc
577
+ await connect();
578
+ uni.showToast({
579
+ title: '开始写入数据, 请勿断开连接',
580
+ icon: 'none',
581
+ });
582
+ // 写入数据
583
+
584
+ const result = await transceive(data);
585
+
586
+ uni.showToast({
587
+ title: '数据写入成功',
588
+ icon: 'none',
589
+ });
590
+ // 断开 nfc
591
+ await close();
592
+ return Promise.resolve({
593
+ errMsg: '数据写入成功',
594
+ data: result,
595
+ });
596
+ } catch (error) {
597
+ return Promise.reject({
598
+ errMsg: '数据写入失败',
599
+ error,
600
+ });
601
+ }
602
+ }
603
+
604
+ /**
605
+ * 写入数据
606
+ * 支持以以下类型
607
+ * Ndef
608
+ *
609
+ * @param {NFC.NdefData} data
610
+ */
611
+ async function writeNdef(data: NFC.NdefRecord[]) {
612
+ if (!isNdef.value) {
613
+ uni.showToast({
614
+ title: 'NFC 标签不支持 NDEF',
615
+ icon: 'none',
616
+ });
617
+ return Promise.reject({
618
+ errMsg: 'NFC 标签不支持 NDEF',
619
+ });
620
+ }
621
+
622
+ if (!nfcInstance) {
623
+ uni.showToast({
624
+ title: '请先建立连接',
625
+ icon: 'none',
626
+ });
627
+ return Promise.reject({
628
+ errMsg: '请先建立连接',
629
+ });
630
+ }
631
+
632
+ if (!isConnected.value) {
633
+ uni.showToast({
634
+ title: '请先建立连接',
635
+ icon: 'none',
636
+ });
637
+ return Promise.reject({
638
+ errMsg: '请先建立连接',
639
+ });
640
+ }
641
+
642
+ uni.showToast({
643
+ title: '开始写入数据,请勿断开连接',
644
+ icon: 'none',
645
+ duration: 3000,
646
+ });
647
+
648
+ try {
649
+ const records = data?.map((item) => {
650
+ // const tnf = stringToArrayBuffer(item.tnf);
651
+ const id = item.id ? stringToArrayBuffer(item.id) : new ArrayBuffer(0);
652
+ const type = stringToArrayBuffer(item.type);
653
+
654
+ return {
655
+ tnf: item.tnf,
656
+ type,
657
+ id,
658
+ payload: item.payload,
659
+ };
660
+ });
661
+
662
+ if (maxTransceiveLength && maxTransceiveLength < records.length) {
663
+ uni.showToast({
664
+ title: '写入数据超出标签容量',
665
+ icon: 'none',
666
+ duration: 3000,
667
+ });
668
+ nfcInstance.close();
669
+
670
+ return Promise.reject({
671
+ errMsg: '写入数据超出标签容量',
672
+ });
673
+ }
674
+
675
+ // 连接 nfc
676
+ await connect();
677
+ uni.showToast({
678
+ title: '开始写入数据, 请勿断开连接',
679
+ icon: 'none',
680
+ });
681
+ // 写入数据
682
+
683
+ const result = await writeNdefMessage({
684
+ records,
685
+ });
686
+
687
+ await close();
688
+ uni.showToast({
689
+ title: '数据写入成功',
690
+ icon: 'none',
691
+ duration: 3000,
692
+ });
693
+ return Promise.resolve({
694
+ errMsg: '数据写入成功',
695
+ data: result,
696
+ });
697
+ } catch (error) {
698
+ uni.showToast({
699
+ title: '数据写入失败',
700
+ icon: 'none',
701
+ duration: 3000,
702
+ });
703
+
704
+ return Promise.reject({
705
+ errMsg: '数据写入失败',
706
+ error,
707
+ });
708
+ }
709
+ }
710
+
711
+ /**
712
+ *
713
+ *
714
+ * @param {string} text
715
+ * @param {string} [language='zh'] 微信小程序下无效
716
+ * @return {*}
717
+ */
718
+ async function writeNdefText(
719
+ text: string,
720
+ _language = 'zh',
721
+ ): Promise<{ errMsg: string }> {
722
+ return writeNdef([
723
+ {
724
+ tnf: 1,
725
+ type: 'T',
726
+ payload: stringToArrayBuffer(text),
727
+ },
728
+ ]);
729
+ }
730
+
731
+ function writeNdefUri(uri: string): Promise<{ errMsg: string }> {
732
+ const record = createUriNdefRecord(uri);
733
+ return writeNdef([record]);
734
+ }
735
+
736
+ function writeNdefAndroidApp(
737
+ packageName: string,
738
+ ): Promise<{ errMsg: string }> {
739
+ return writeNdef([
740
+ {
741
+ tnf: 4,
742
+ type: 'android.com:pkg',
743
+ payload: stringToArrayBuffer(packageName),
744
+ },
745
+ ]);
746
+ }
747
+
748
+ function writeNdefWifi({
749
+ ssid,
750
+ password,
751
+ authType,
752
+ }: NFC.WSCConfig): Promise<{ errMsg: string }> {
753
+ const mimeType = 'application/vnd.wfa.wsc';
754
+ const wifiData = generateWSCBytesForAndroid({
755
+ ssid,
756
+ password,
757
+ authType,
758
+ });
759
+ return writeNdef([
760
+ {
761
+ tnf: 2,
762
+ type: mimeType,
763
+ payload: arrayNumberToArrayBuffer(wifiData),
764
+ },
765
+ ]);
766
+ }
767
+
768
+ function writeNdefVcard(
769
+ cardInfo: NFC.VCardContactInfo,
770
+ ): Promise<{ errMsg: string }> {
771
+ const mimeType = 'text/vcard';
772
+ const cardString = formatCardInfo(cardInfo);
773
+
774
+ const cardData = stringToArrayBuffer(cardString);
775
+ return writeNdef([
776
+ {
777
+ tnf: 2,
778
+ type: mimeType,
779
+ payload: cardData,
780
+ },
781
+ ]);
782
+ }
783
+
784
+ onMounted(() => {
785
+ initNfcAdapter();
786
+ });
787
+
788
+ onUnmounted(() => {
789
+ stopHCE();
790
+ offHCEMessage();
791
+ });
792
+
793
+ return {
794
+ data,
795
+ isNdef,
796
+ isSupportNFC,
797
+ isListening,
798
+ isConnected,
799
+ nfcInstance,
800
+ startHCE,
801
+ stopHCE,
802
+ connect,
803
+ close,
804
+ write,
805
+ writeNdef,
806
+ writeNdefText,
807
+ writeNdefUri,
808
+ writeNdefAndroidApp,
809
+ writeNdefWifi,
810
+ writeNdefVcard,
811
+ };
812
+ }