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.
- package/README.md +8 -0
- package/dist/const.cjs +1 -1
- package/dist/const.d.ts +1 -0
- package/dist/const.d.ts.map +1 -1
- package/dist/const.js +1 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +2 -2
- package/dist/i18n/locales/en.cjs +1 -1
- package/dist/i18n/locales/en.d.ts +5 -0
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +1 -1
- package/dist/i18n/locales/zh-Hans.cjs +1 -1
- package/dist/i18n/locales/zh-Hans.d.ts +5 -0
- package/dist/i18n/locales/zh-Hans.d.ts.map +1 -1
- package/dist/i18n/locales/zh-Hans.js +1 -1
- package/dist/modules/devIntercept/index.cjs +9 -9
- package/dist/modules/devIntercept/index.d.ts +1 -1
- package/dist/modules/devIntercept/index.d.ts.map +1 -1
- package/dist/modules/devIntercept/index.js +9 -9
- package/dist/modules/devStore/index.cjs +1 -1
- package/dist/modules/devStore/index.d.ts.map +1 -1
- package/dist/modules/devStore/index.js +1 -1
- package/dist/plugins/uniDevTool/transform/transformMain.cjs +3 -3
- package/dist/plugins/uniDevTool/transform/transformMain.d.ts +2 -1
- package/dist/plugins/uniDevTool/transform/transformMain.d.ts.map +1 -1
- package/dist/plugins/uniDevTool/transform/transformMain.js +3 -3
- package/dist/plugins/uniDevTool/transform/transformVue.cjs +31 -25
- package/dist/plugins/uniDevTool/transform/transformVue.d.ts +2 -1
- package/dist/plugins/uniDevTool/transform/transformVue.d.ts.map +1 -1
- package/dist/plugins/uniDevTool/transform/transformVue.js +30 -24
- package/dist/plugins/uniDevTool/uniDevTool.cjs +3 -3
- package/dist/plugins/uniDevTool/uniDevTool.d.ts +3 -1
- package/dist/plugins/uniDevTool/uniDevTool.d.ts.map +1 -1
- package/dist/plugins/uniDevTool/uniDevTool.js +3 -3
- package/dist/type.d.ts +3 -0
- package/dist/type.d.ts.map +1 -1
- package/dist/v3/DevTool/components/BluetoothList/BluetoothItem.vue +199 -199
- package/dist/v3/DevTool/components/BluetoothList/BluetoothTool.vue +730 -730
- package/dist/v3/DevTool/components/BluetoothList/index.vue +167 -167
- package/dist/v3/DevTool/components/CaptureScreen/index.vue +109 -109
- package/dist/v3/DevTool/components/ConsoleList/ConsoleItem.vue +230 -225
- package/dist/v3/DevTool/components/ConsoleList/RunJSInput.vue +247 -247
- package/dist/v3/DevTool/components/ConsoleList/index.vue +171 -171
- package/dist/v3/DevTool/components/ConsoleList/staticTips.ts +1145 -1145
- package/dist/v3/DevTool/components/DevToolTitle/index.vue +24 -24
- package/dist/v3/DevTool/components/DevToolWindow/DevToolOverlay.vue +197 -197
- package/dist/v3/DevTool/components/DevToolWindow/hooks/dataUtils.ts +48 -48
- package/dist/v3/DevTool/components/DevToolWindow/hooks/useDevToolData.ts +387 -387
- package/dist/v3/DevTool/components/DevToolWindow/hooks/useDevToolHandlers.ts +629 -629
- package/dist/v3/DevTool/components/DevToolWindow/hooks/useDevToolOverlay.ts +201 -197
- package/dist/v3/DevTool/components/ElEvent/ElEventItem.vue +105 -105
- package/dist/v3/DevTool/components/ElEvent/index.vue +106 -106
- package/dist/v3/DevTool/components/Instance/components/InstanceTreeNode.vue +265 -265
- package/dist/v3/DevTool/components/Instance/flatten.ts +226 -226
- package/dist/v3/DevTool/components/Instance/index.vue +94 -94
- package/dist/v3/DevTool/components/Instance/registry.ts +49 -49
- package/dist/v3/DevTool/components/Instance/transformTree.ts +375 -375
- package/dist/v3/DevTool/components/Instance/transformTreeCtx.ts +268 -268
- package/dist/v3/DevTool/components/Instance/typing.d.ts +43 -43
- package/dist/v3/DevTool/components/InstanceDetail/index.vue +485 -485
- package/dist/v3/DevTool/components/JsonDetail/index.vue +70 -70
- package/dist/v3/DevTool/components/NFCList/NFCItem.vue +112 -112
- package/dist/v3/DevTool/components/NFCList/NFCTool.vue +454 -454
- package/dist/v3/DevTool/components/NFCList/const.ts +56 -56
- package/dist/v3/DevTool/components/NFCList/index.vue +94 -94
- package/dist/v3/DevTool/components/NetworkList/InterceptConfig.vue +624 -624
- package/dist/v3/DevTool/components/NetworkList/InterceptItem.vue +140 -140
- package/dist/v3/DevTool/components/NetworkList/NetworkDetail.vue +287 -287
- package/dist/v3/DevTool/components/NetworkList/NetworkIntercept.vue +88 -88
- package/dist/v3/DevTool/components/NetworkList/NetworkItem.vue +163 -163
- package/dist/v3/DevTool/components/NetworkList/NetworkSend.vue +589 -589
- package/dist/v3/DevTool/components/NetworkList/const.ts +4 -4
- package/dist/v3/DevTool/components/NetworkList/hooks/useNetworkForm.ts +86 -86
- package/dist/v3/DevTool/components/NetworkList/index.vue +160 -160
- package/dist/v3/DevTool/components/NetworkList/utils.ts +101 -101
- package/dist/v3/DevTool/components/Performance/index.vue +498 -498
- package/dist/v3/DevTool/components/Performance/modules/PerformanceMetrics.vue +153 -153
- package/dist/v3/DevTool/components/Performance/modules/usePerformanceChart.ts +460 -460
- package/dist/v3/DevTool/components/Performance/modules/usePerformanceData.ts +258 -258
- package/dist/v3/DevTool/components/PiniaList/index.vue +93 -93
- package/dist/v3/DevTool/components/RunJS/index.vue +148 -148
- package/dist/v3/DevTool/components/ScanCodeList/ScanCodeItem.vue +97 -97
- package/dist/v3/DevTool/components/ScanCodeList/index.vue +100 -100
- package/dist/v3/DevTool/components/SettingButton/index.vue +45 -45
- package/dist/v3/DevTool/components/SettingList/index.vue +218 -218
- package/dist/v3/DevTool/components/SettingList/modules/SettingBarrage.vue +304 -304
- package/dist/v3/DevTool/components/SettingList/modules/SettingDevTool.vue +212 -212
- package/dist/v3/DevTool/components/SettingList/modules/SettingInfo.vue +157 -157
- package/dist/v3/DevTool/components/SettingList/modules/SettingLanguage.vue +74 -74
- package/dist/v3/DevTool/components/SettingList/modules/SettingLog.vue +230 -230
- package/dist/v3/DevTool/components/SettingList/typing.d.ts +2 -2
- package/dist/v3/DevTool/components/SourceCode/Line.vue +127 -127
- package/dist/v3/DevTool/components/SourceCode/parseCode.ts +609 -609
- package/dist/v3/DevTool/components/StorageList/index.vue +174 -174
- package/dist/v3/DevTool/components/TransferList/TransferDetail.vue +268 -268
- package/dist/v3/DevTool/components/VuexList/index.vue +84 -84
- package/dist/v3/DevTool/index.vue +1 -0
- package/dist/v3/components/AppTransition/index.vue +176 -176
- package/dist/v3/components/AutoSizer/index.vue +192 -192
- package/dist/v3/components/AutoSizer/index1.vue +184 -184
- package/dist/v3/components/AutoSizer/utils.ts +49 -49
- package/dist/v3/components/Barrage/BarrageItem.vue +137 -137
- package/dist/v3/components/Barrage/index.vue +202 -202
- package/dist/v3/components/CircularButton/index.vue +84 -84
- package/dist/v3/components/CustomSwiper/CustomSwiperItem.vue +49 -49
- package/dist/v3/components/CustomSwiper/index.vue +104 -104
- package/dist/v3/components/DevErrorBoundary/index.vue +380 -0
- package/dist/v3/components/Empty/index.vue +29 -29
- package/dist/v3/components/FilterSelect/index.vue +179 -179
- package/dist/v3/components/JsonPretty/components/Brackets/index.vue +27 -27
- package/dist/v3/components/JsonPretty/components/Carets/index.vue +59 -59
- package/dist/v3/components/JsonPretty/components/CheckController/index.vue +136 -136
- package/dist/v3/components/JsonPretty/components/TreeNode/index.vue +387 -387
- package/dist/v3/components/JsonPretty/hooks/useClipboard.ts +21 -21
- package/dist/v3/components/JsonPretty/hooks/useError.ts +21 -21
- package/dist/v3/components/JsonPretty/type.ts +127 -127
- package/dist/v3/components/JsonPretty/utils/index.ts +169 -169
- package/dist/v3/components/MovableContainer/index.vue +8 -4
- package/dist/v3/components/Pick/index.vue +322 -322
- package/dist/v3/components/Tag/index.vue +113 -113
- package/dist/v3/components/VirtualList/AutoSize.vue +40 -40
- package/dist/v3/components/VirtualList/index.vue +416 -416
- package/dist/v3/hooks/useBluetooth/index.ts +561 -561
- package/dist/v3/hooks/useContainerStyle.ts +153 -153
- package/dist/v3/hooks/useNFC/index.ts +107 -107
- package/dist/v3/hooks/useNFC/typing.d.ts +396 -396
- package/dist/v3/hooks/useNFC/useNFCAndroid.ts +966 -966
- package/dist/v3/hooks/useNFC/useNFCMpWeiXin.ts +812 -812
- package/dist/v3/hooks/useNFC/utils.ts +754 -754
- package/dist/v3/hooks/useRequest/index.ts +586 -586
- package/dist/v3/hooks/useRequest/utils.ts +267 -267
- package/dist/v3/hooks/useScanCode/index.ts +206 -206
- package/dist/v3/hooks/useWebsocket/index.ts +253 -253
- package/dist/v3/styles/theme.ts +12 -12
- 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
|
+
}
|