vite-uni-dev-tool 1.0.0 → 1.1.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 +46 -0
- package/dist/const.cjs +1 -1
- package/dist/const.d.ts +12 -0
- package/dist/const.d.ts.map +1 -1
- package/dist/const.js +1 -1
- package/dist/core-shared.d.ts +1 -1
- package/dist/core-shared.d.ts.map +1 -1
- package/dist/core-shared.js +1 -1
- package/dist/core.d.ts +10 -3
- 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 +81 -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 +82 -1
- package/dist/i18n/locales/zh-Hans.d.ts.map +1 -1
- package/dist/i18n/locales/zh-Hans.js +1 -1
- package/dist/modules/devConsole/index.cjs +1 -1
- package/dist/modules/devConsole/index.js +3 -3
- package/dist/modules/devEvent/index.cjs +3 -3
- package/dist/modules/devEvent/index.d.ts +1 -0
- package/dist/modules/devEvent/index.d.ts.map +1 -1
- package/dist/modules/devEvent/index.js +3 -3
- package/dist/modules/devIntercept/index.cjs +14 -13
- package/dist/modules/devIntercept/index.d.ts +19 -0
- package/dist/modules/devIntercept/index.d.ts.map +1 -1
- package/dist/modules/devIntercept/index.js +14 -13
- package/dist/modules/devStore/index.cjs +1 -1
- package/dist/modules/devStore/index.d.ts +21 -0
- 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 +1 -1
- package/dist/plugins/uniDevTool/transform/transformMain.js +1 -1
- package/dist/type.d.ts +47 -2
- package/dist/type.d.ts.map +1 -1
- package/dist/utils/language.cjs +1 -1
- package/dist/utils/language.d.ts.map +1 -1
- package/dist/utils/language.js +1 -1
- package/dist/utils/object.cjs +1 -1
- package/dist/utils/object.d.ts.map +1 -1
- package/dist/utils/object.js +1 -1
- package/dist/v3/DevTool/components/BluetoothList/BluetoothItem.vue +199 -0
- package/dist/v3/DevTool/components/BluetoothList/BluetoothTool.vue +730 -0
- package/dist/v3/DevTool/components/BluetoothList/index.vue +167 -0
- package/dist/v3/{CaptureScreen → DevTool/components/CaptureScreen}/index.vue +109 -109
- package/dist/v3/{ConsoleList → DevTool/components/ConsoleList}/ConsoleItem.vue +225 -224
- package/dist/v3/{ConsoleList → DevTool/components/ConsoleList}/RunJSInput.vue +247 -249
- package/dist/v3/{ConsoleList → DevTool/components/ConsoleList}/index.vue +171 -160
- package/dist/v3/{ConsoleList → DevTool/components/ConsoleList}/staticTips.ts +1145 -1145
- package/dist/v3/{DevToolButton → DevTool/components/DevToolButton}/index.vue +7 -4
- package/dist/v3/{DevToolTitle → DevTool/components/DevToolTitle}/index.vue +24 -24
- package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/DevToolOverlay.vue +197 -182
- package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/const.ts +28 -5
- package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/hooks/dataUtils.ts +48 -48
- package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/hooks/useDevToolData.ts +387 -338
- package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/hooks/useDevToolHandlers.ts +629 -549
- package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/hooks/useDevToolOverlay.ts +197 -184
- package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/index.vue +67 -16
- package/dist/v3/{ElEvent → DevTool/components/ElEvent}/ElEventItem.vue +105 -105
- package/dist/v3/{ElEvent → DevTool/components/ElEvent}/index.vue +106 -109
- package/dist/v3/{Instance → DevTool/components/Instance}/components/InstanceTreeNode.vue +265 -265
- package/dist/v3/{Instance → DevTool/components/Instance}/flatten.ts +226 -226
- package/dist/v3/{Instance → DevTool/components/Instance}/index.vue +94 -94
- package/dist/v3/{Instance → DevTool/components/Instance}/registry.ts +49 -49
- package/dist/v3/{Instance → DevTool/components/Instance}/transformTree.ts +375 -375
- package/dist/v3/{Instance → DevTool/components/Instance}/transformTreeCtx.ts +268 -268
- package/dist/v3/{Instance → DevTool/components/Instance}/typing.d.ts +43 -43
- package/dist/v3/{InstanceDetail → DevTool/components/InstanceDetail}/index.vue +485 -485
- package/dist/v3/{JsonDetail → DevTool/components/JsonDetail}/index.vue +70 -70
- package/dist/v3/{NFCList → DevTool/components/NFCList}/NFCItem.vue +112 -113
- package/dist/v3/{NFCList → DevTool/components/NFCList}/NFCTool.vue +454 -478
- package/dist/v3/{NFCList → DevTool/components/NFCList}/const.ts +56 -56
- package/dist/v3/{NFCList → DevTool/components/NFCList}/index.vue +94 -98
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/InterceptConfig.vue +624 -608
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/InterceptItem.vue +140 -140
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/NetworkDetail.vue +287 -296
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/NetworkIntercept.vue +88 -93
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/NetworkItem.vue +163 -167
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/NetworkSend.vue +589 -556
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/const.ts +4 -4
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/hooks/useNetworkForm.ts +86 -86
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/index.vue +160 -160
- package/dist/v3/{NetworkList → DevTool/components/NetworkList}/utils.ts +101 -101
- package/dist/v3/{Performance → DevTool/components/Performance}/index.vue +498 -495
- package/dist/v3/{Performance → DevTool/components/Performance}/modules/PerformanceMetrics.vue +153 -153
- package/dist/v3/{Performance → DevTool/components/Performance}/modules/PerformanceWidget.vue +12 -9
- package/dist/v3/{Performance → DevTool/components/Performance}/modules/usePerformanceChart.ts +460 -460
- package/dist/v3/{Performance → DevTool/components/Performance}/modules/usePerformanceData.ts +258 -258
- package/dist/v3/{PiniaList → DevTool/components/PiniaList}/index.vue +93 -94
- package/dist/v3/{RouteList → DevTool/components/RouteList}/index.vue +21 -24
- package/dist/v3/{RunJS → DevTool/components/RunJS}/index.vue +148 -148
- package/dist/v3/{ScanCodeList → DevTool/components/ScanCodeList}/ScanCodeItem.vue +97 -98
- package/dist/v3/{ScanCodeList → DevTool/components/ScanCodeList}/index.vue +100 -104
- package/dist/v3/{SettingButton → DevTool/components/SettingButton}/index.vue +45 -45
- package/dist/v3/{SettingList → DevTool/components/SettingList}/index.vue +218 -150
- package/dist/v3/DevTool/components/SettingList/modules/SettingBarrage.vue +304 -0
- package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingDevTool.vue +212 -208
- package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingInfo.vue +157 -119
- package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingLanguage.vue +74 -74
- package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingLog.vue +230 -230
- package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingNetwork.vue +3 -3
- package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingTheme.vue +37 -7
- package/dist/v3/{SettingList → DevTool/components/SettingList}/typing.d.ts +2 -2
- package/dist/v3/{SourceCode → DevTool/components/SourceCode}/Line.vue +127 -116
- package/dist/v3/{SourceCode → DevTool/components/SourceCode}/index.vue +8 -8
- package/dist/v3/{SourceCode → DevTool/components/SourceCode}/parseCode.ts +609 -701
- package/dist/v3/{StorageList → DevTool/components/StorageList}/index.vue +174 -174
- package/dist/v3/{TransferList → DevTool/components/TransferList}/TransferDetail.vue +268 -268
- package/dist/v3/{TransferList → DevTool/components/TransferList}/TransferItem.vue +4 -4
- package/dist/v3/{TransferList → DevTool/components/TransferList}/index.vue +8 -8
- package/dist/v3/{UniEvent → DevTool/components/UniEvent}/UniEventItem.vue +6 -7
- package/dist/v3/{UniEvent → DevTool/components/UniEvent}/index.vue +6 -6
- package/dist/v3/{VuexList → DevTool/components/VuexList}/index.vue +84 -84
- package/dist/v3/{WebSocket → DevTool/components/WebSocket}/WebSocketDetail.vue +8 -8
- package/dist/v3/{WebSocket → DevTool/components/WebSocket}/WebSocketItem.vue +4 -4
- package/dist/v3/{WebSocket → DevTool/components/WebSocket}/index.vue +8 -8
- package/dist/v3/DevTool/index.vue +179 -5
- package/dist/v3/{AppTransition → components/AppTransition}/index.vue +176 -170
- package/dist/v3/{AutoSizer → components/AutoSizer}/index.vue +192 -192
- package/dist/v3/{AutoSizer → components/AutoSizer}/index1.vue +184 -184
- package/dist/v3/{AutoSizer → components/AutoSizer}/utils.ts +49 -49
- package/dist/v3/components/Barrage/BarrageItem.vue +137 -0
- package/dist/v3/components/Barrage/index.vue +202 -0
- package/dist/v3/{CircularButton → components/CircularButton}/index.vue +84 -84
- package/dist/v3/{CustomSwiper → components/CustomSwiper}/CustomSwiperItem.vue +49 -49
- package/dist/v3/{CustomSwiper → components/CustomSwiper}/index.vue +104 -104
- package/dist/v3/{DraggableContainer → components/DraggableContainer}/index.vue +1 -1
- package/dist/v3/{Empty → components/Empty}/index.vue +29 -29
- package/dist/v3/{FilterInput → components/FilterInput}/index.vue +1 -1
- package/dist/v3/{FilterSelect → components/FilterSelect}/index.vue +179 -179
- package/dist/v3/{JsonPretty → components/JsonPretty}/components/Brackets/index.vue +27 -27
- package/dist/v3/{JsonPretty → components/JsonPretty}/components/Carets/index.vue +59 -59
- package/dist/v3/{JsonPretty → components/JsonPretty}/components/CheckController/index.vue +136 -136
- package/dist/v3/{JsonPretty → components/JsonPretty}/components/TreeNode/index.vue +387 -381
- package/dist/v3/{JsonPretty → components/JsonPretty}/hooks/useClipboard.ts +21 -21
- package/dist/v3/{JsonPretty → components/JsonPretty}/hooks/useError.ts +21 -21
- package/dist/v3/{JsonPretty → components/JsonPretty}/index.vue +16 -13
- package/dist/v3/{JsonPretty → components/JsonPretty}/type.ts +127 -126
- package/dist/v3/{JsonPretty → components/JsonPretty}/utils/index.ts +169 -169
- package/dist/v3/{MovableContainer → components/MovableContainer}/index.vue +1 -1
- package/dist/v3/{Pick → components/Pick}/index.vue +322 -322
- package/dist/v3/{Tabs → components/Tabs}/index.vue +30 -4
- package/dist/v3/{Tag → components/Tag}/index.vue +113 -113
- package/dist/v3/{VirtualList → components/VirtualList}/AutoSize.vue +40 -40
- package/dist/v3/{VirtualList → components/VirtualList}/index.vue +416 -412
- package/dist/v3/hooks/useBluetooth/index.ts +561 -0
- 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 -573
- package/dist/v3/hooks/useRequest/utils.ts +267 -267
- package/dist/v3/hooks/useScanCode/index.ts +206 -206
- package/dist/v3/hooks/useWebsocket/README.md +79 -0
- package/dist/v3/hooks/useWebsocket/index.ts +253 -0
- package/dist/v3/styles/theme.css +17 -10
- package/dist/v3/styles/theme.ts +12 -12
- package/package.json +59 -64
- package/dist/plugins/uniParseStock/index.d.ts +0 -10
- package/dist/plugins/uniParseStock/index.d.ts.map +0 -1
- /package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/index.css +0 -0
- /package/dist/v3/{SettingList → DevTool/components/SettingList}/index.css +0 -0
- /package/dist/v3/{Empty → components/Empty}/empty.png +0 -0
- /package/dist/v3/{VirtualList → components/VirtualList}/readme.md +0 -0
|
@@ -1,966 +1,966 @@
|
|
|
1
|
-
import { onMounted, onUnmounted, ref } from 'vue';
|
|
2
|
-
import {
|
|
3
|
-
formatCardInfo,
|
|
4
|
-
getAndroidTechs,
|
|
5
|
-
getReadWriteStandard,
|
|
6
|
-
getSakHex,
|
|
7
|
-
getSakType,
|
|
8
|
-
getTnfDescription,
|
|
9
|
-
getTypeDescription,
|
|
10
|
-
parseAtqaAndroid,
|
|
11
|
-
parseUniversalTLV,
|
|
12
|
-
parseVCardPayload,
|
|
13
|
-
stringToBytes,
|
|
14
|
-
transformArrayBuffer,
|
|
15
|
-
wifiTLVConfig,
|
|
16
|
-
generateWSCBytesForAndroid,
|
|
17
|
-
} from './utils';
|
|
18
|
-
|
|
19
|
-
// 声明变量,但不立即初始化
|
|
20
|
-
let NfcAdapter: any;
|
|
21
|
-
let _Context: any;
|
|
22
|
-
let _Tag: any;
|
|
23
|
-
let Ndef: any;
|
|
24
|
-
let NfcA: any;
|
|
25
|
-
let NfcB: any;
|
|
26
|
-
let NfcF: any;
|
|
27
|
-
let NfcV: any;
|
|
28
|
-
let _NdefFormat: any;
|
|
29
|
-
let NdefFormatable: any;
|
|
30
|
-
let MifareClassic: any;
|
|
31
|
-
let MifareUltralight: any;
|
|
32
|
-
let IsoDep: any;
|
|
33
|
-
let Intent: any;
|
|
34
|
-
let PendingIntent: any;
|
|
35
|
-
let IntentFilter: any;
|
|
36
|
-
let Settings: any;
|
|
37
|
-
let NdefRecord: any;
|
|
38
|
-
let NdefMessage: any;
|
|
39
|
-
|
|
40
|
-
let INTENT_FLAGS_SINGLE_TOP: any;
|
|
41
|
-
let PENDING_INTENT_FLAGS: any;
|
|
42
|
-
let EXTRA_NDEF_MESSAGES: any;
|
|
43
|
-
let EXTRA_ID: any;
|
|
44
|
-
let EXTRA_TAG: any;
|
|
45
|
-
let _TNF_MIME_MEDIA: any;
|
|
46
|
-
let _ACTION_NFC_SETTINGS: any;
|
|
47
|
-
|
|
48
|
-
let NFC_INTENT_FILTERS: any[] = [];
|
|
49
|
-
|
|
50
|
-
const NFC_TECH_LISTS = [
|
|
51
|
-
['android.nfc.tech.Ndef'],
|
|
52
|
-
['android.nfc.tech.NdefFormatable'],
|
|
53
|
-
['android.nfc.tech.IsoDep'],
|
|
54
|
-
['android.nfc.tech.NfcA'],
|
|
55
|
-
['android.nfc.tech.NfcB'],
|
|
56
|
-
['android.nfc.tech.NfcF'],
|
|
57
|
-
['android.nfc.tech.NfcV'],
|
|
58
|
-
['android.nfc.tech.MifareClassic'],
|
|
59
|
-
['android.nfc.tech.MifareUltralight'],
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
// 初始化 Android 类
|
|
63
|
-
function initAndroidClasses() {
|
|
64
|
-
try {
|
|
65
|
-
if (NfcAdapter) return; // 避免重复初始化
|
|
66
|
-
|
|
67
|
-
NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');
|
|
68
|
-
_Context = plus.android.importClass('android.content.Context');
|
|
69
|
-
_Tag = plus.android.importClass('android.nfc.Tag');
|
|
70
|
-
Ndef = plus.android.importClass('android.nfc.tech.Ndef');
|
|
71
|
-
NfcA = plus.android.importClass('android.nfc.tech.NfcA');
|
|
72
|
-
NfcB = plus.android.importClass('android.nfc.tech.NfcB');
|
|
73
|
-
NfcF = plus.android.importClass('android.nfc.tech.NfcF');
|
|
74
|
-
NfcV = plus.android.importClass('android.nfc.tech.NfcV');
|
|
75
|
-
_NdefFormat = plus.android.importClass('android.nfc.tech.NdefFormat');
|
|
76
|
-
NdefFormatable = plus.android.importClass(
|
|
77
|
-
'android.nfc.tech.NdefFormatable',
|
|
78
|
-
);
|
|
79
|
-
MifareClassic = plus.android.importClass('android.nfc.tech.MifareClassic');
|
|
80
|
-
MifareUltralight = plus.android.importClass(
|
|
81
|
-
'android.nfc.tech.MifareUltralight',
|
|
82
|
-
);
|
|
83
|
-
IsoDep = plus.android.importClass('android.nfc.tech.IsoDep');
|
|
84
|
-
Intent = plus.android.importClass('android.content.Intent');
|
|
85
|
-
PendingIntent = plus.android.importClass('android.app.PendingIntent');
|
|
86
|
-
IntentFilter = plus.android.importClass('android.content.IntentFilter');
|
|
87
|
-
Settings = plus.android.importClass('android.provider.Settings');
|
|
88
|
-
NdefRecord = plus.android.importClass('android.nfc.NdefRecord');
|
|
89
|
-
NdefMessage = plus.android.importClass('android.nfc.NdefMessage');
|
|
90
|
-
|
|
91
|
-
INTENT_FLAGS_SINGLE_TOP = Intent.FLAG_ACTIVITY_SINGLE_TOP;
|
|
92
|
-
PENDING_INTENT_FLAGS = PendingIntent.FLAG_MUTABLE;
|
|
93
|
-
|
|
94
|
-
EXTRA_NDEF_MESSAGES = NfcAdapter.EXTRA_NDEF_MESSAGES;
|
|
95
|
-
EXTRA_ID = NfcAdapter.EXTRA_ID;
|
|
96
|
-
EXTRA_TAG = NfcAdapter.EXTRA_TAG;
|
|
97
|
-
|
|
98
|
-
_TNF_MIME_MEDIA = NdefRecord.TNF_MIME_MEDIA;
|
|
99
|
-
_ACTION_NFC_SETTINGS = Settings.ACTION_NFC_SETTINGS;
|
|
100
|
-
|
|
101
|
-
NFC_INTENT_FILTERS = [
|
|
102
|
-
NfcAdapter.ACTION_NDEF_DISCOVERED,
|
|
103
|
-
NfcAdapter.ACTION_TECH_DISCOVERED,
|
|
104
|
-
NfcAdapter.ACTION_TAG_DISCOVERED,
|
|
105
|
-
];
|
|
106
|
-
} catch (e) {
|
|
107
|
-
console.error('Core: initAndroidClasses error', e);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export default function useNFCAndroid(
|
|
112
|
-
listener: NFC.Listener,
|
|
113
|
-
options?: NFC.NfcOption,
|
|
114
|
-
): NFC.NfcResult {
|
|
115
|
-
/** 是否支持 nfc */
|
|
116
|
-
const isSupportNFC = ref<boolean | undefined>(false);
|
|
117
|
-
/** 是否监听中 */
|
|
118
|
-
const isListening = ref<boolean>(false);
|
|
119
|
-
/** 是否已连接 */
|
|
120
|
-
const isConnected = ref<boolean>(false);
|
|
121
|
-
/** nfc 数据 */
|
|
122
|
-
const data = ref<NFC.Result>({
|
|
123
|
-
id: new ArrayBuffer(0),
|
|
124
|
-
techs: [],
|
|
125
|
-
byteArray: [],
|
|
126
|
-
hexArray: [],
|
|
127
|
-
hexNumberArray: [],
|
|
128
|
-
hexString: '',
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
/** ndef 写入方式比较特殊,需要特殊处理 */
|
|
132
|
-
const isNdef = ref(false);
|
|
133
|
-
|
|
134
|
-
// 延迟获取 mainActivity,确保 plus 已就绪
|
|
135
|
-
let mainActivity: any = null;
|
|
136
|
-
|
|
137
|
-
onMounted(() => {
|
|
138
|
-
initAndroidClasses();
|
|
139
|
-
try {
|
|
140
|
-
mainActivity = plus.android.runtimeMainActivity();
|
|
141
|
-
initNfcAdapter();
|
|
142
|
-
} catch (e) {
|
|
143
|
-
console.error('Core: failed to init NFC adapter', e);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
let checkInterval: any = null;
|
|
148
|
-
|
|
149
|
-
let nfcAdapter: NFC.Adapter | null = null;
|
|
150
|
-
let nfcPendingIntent: any = null;
|
|
151
|
-
let nfcTag: any = null;
|
|
152
|
-
let nfcInstance: any = null;
|
|
153
|
-
|
|
154
|
-
let maxTransceiveLength = 0;
|
|
155
|
-
|
|
156
|
-
function checkConnected() {
|
|
157
|
-
checkInterval = setInterval(() => {
|
|
158
|
-
if (!nfcAdapter) {
|
|
159
|
-
isConnected.value = false;
|
|
160
|
-
clearInterval(checkInterval);
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (!nfcAdapter.isEnabled()) {
|
|
165
|
-
isConnected.value = false;
|
|
166
|
-
clearInterval(checkInterval);
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
if (!nfcInstance) {
|
|
170
|
-
isConnected.value = false;
|
|
171
|
-
clearInterval(checkInterval);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (nfcInstance.isConnected()) {
|
|
176
|
-
isConnected.value = true;
|
|
177
|
-
} else {
|
|
178
|
-
isConnected.value = false;
|
|
179
|
-
clearInterval(checkInterval);
|
|
180
|
-
}
|
|
181
|
-
}, options?.checkConnectedDelay ?? 500);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function getInstance(techs: NFC.NfcType[], needNdef?: boolean) {
|
|
185
|
-
let type = 'Ndef';
|
|
186
|
-
if (needNdef) {
|
|
187
|
-
type = 'Ndef';
|
|
188
|
-
} else {
|
|
189
|
-
type = techs.filter((tech) => tech != 'Ndef' && tech != 'NDEF')?.[0];
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
switch (type) {
|
|
193
|
-
case 'NFC-A':
|
|
194
|
-
return NfcA.get(nfcTag);
|
|
195
|
-
case 'NFC-B':
|
|
196
|
-
return NfcB.get(nfcTag);
|
|
197
|
-
case 'NFC-F':
|
|
198
|
-
return NfcF.get(nfcTag);
|
|
199
|
-
case 'NFC-V':
|
|
200
|
-
return NfcV.get(nfcTag);
|
|
201
|
-
case 'MIFARE Classic':
|
|
202
|
-
return MifareClassic.get(nfcTag);
|
|
203
|
-
case 'MIFARE Ultralight':
|
|
204
|
-
return MifareUltralight.get(nfcTag);
|
|
205
|
-
case 'Ndef':
|
|
206
|
-
isNdef.value = true;
|
|
207
|
-
return Ndef.get(nfcTag);
|
|
208
|
-
case 'Ndef Formatable':
|
|
209
|
-
return NdefFormatable.get(nfcTag);
|
|
210
|
-
case 'ISO-DEP':
|
|
211
|
-
return IsoDep.get(nfcTag);
|
|
212
|
-
default:
|
|
213
|
-
return undefined;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function innerListener() {
|
|
218
|
-
try {
|
|
219
|
-
const intent = mainActivity.getIntent();
|
|
220
|
-
if (!intent) {
|
|
221
|
-
uni.showToast({ title: 'NFC 数据解析失败', icon: 'none' });
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// 获取id
|
|
226
|
-
const id = intent.getByteArrayExtra(EXTRA_ID);
|
|
227
|
-
|
|
228
|
-
const transform = transformArrayBuffer(id);
|
|
229
|
-
|
|
230
|
-
let techs: NFC.NfcType[] = [];
|
|
231
|
-
|
|
232
|
-
let sak = 0;
|
|
233
|
-
let sakHex = '';
|
|
234
|
-
let sakType = undefined;
|
|
235
|
-
let atqaInfo = {
|
|
236
|
-
uidType: 0,
|
|
237
|
-
storageSize: 0,
|
|
238
|
-
manufacturer: 0,
|
|
239
|
-
cardFeatures: 0,
|
|
240
|
-
reserved: 0,
|
|
241
|
-
};
|
|
242
|
-
let readWriteStandard: string[] = [];
|
|
243
|
-
let sectorCount = 0;
|
|
244
|
-
let blockCount = 0;
|
|
245
|
-
let messages: any = [];
|
|
246
|
-
nfcTag = intent.getParcelableExtra(EXTRA_TAG); // 先获取 Tag 实例
|
|
247
|
-
|
|
248
|
-
if (nfcTag) {
|
|
249
|
-
// 核心方法:通过 Tag.getTechList() 获取原生技术列表数组
|
|
250
|
-
const nativeTechList = nfcTag.getTechList();
|
|
251
|
-
// 转换为可直接使用的 string 数组(兼容原生返回格式)
|
|
252
|
-
techs = Array.isArray(nativeTechList) ? nativeTechList : [];
|
|
253
|
-
|
|
254
|
-
techs = getAndroidTechs(techs);
|
|
255
|
-
|
|
256
|
-
nfcInstance = getInstance(techs, true);
|
|
257
|
-
|
|
258
|
-
if (!nfcInstance) {
|
|
259
|
-
uni.showToast({ title: 'NFC 实例获取失败', icon: 'none' });
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// 一定要连接
|
|
264
|
-
nfcInstance?.connect?.();
|
|
265
|
-
|
|
266
|
-
if (isNdef.value) {
|
|
267
|
-
const otherInstance = getInstance(techs);
|
|
268
|
-
maxTransceiveLength = otherInstance?.getMaxTransceiveLength?.() ?? 0;
|
|
269
|
-
} else {
|
|
270
|
-
maxTransceiveLength = nfcInstance?.getMaxTransceiveLength?.() ?? 0;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
readWriteStandard = getReadWriteStandard(techs);
|
|
274
|
-
|
|
275
|
-
sectorCount = nfcInstance?.getSectorCount?.();
|
|
276
|
-
|
|
277
|
-
blockCount = nfcInstance?.getBlockCount?.();
|
|
278
|
-
|
|
279
|
-
const ndefMessage = intent.getParcelableArrayExtra(EXTRA_NDEF_MESSAGES);
|
|
280
|
-
|
|
281
|
-
if (ndefMessage && ndefMessage.length > 0) {
|
|
282
|
-
let records = ndefMessage?.[0]?.getRecords?.();
|
|
283
|
-
|
|
284
|
-
records = records.map((record: any) => {
|
|
285
|
-
const idObject = record?.getId?.();
|
|
286
|
-
|
|
287
|
-
const id = idObject
|
|
288
|
-
? plus.android.invoke(idObject, 'toString')
|
|
289
|
-
: '';
|
|
290
|
-
|
|
291
|
-
const tnfObject = record?.getTnf?.();
|
|
292
|
-
const tnf = tnfObject
|
|
293
|
-
? plus.android.invoke(tnfObject, 'toString')
|
|
294
|
-
: '';
|
|
295
|
-
const tnfDescription = getTnfDescription(tnf);
|
|
296
|
-
|
|
297
|
-
const payloadByte = record?.getPayload?.();
|
|
298
|
-
|
|
299
|
-
const typeObject = record?.getType?.();
|
|
300
|
-
const type = typeObject
|
|
301
|
-
? (plus.android.newObject('java.lang.String', typeObject) as any)
|
|
302
|
-
: '';
|
|
303
|
-
const typeDescription = getTypeDescription(
|
|
304
|
-
type as string,
|
|
305
|
-
payloadByte,
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
let payload: any = payloadByte
|
|
309
|
-
? plus.android.newObject('java.lang.String', payloadByte)
|
|
310
|
-
: '';
|
|
311
|
-
if (type === 'application/vnd.wfa.wsc') {
|
|
312
|
-
payload = parseUniversalTLV(payloadByte, wifiTLVConfig);
|
|
313
|
-
} else if (type === 'text/vcard') {
|
|
314
|
-
payload = parseVCardPayload(payload);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return {
|
|
318
|
-
id,
|
|
319
|
-
tnf,
|
|
320
|
-
tnfDescription,
|
|
321
|
-
type,
|
|
322
|
-
typeDescription,
|
|
323
|
-
payload,
|
|
324
|
-
};
|
|
325
|
-
});
|
|
326
|
-
messages = [
|
|
327
|
-
{
|
|
328
|
-
records,
|
|
329
|
-
},
|
|
330
|
-
];
|
|
331
|
-
} else {
|
|
332
|
-
messages = [];
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
if (techs.includes('NFC-A')) {
|
|
336
|
-
// NFC-A 标签的 SAK 信息
|
|
337
|
-
const nfcAInstance = NfcA.get(nfcTag);
|
|
338
|
-
const sakShortObject =
|
|
339
|
-
plus.android.invoke(nfcAInstance, 'getSak') ?? 0;
|
|
340
|
-
|
|
341
|
-
const sakStr = plus.android.invoke(sakShortObject, 'toString');
|
|
342
|
-
|
|
343
|
-
sak = Number(sakStr) || 0;
|
|
344
|
-
|
|
345
|
-
sakType = getSakType(sak);
|
|
346
|
-
|
|
347
|
-
sakHex = getSakHex(sak);
|
|
348
|
-
|
|
349
|
-
const atqa = plus.android.invoke(nfcAInstance, 'getAtqa');
|
|
350
|
-
|
|
351
|
-
atqaInfo = parseAtqaAndroid(atqa);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// 返回数据
|
|
356
|
-
data.value = {
|
|
357
|
-
...data.value,
|
|
358
|
-
...transform,
|
|
359
|
-
...atqaInfo,
|
|
360
|
-
id,
|
|
361
|
-
sak,
|
|
362
|
-
sakHex,
|
|
363
|
-
sakType,
|
|
364
|
-
techs,
|
|
365
|
-
messages,
|
|
366
|
-
maxTransceiveLength,
|
|
367
|
-
readWriteStandard,
|
|
368
|
-
sectorCount,
|
|
369
|
-
blockCount,
|
|
370
|
-
};
|
|
371
|
-
// 回调通知外部
|
|
372
|
-
listener(data.value);
|
|
373
|
-
// 检查链接状态
|
|
374
|
-
checkConnected();
|
|
375
|
-
|
|
376
|
-
// 可将改行去除
|
|
377
|
-
uni?.__dev_tool_nfc_collection__?.(data.value);
|
|
378
|
-
} catch (_error) {
|
|
379
|
-
console.log('error: ', _error);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
function initNfcAdapter() {
|
|
384
|
-
try {
|
|
385
|
-
if (!mainActivity) {
|
|
386
|
-
uni.showToast({ title: '无法获取主 Activity 实例', icon: 'none' });
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
nfcAdapter = NfcAdapter.getDefaultAdapter(mainActivity);
|
|
391
|
-
|
|
392
|
-
// 1. 设备不支持 NFC
|
|
393
|
-
if (!nfcAdapter) {
|
|
394
|
-
isSupportNFC.value = false;
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// 2. NFC 功能未开启
|
|
399
|
-
if (!nfcAdapter.isEnabled()) {
|
|
400
|
-
isSupportNFC.value = false;
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// 3. 初始化成功,注册监听
|
|
405
|
-
isSupportNFC.value = true;
|
|
406
|
-
} catch (_error) {
|
|
407
|
-
isSupportNFC.value = false;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function startHCE() {
|
|
412
|
-
if (!isSupportNFC.value) {
|
|
413
|
-
uni.showToast({
|
|
414
|
-
title: '设备不支持 NFC',
|
|
415
|
-
icon: 'none',
|
|
416
|
-
});
|
|
417
|
-
return Promise.reject({
|
|
418
|
-
errMsg: '设备不支持 NFC',
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
// 前置校验
|
|
422
|
-
if (!nfcAdapter) {
|
|
423
|
-
uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
|
|
424
|
-
return Promise.reject({
|
|
425
|
-
errMsg: '请先初始化 NFC 适配器 NFC',
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
//
|
|
429
|
-
if (isListening.value) {
|
|
430
|
-
uni.showToast({ title: 'NFC 监听已开启,无需重复操作', icon: 'none' });
|
|
431
|
-
return Promise.reject({
|
|
432
|
-
errMsg: 'NFC 监听已开启,无需重复操作',
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
try {
|
|
437
|
-
// 1. 注册 newintent 事件监听
|
|
438
|
-
plus.globalEvent.addEventListener('newintent', innerListener);
|
|
439
|
-
|
|
440
|
-
plus.globalEvent.addEventListener('resume', () => {
|
|
441
|
-
if (nfcAdapter) {
|
|
442
|
-
const filters = NFC_INTENT_FILTERS.map(
|
|
443
|
-
(filter) => new IntentFilter(filter),
|
|
444
|
-
);
|
|
445
|
-
nfcAdapter?.enableForegroundDispatch(
|
|
446
|
-
mainActivity,
|
|
447
|
-
nfcPendingIntent,
|
|
448
|
-
filters,
|
|
449
|
-
NFC_TECH_LISTS,
|
|
450
|
-
);
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
plus.globalEvent.addEventListener('pause', () => {
|
|
455
|
-
if (nfcAdapter) {
|
|
456
|
-
nfcAdapter?.disableForegroundDispatch(mainActivity);
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
// 2. 构建前台调度 PendingIntent(缓存实例,避免重复创建)
|
|
461
|
-
if (!nfcPendingIntent) {
|
|
462
|
-
const intent = new Intent(mainActivity, mainActivity.getClass());
|
|
463
|
-
intent.addFlags(INTENT_FLAGS_SINGLE_TOP);
|
|
464
|
-
nfcPendingIntent = PendingIntent.getActivity(
|
|
465
|
-
mainActivity,
|
|
466
|
-
0,
|
|
467
|
-
intent,
|
|
468
|
-
PENDING_INTENT_FLAGS,
|
|
469
|
-
);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// 3. 构建 Intent 过滤器
|
|
473
|
-
const filters = NFC_INTENT_FILTERS.map(
|
|
474
|
-
(filter) => new IntentFilter(filter),
|
|
475
|
-
);
|
|
476
|
-
|
|
477
|
-
// 4. 启用前台调度(核心:App 前台优先捕获 NFC 事件)
|
|
478
|
-
nfcAdapter?.enableForegroundDispatch(
|
|
479
|
-
mainActivity,
|
|
480
|
-
nfcPendingIntent,
|
|
481
|
-
filters,
|
|
482
|
-
NFC_TECH_LISTS,
|
|
483
|
-
);
|
|
484
|
-
|
|
485
|
-
// 5. 更新监听状态
|
|
486
|
-
isListening.value = true;
|
|
487
|
-
uni.showToast({
|
|
488
|
-
title: '开始监听NFC',
|
|
489
|
-
icon: 'none',
|
|
490
|
-
});
|
|
491
|
-
return Promise.reject({
|
|
492
|
-
errMsg: '开始监听NFC',
|
|
493
|
-
});
|
|
494
|
-
} catch (_error) {
|
|
495
|
-
uni.showToast({ title: 'NFC 监听开启失败', icon: 'none' });
|
|
496
|
-
isListening.value = false;
|
|
497
|
-
return Promise.reject({
|
|
498
|
-
errMsg: 'NFC 监听开启失败',
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
function stopHCE() {
|
|
504
|
-
// 前置校验
|
|
505
|
-
if (!isSupportNFC.value) {
|
|
506
|
-
uni.showToast({
|
|
507
|
-
title: '设备不支持 NFC',
|
|
508
|
-
icon: 'none',
|
|
509
|
-
});
|
|
510
|
-
return Promise.reject({
|
|
511
|
-
errMsg: '设备不支持 NFC',
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
// 前置校验
|
|
515
|
-
if (!nfcAdapter) {
|
|
516
|
-
uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
|
|
517
|
-
return Promise.reject({
|
|
518
|
-
errMsg: '请先初始化 NFC 适配器',
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
//
|
|
522
|
-
if (!isListening.value) {
|
|
523
|
-
uni.showToast({ title: 'NFC 监听已关闭,无需重复操作', icon: 'none' });
|
|
524
|
-
|
|
525
|
-
return Promise.reject({
|
|
526
|
-
errMsg: 'NFC 监听已关闭,无需重复操作',
|
|
527
|
-
});
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
try {
|
|
531
|
-
// 1. 禁用前台调度
|
|
532
|
-
nfcAdapter.disableForegroundDispatch(mainActivity);
|
|
533
|
-
// 2. 更新监听状态
|
|
534
|
-
isListening.value = false;
|
|
535
|
-
isConnected.value = false;
|
|
536
|
-
uni.showToast({
|
|
537
|
-
title: '停止监听NFC',
|
|
538
|
-
icon: 'none',
|
|
539
|
-
});
|
|
540
|
-
clearInterval(checkInterval);
|
|
541
|
-
return Promise.resolve({
|
|
542
|
-
errMsg: '停止监听NFC',
|
|
543
|
-
});
|
|
544
|
-
} catch (_error) {
|
|
545
|
-
uni.showToast({ title: 'NFC 监听停止失败', icon: 'error' });
|
|
546
|
-
return Promise.resolve({
|
|
547
|
-
errMsg: 'NFC 监听停止失败',
|
|
548
|
-
error: _error,
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
function connect() {
|
|
554
|
-
if (!isSupportNFC.value) {
|
|
555
|
-
uni.showToast({ title: '设备不支持 NFC', icon: 'none' });
|
|
556
|
-
return Promise.reject({
|
|
557
|
-
errMsg: '设备不支持 NFC',
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
if (!nfcInstance) {
|
|
562
|
-
uni.showToast({ title: '请先靠近 NFC 标签', icon: 'none' });
|
|
563
|
-
return Promise.reject({
|
|
564
|
-
errMsg: '请先靠近 NFC 标签',
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
if (!isListening.value) {
|
|
569
|
-
uni.showToast({ title: '请先开启前台调度监听', icon: 'none' });
|
|
570
|
-
return Promise.reject({
|
|
571
|
-
errMsg: '请先开启前台调度监听',
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
try {
|
|
576
|
-
checkConnected();
|
|
577
|
-
if (!nfcInstance.isConnected()) {
|
|
578
|
-
// 补充连接状态判断
|
|
579
|
-
nfcInstance.connect();
|
|
580
|
-
isConnected.value = true;
|
|
581
|
-
uni.showToast({ title: 'NFC 连接成功', icon: 'none' });
|
|
582
|
-
return Promise.resolve({
|
|
583
|
-
errMsg: 'NFC 连接成功',
|
|
584
|
-
});
|
|
585
|
-
} else {
|
|
586
|
-
isConnected.value = true;
|
|
587
|
-
uni.showToast({ title: 'NFC 已处于连接状态', icon: 'none' });
|
|
588
|
-
return Promise.reject({
|
|
589
|
-
errMsg: 'NFC 已处于连接状态',
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
} catch (error) {
|
|
593
|
-
uni.showToast({ title: 'NFC 连接失败', icon: 'none' });
|
|
594
|
-
isConnected.value = false;
|
|
595
|
-
return Promise.reject({
|
|
596
|
-
errMsg: 'NFC 连接失败',
|
|
597
|
-
error,
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
function close() {
|
|
603
|
-
if (!isSupportNFC.value) {
|
|
604
|
-
uni.showToast({ title: '设备不支持 NFC', icon: 'none' });
|
|
605
|
-
return Promise.reject({
|
|
606
|
-
errMsg: '设备不支持 NFC',
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
if (!nfcInstance) {
|
|
611
|
-
uni.showToast({ title: '无连接中的 NFC 标签', icon: 'none' });
|
|
612
|
-
return Promise.reject({
|
|
613
|
-
errMsg: '无连接中的 NFC 标签',
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
try {
|
|
618
|
-
if (nfcInstance.isConnected()) {
|
|
619
|
-
nfcInstance.close();
|
|
620
|
-
}
|
|
621
|
-
// 清空缓存,重置状态
|
|
622
|
-
nfcTag = null;
|
|
623
|
-
nfcInstance = null;
|
|
624
|
-
isConnected.value = false;
|
|
625
|
-
isNdef.value = false;
|
|
626
|
-
clearInterval(checkInterval);
|
|
627
|
-
uni.showToast({ title: 'NFC 连接已关闭', icon: 'none' });
|
|
628
|
-
return Promise.resolve({
|
|
629
|
-
errMsg: 'NFC 连接已关闭',
|
|
630
|
-
});
|
|
631
|
-
} catch (error) {
|
|
632
|
-
uni.showToast({ title: 'NFC 连接关闭失败', icon: 'none' });
|
|
633
|
-
return Promise.reject({
|
|
634
|
-
errMsg: 'NFC 连接关闭失败',
|
|
635
|
-
error,
|
|
636
|
-
});
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
function offHCEMessage() {
|
|
641
|
-
try {
|
|
642
|
-
if (!isSupportNFC.value) {
|
|
643
|
-
uni.showToast({ title: '设备不支持 NFC,无需移除监听', icon: 'none' });
|
|
644
|
-
return true;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// 1. 移除 newintent 事件监听
|
|
648
|
-
plus.globalEvent.removeEventListener('newintent', innerListener);
|
|
649
|
-
|
|
650
|
-
// 2. 停止前台调度,关闭连接
|
|
651
|
-
if (nfcAdapter && isListening.value) {
|
|
652
|
-
nfcAdapter.disableForegroundDispatch(mainActivity);
|
|
653
|
-
}
|
|
654
|
-
if (nfcInstance && nfcInstance.isConnected()) {
|
|
655
|
-
nfcInstance.close();
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
// 3. 清空所有缓存,重置状态
|
|
659
|
-
nfcPendingIntent = null;
|
|
660
|
-
nfcTag = null;
|
|
661
|
-
nfcInstance = null;
|
|
662
|
-
isListening.value = false;
|
|
663
|
-
isConnected.value = false;
|
|
664
|
-
isNdef.value = false;
|
|
665
|
-
clearInterval(checkInterval);
|
|
666
|
-
uni.showToast({ title: 'NFC 监听已移除', icon: 'none' });
|
|
667
|
-
return true;
|
|
668
|
-
} catch (_error) {
|
|
669
|
-
uni.showToast({ title: 'NFC 监听移除失败', icon: 'none' });
|
|
670
|
-
|
|
671
|
-
return false;
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
/**
|
|
676
|
-
* 确保 NFC 已连接
|
|
677
|
-
* @param checkNdef 是否检查 NDEF 支持
|
|
678
|
-
*/
|
|
679
|
-
function ensureConnected(checkNdef = false) {
|
|
680
|
-
if (checkNdef && !isNdef.value) {
|
|
681
|
-
uni.showToast({ title: 'NFC 标签不支持 NDEF', icon: 'none' });
|
|
682
|
-
throw { errMsg: 'NFC 标签不支持 NDEF' };
|
|
683
|
-
}
|
|
684
|
-
if (!nfcInstance) {
|
|
685
|
-
uni.showToast({ title: '请先建立连接', icon: 'none' });
|
|
686
|
-
throw { errMsg: '请先建立连接' };
|
|
687
|
-
}
|
|
688
|
-
if (!isConnected.value) {
|
|
689
|
-
uni.showToast({ title: '请先建立连接', icon: 'none' });
|
|
690
|
-
throw { errMsg: '请先建立连接' };
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* 执行 NDEF 写入操作的通用流程
|
|
696
|
-
* @param createMessage 创建 NdefMessage 的函数
|
|
697
|
-
* @returns Promise
|
|
698
|
-
*/
|
|
699
|
-
async function executeNdefWrite(createMessage: () => any) {
|
|
700
|
-
try {
|
|
701
|
-
ensureConnected(true);
|
|
702
|
-
|
|
703
|
-
uni.showToast({
|
|
704
|
-
title: '开始写入数据,请勿断开连接',
|
|
705
|
-
icon: 'none',
|
|
706
|
-
duration: 3000,
|
|
707
|
-
});
|
|
708
|
-
|
|
709
|
-
const message = createMessage();
|
|
710
|
-
|
|
711
|
-
// 容量检查
|
|
712
|
-
if (maxTransceiveLength < message.getByteArrayLength()) {
|
|
713
|
-
uni.showToast({
|
|
714
|
-
title: '写入数据超出标签容量',
|
|
715
|
-
icon: 'none',
|
|
716
|
-
duration: 3000,
|
|
717
|
-
});
|
|
718
|
-
try {
|
|
719
|
-
nfcInstance.close();
|
|
720
|
-
} catch (_e) {
|
|
721
|
-
// ignore error
|
|
722
|
-
}
|
|
723
|
-
return Promise.reject({ errMsg: '写入数据超出标签容量' });
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
if (nfcInstance.isWritable()) {
|
|
727
|
-
nfcInstance.writeNdefMessage(message);
|
|
728
|
-
nfcInstance.close();
|
|
729
|
-
|
|
730
|
-
uni.showToast({
|
|
731
|
-
title: '数据写入成功',
|
|
732
|
-
icon: 'none',
|
|
733
|
-
duration: 3000,
|
|
734
|
-
});
|
|
735
|
-
return Promise.resolve({ errMsg: '数据写入成功' });
|
|
736
|
-
} else {
|
|
737
|
-
uni.showToast({
|
|
738
|
-
title: 'NFC 标签不允许写入',
|
|
739
|
-
icon: 'none',
|
|
740
|
-
duration: 3000,
|
|
741
|
-
});
|
|
742
|
-
nfcInstance.close();
|
|
743
|
-
return Promise.reject({ errMsg: 'NFC 标签不允许写入' });
|
|
744
|
-
}
|
|
745
|
-
} catch (_error) {
|
|
746
|
-
uni.showToast({
|
|
747
|
-
title: '数据写入失败',
|
|
748
|
-
icon: 'none',
|
|
749
|
-
duration: 3000,
|
|
750
|
-
});
|
|
751
|
-
try {
|
|
752
|
-
nfcInstance?.close();
|
|
753
|
-
} catch (_e) {
|
|
754
|
-
// ignore error
|
|
755
|
-
}
|
|
756
|
-
return Promise.reject({ errMsg: '数据写入失败', error: _error });
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
/**
|
|
761
|
-
* 非 ndef 数据写入
|
|
762
|
-
*
|
|
763
|
-
* TODO: 暂时无法提供通用的写入方法
|
|
764
|
-
*
|
|
765
|
-
* @param {ArrayBuffer} writeData
|
|
766
|
-
* @return {*}
|
|
767
|
-
*/
|
|
768
|
-
function write(writeData: ArrayBuffer) {
|
|
769
|
-
if (isNdef.value) {
|
|
770
|
-
uni.showToast({
|
|
771
|
-
title: 'NDEF 请勿使用该方法',
|
|
772
|
-
icon: 'none',
|
|
773
|
-
});
|
|
774
|
-
return Promise.reject({
|
|
775
|
-
errMsg: 'NDEF 请勿使用该方法',
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
if (!nfcInstance) {
|
|
780
|
-
uni.showToast({
|
|
781
|
-
title: '请先建立连接',
|
|
782
|
-
icon: 'none',
|
|
783
|
-
});
|
|
784
|
-
return Promise.reject({
|
|
785
|
-
errMsg: '请先建立连接',
|
|
786
|
-
});
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
if (!isConnected.value) {
|
|
790
|
-
uni.showToast({
|
|
791
|
-
title: '请先建立连接',
|
|
792
|
-
icon: 'none',
|
|
793
|
-
});
|
|
794
|
-
return Promise.reject({
|
|
795
|
-
errMsg: '请先建立连接',
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
uni.showToast({
|
|
800
|
-
title: '开始写入数据,请勿断开连接',
|
|
801
|
-
icon: 'none',
|
|
802
|
-
});
|
|
803
|
-
|
|
804
|
-
try {
|
|
805
|
-
nfcInstance.connect();
|
|
806
|
-
if (!nfcInstance.isWritable()) {
|
|
807
|
-
uni.showToast({ title: 'NFC 标签不允许写入', icon: 'none' });
|
|
808
|
-
nfcInstance.close();
|
|
809
|
-
return Promise.reject({
|
|
810
|
-
errMsg: 'NFC 标签不允许写入',
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
if (nfcInstance.getMaxTransceiveLength() < writeData.byteLength) {
|
|
814
|
-
uni.showToast({ title: '写入数据超出标签容量', icon: 'none' });
|
|
815
|
-
nfcInstance.close();
|
|
816
|
-
return Promise.reject({
|
|
817
|
-
errMsg: '写入数据超出标签容量',
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
|
-
const result = nfcInstance.transceive(writeData);
|
|
821
|
-
nfcInstance.close();
|
|
822
|
-
uni.showToast({ title: '数据写入成功', icon: 'none' });
|
|
823
|
-
return Promise.resolve({
|
|
824
|
-
errMsg: '数据写入成功',
|
|
825
|
-
data: result,
|
|
826
|
-
});
|
|
827
|
-
} catch (error) {
|
|
828
|
-
uni.showToast({ title: '数据写入失败', icon: 'none' });
|
|
829
|
-
return Promise.reject({
|
|
830
|
-
errMsg: '数据写入失败',
|
|
831
|
-
error,
|
|
832
|
-
});
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
/**
|
|
837
|
-
* 通用的 ndef 写入方法
|
|
838
|
-
*
|
|
839
|
-
* @param {NFC.NdefData} data
|
|
840
|
-
*/
|
|
841
|
-
function writeNdef(data: NFC.NdefRecord[]) {
|
|
842
|
-
return executeNdefWrite(() => {
|
|
843
|
-
const records = data?.map((item) => {
|
|
844
|
-
const tnf = stringToBytes(item.tnf + '');
|
|
845
|
-
const id = item.id ? stringToBytes(item.id) : null;
|
|
846
|
-
const type = stringToBytes(item.type);
|
|
847
|
-
|
|
848
|
-
return new NdefRecord(tnf, type, id, item.payload);
|
|
849
|
-
});
|
|
850
|
-
return new NdefMessage(records);
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
/**
|
|
855
|
-
* 写入 NDEF 文本数据
|
|
856
|
-
*
|
|
857
|
-
* https://developer.android.google.cn/reference/kotlin/android/nfc/NdefRecord?hl=en#createtextrecord
|
|
858
|
-
*
|
|
859
|
-
* @param {string} text
|
|
860
|
-
* @param {string} [language='zh']
|
|
861
|
-
* @return {*}
|
|
862
|
-
*/
|
|
863
|
-
function writeNdefText(text: string, language: string = 'zh') {
|
|
864
|
-
return executeNdefWrite(() => {
|
|
865
|
-
return new NdefMessage([NdefRecord.createTextRecord(language, text)]);
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
/**
|
|
870
|
-
* 写入 NDEF URI 数据
|
|
871
|
-
* https://developer.android.google.cn/reference/kotlin/android/nfc/NdefRecord?hl=en#createuri
|
|
872
|
-
*
|
|
873
|
-
* 会自动根据
|
|
874
|
-
* https://
|
|
875
|
-
* tel:
|
|
876
|
-
* ...
|
|
877
|
-
* 进行区分
|
|
878
|
-
*
|
|
879
|
-
* @param {string} uri
|
|
880
|
-
* @return {*}
|
|
881
|
-
*/
|
|
882
|
-
function writeNdefUri(uri: string) {
|
|
883
|
-
return executeNdefWrite(() => {
|
|
884
|
-
return new NdefMessage([NdefRecord.createUri(uri)]);
|
|
885
|
-
});
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
/**
|
|
889
|
-
* Android 应用包名 写入
|
|
890
|
-
*
|
|
891
|
-
* @param {string} packageName - 数据
|
|
892
|
-
* @param {string} [typeName] - 类型名称,默认为 "a" (Android Application Record)
|
|
893
|
-
* @return {*}
|
|
894
|
-
*/
|
|
895
|
-
function writeNdefAndroidApp(packageName: string) {
|
|
896
|
-
return executeNdefWrite(() => {
|
|
897
|
-
// 创建 Android 应用记录 (AAR - Android Application Record)
|
|
898
|
-
const appRecord = NdefRecord.createApplicationRecord(packageName);
|
|
899
|
-
return new NdefMessage([appRecord]);
|
|
900
|
-
});
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
/**
|
|
904
|
-
* 写入 WiFi 配置到 NFC 标签
|
|
905
|
-
*
|
|
906
|
-
* @param {NFC.WSCConfig} { ssid, password, authType }
|
|
907
|
-
* @return {*}
|
|
908
|
-
*/
|
|
909
|
-
function writeNdefWifi({ ssid, password, authType }: NFC.WSCConfig) {
|
|
910
|
-
return executeNdefWrite(() => {
|
|
911
|
-
const mimeType = 'application/vnd.wfa.wsc';
|
|
912
|
-
const wifiData = generateWSCBytesForAndroid({
|
|
913
|
-
ssid,
|
|
914
|
-
password,
|
|
915
|
-
authType,
|
|
916
|
-
});
|
|
917
|
-
const wifiRecord = NdefRecord.createMime(mimeType, wifiData);
|
|
918
|
-
return new NdefMessage([wifiRecord]);
|
|
919
|
-
});
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
/**
|
|
923
|
-
* 写入 vCard 数据到 NFC 标签
|
|
924
|
-
*
|
|
925
|
-
* @param {NFC.VCardContactInfo} cardInfo
|
|
926
|
-
* @return {*}
|
|
927
|
-
*/
|
|
928
|
-
function writeNdefVcard(cardInfo: NFC.VCardContactInfo) {
|
|
929
|
-
return executeNdefWrite(() => {
|
|
930
|
-
const mimeType = 'text/vcard';
|
|
931
|
-
const cardString = formatCardInfo(cardInfo);
|
|
932
|
-
const cardData = stringToBytes(cardString);
|
|
933
|
-
const cardRecord = NdefRecord.createMime(mimeType, cardData);
|
|
934
|
-
return new NdefMessage([cardRecord]);
|
|
935
|
-
});
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
onMounted(() => {
|
|
939
|
-
initNfcAdapter();
|
|
940
|
-
});
|
|
941
|
-
|
|
942
|
-
onUnmounted(() => {
|
|
943
|
-
stopHCE();
|
|
944
|
-
offHCEMessage();
|
|
945
|
-
});
|
|
946
|
-
|
|
947
|
-
return {
|
|
948
|
-
data,
|
|
949
|
-
isNdef,
|
|
950
|
-
isSupportNFC,
|
|
951
|
-
isListening,
|
|
952
|
-
isConnected,
|
|
953
|
-
nfcInstance,
|
|
954
|
-
startHCE,
|
|
955
|
-
stopHCE,
|
|
956
|
-
connect,
|
|
957
|
-
close,
|
|
958
|
-
write,
|
|
959
|
-
writeNdef,
|
|
960
|
-
writeNdefText,
|
|
961
|
-
writeNdefUri,
|
|
962
|
-
writeNdefAndroidApp,
|
|
963
|
-
writeNdefWifi,
|
|
964
|
-
writeNdefVcard,
|
|
965
|
-
};
|
|
966
|
-
}
|
|
1
|
+
import { onMounted, onUnmounted, ref } from 'vue';
|
|
2
|
+
import {
|
|
3
|
+
formatCardInfo,
|
|
4
|
+
getAndroidTechs,
|
|
5
|
+
getReadWriteStandard,
|
|
6
|
+
getSakHex,
|
|
7
|
+
getSakType,
|
|
8
|
+
getTnfDescription,
|
|
9
|
+
getTypeDescription,
|
|
10
|
+
parseAtqaAndroid,
|
|
11
|
+
parseUniversalTLV,
|
|
12
|
+
parseVCardPayload,
|
|
13
|
+
stringToBytes,
|
|
14
|
+
transformArrayBuffer,
|
|
15
|
+
wifiTLVConfig,
|
|
16
|
+
generateWSCBytesForAndroid,
|
|
17
|
+
} from './utils';
|
|
18
|
+
|
|
19
|
+
// 声明变量,但不立即初始化
|
|
20
|
+
let NfcAdapter: any;
|
|
21
|
+
let _Context: any;
|
|
22
|
+
let _Tag: any;
|
|
23
|
+
let Ndef: any;
|
|
24
|
+
let NfcA: any;
|
|
25
|
+
let NfcB: any;
|
|
26
|
+
let NfcF: any;
|
|
27
|
+
let NfcV: any;
|
|
28
|
+
let _NdefFormat: any;
|
|
29
|
+
let NdefFormatable: any;
|
|
30
|
+
let MifareClassic: any;
|
|
31
|
+
let MifareUltralight: any;
|
|
32
|
+
let IsoDep: any;
|
|
33
|
+
let Intent: any;
|
|
34
|
+
let PendingIntent: any;
|
|
35
|
+
let IntentFilter: any;
|
|
36
|
+
let Settings: any;
|
|
37
|
+
let NdefRecord: any;
|
|
38
|
+
let NdefMessage: any;
|
|
39
|
+
|
|
40
|
+
let INTENT_FLAGS_SINGLE_TOP: any;
|
|
41
|
+
let PENDING_INTENT_FLAGS: any;
|
|
42
|
+
let EXTRA_NDEF_MESSAGES: any;
|
|
43
|
+
let EXTRA_ID: any;
|
|
44
|
+
let EXTRA_TAG: any;
|
|
45
|
+
let _TNF_MIME_MEDIA: any;
|
|
46
|
+
let _ACTION_NFC_SETTINGS: any;
|
|
47
|
+
|
|
48
|
+
let NFC_INTENT_FILTERS: any[] = [];
|
|
49
|
+
|
|
50
|
+
const NFC_TECH_LISTS = [
|
|
51
|
+
['android.nfc.tech.Ndef'],
|
|
52
|
+
['android.nfc.tech.NdefFormatable'],
|
|
53
|
+
['android.nfc.tech.IsoDep'],
|
|
54
|
+
['android.nfc.tech.NfcA'],
|
|
55
|
+
['android.nfc.tech.NfcB'],
|
|
56
|
+
['android.nfc.tech.NfcF'],
|
|
57
|
+
['android.nfc.tech.NfcV'],
|
|
58
|
+
['android.nfc.tech.MifareClassic'],
|
|
59
|
+
['android.nfc.tech.MifareUltralight'],
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// 初始化 Android 类
|
|
63
|
+
function initAndroidClasses() {
|
|
64
|
+
try {
|
|
65
|
+
if (NfcAdapter) return; // 避免重复初始化
|
|
66
|
+
|
|
67
|
+
NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');
|
|
68
|
+
_Context = plus.android.importClass('android.content.Context');
|
|
69
|
+
_Tag = plus.android.importClass('android.nfc.Tag');
|
|
70
|
+
Ndef = plus.android.importClass('android.nfc.tech.Ndef');
|
|
71
|
+
NfcA = plus.android.importClass('android.nfc.tech.NfcA');
|
|
72
|
+
NfcB = plus.android.importClass('android.nfc.tech.NfcB');
|
|
73
|
+
NfcF = plus.android.importClass('android.nfc.tech.NfcF');
|
|
74
|
+
NfcV = plus.android.importClass('android.nfc.tech.NfcV');
|
|
75
|
+
_NdefFormat = plus.android.importClass('android.nfc.tech.NdefFormat');
|
|
76
|
+
NdefFormatable = plus.android.importClass(
|
|
77
|
+
'android.nfc.tech.NdefFormatable',
|
|
78
|
+
);
|
|
79
|
+
MifareClassic = plus.android.importClass('android.nfc.tech.MifareClassic');
|
|
80
|
+
MifareUltralight = plus.android.importClass(
|
|
81
|
+
'android.nfc.tech.MifareUltralight',
|
|
82
|
+
);
|
|
83
|
+
IsoDep = plus.android.importClass('android.nfc.tech.IsoDep');
|
|
84
|
+
Intent = plus.android.importClass('android.content.Intent');
|
|
85
|
+
PendingIntent = plus.android.importClass('android.app.PendingIntent');
|
|
86
|
+
IntentFilter = plus.android.importClass('android.content.IntentFilter');
|
|
87
|
+
Settings = plus.android.importClass('android.provider.Settings');
|
|
88
|
+
NdefRecord = plus.android.importClass('android.nfc.NdefRecord');
|
|
89
|
+
NdefMessage = plus.android.importClass('android.nfc.NdefMessage');
|
|
90
|
+
|
|
91
|
+
INTENT_FLAGS_SINGLE_TOP = Intent.FLAG_ACTIVITY_SINGLE_TOP;
|
|
92
|
+
PENDING_INTENT_FLAGS = PendingIntent.FLAG_MUTABLE;
|
|
93
|
+
|
|
94
|
+
EXTRA_NDEF_MESSAGES = NfcAdapter.EXTRA_NDEF_MESSAGES;
|
|
95
|
+
EXTRA_ID = NfcAdapter.EXTRA_ID;
|
|
96
|
+
EXTRA_TAG = NfcAdapter.EXTRA_TAG;
|
|
97
|
+
|
|
98
|
+
_TNF_MIME_MEDIA = NdefRecord.TNF_MIME_MEDIA;
|
|
99
|
+
_ACTION_NFC_SETTINGS = Settings.ACTION_NFC_SETTINGS;
|
|
100
|
+
|
|
101
|
+
NFC_INTENT_FILTERS = [
|
|
102
|
+
NfcAdapter.ACTION_NDEF_DISCOVERED,
|
|
103
|
+
NfcAdapter.ACTION_TECH_DISCOVERED,
|
|
104
|
+
NfcAdapter.ACTION_TAG_DISCOVERED,
|
|
105
|
+
];
|
|
106
|
+
} catch (e) {
|
|
107
|
+
console.error('Core: initAndroidClasses error', e);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export default function useNFCAndroid(
|
|
112
|
+
listener: NFC.Listener,
|
|
113
|
+
options?: NFC.NfcOption,
|
|
114
|
+
): NFC.NfcResult {
|
|
115
|
+
/** 是否支持 nfc */
|
|
116
|
+
const isSupportNFC = ref<boolean | undefined>(false);
|
|
117
|
+
/** 是否监听中 */
|
|
118
|
+
const isListening = ref<boolean>(false);
|
|
119
|
+
/** 是否已连接 */
|
|
120
|
+
const isConnected = ref<boolean>(false);
|
|
121
|
+
/** nfc 数据 */
|
|
122
|
+
const data = ref<NFC.Result>({
|
|
123
|
+
id: new ArrayBuffer(0),
|
|
124
|
+
techs: [],
|
|
125
|
+
byteArray: [],
|
|
126
|
+
hexArray: [],
|
|
127
|
+
hexNumberArray: [],
|
|
128
|
+
hexString: '',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
/** ndef 写入方式比较特殊,需要特殊处理 */
|
|
132
|
+
const isNdef = ref(false);
|
|
133
|
+
|
|
134
|
+
// 延迟获取 mainActivity,确保 plus 已就绪
|
|
135
|
+
let mainActivity: any = null;
|
|
136
|
+
|
|
137
|
+
onMounted(() => {
|
|
138
|
+
initAndroidClasses();
|
|
139
|
+
try {
|
|
140
|
+
mainActivity = plus.android.runtimeMainActivity();
|
|
141
|
+
initNfcAdapter();
|
|
142
|
+
} catch (e) {
|
|
143
|
+
console.error('Core: failed to init NFC adapter', e);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
let checkInterval: any = null;
|
|
148
|
+
|
|
149
|
+
let nfcAdapter: NFC.Adapter | null = null;
|
|
150
|
+
let nfcPendingIntent: any = null;
|
|
151
|
+
let nfcTag: any = null;
|
|
152
|
+
let nfcInstance: any = null;
|
|
153
|
+
|
|
154
|
+
let maxTransceiveLength = 0;
|
|
155
|
+
|
|
156
|
+
function checkConnected() {
|
|
157
|
+
checkInterval = setInterval(() => {
|
|
158
|
+
if (!nfcAdapter) {
|
|
159
|
+
isConnected.value = false;
|
|
160
|
+
clearInterval(checkInterval);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (!nfcAdapter.isEnabled()) {
|
|
165
|
+
isConnected.value = false;
|
|
166
|
+
clearInterval(checkInterval);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (!nfcInstance) {
|
|
170
|
+
isConnected.value = false;
|
|
171
|
+
clearInterval(checkInterval);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (nfcInstance.isConnected()) {
|
|
176
|
+
isConnected.value = true;
|
|
177
|
+
} else {
|
|
178
|
+
isConnected.value = false;
|
|
179
|
+
clearInterval(checkInterval);
|
|
180
|
+
}
|
|
181
|
+
}, options?.checkConnectedDelay ?? 500);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function getInstance(techs: NFC.NfcType[], needNdef?: boolean) {
|
|
185
|
+
let type = 'Ndef';
|
|
186
|
+
if (needNdef) {
|
|
187
|
+
type = 'Ndef';
|
|
188
|
+
} else {
|
|
189
|
+
type = techs.filter((tech) => tech != 'Ndef' && tech != 'NDEF')?.[0];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
switch (type) {
|
|
193
|
+
case 'NFC-A':
|
|
194
|
+
return NfcA.get(nfcTag);
|
|
195
|
+
case 'NFC-B':
|
|
196
|
+
return NfcB.get(nfcTag);
|
|
197
|
+
case 'NFC-F':
|
|
198
|
+
return NfcF.get(nfcTag);
|
|
199
|
+
case 'NFC-V':
|
|
200
|
+
return NfcV.get(nfcTag);
|
|
201
|
+
case 'MIFARE Classic':
|
|
202
|
+
return MifareClassic.get(nfcTag);
|
|
203
|
+
case 'MIFARE Ultralight':
|
|
204
|
+
return MifareUltralight.get(nfcTag);
|
|
205
|
+
case 'Ndef':
|
|
206
|
+
isNdef.value = true;
|
|
207
|
+
return Ndef.get(nfcTag);
|
|
208
|
+
case 'Ndef Formatable':
|
|
209
|
+
return NdefFormatable.get(nfcTag);
|
|
210
|
+
case 'ISO-DEP':
|
|
211
|
+
return IsoDep.get(nfcTag);
|
|
212
|
+
default:
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function innerListener() {
|
|
218
|
+
try {
|
|
219
|
+
const intent = mainActivity.getIntent();
|
|
220
|
+
if (!intent) {
|
|
221
|
+
uni.showToast({ title: 'NFC 数据解析失败', icon: 'none' });
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// 获取id
|
|
226
|
+
const id = intent.getByteArrayExtra(EXTRA_ID);
|
|
227
|
+
|
|
228
|
+
const transform = transformArrayBuffer(id);
|
|
229
|
+
|
|
230
|
+
let techs: NFC.NfcType[] = [];
|
|
231
|
+
|
|
232
|
+
let sak = 0;
|
|
233
|
+
let sakHex = '';
|
|
234
|
+
let sakType = undefined;
|
|
235
|
+
let atqaInfo = {
|
|
236
|
+
uidType: 0,
|
|
237
|
+
storageSize: 0,
|
|
238
|
+
manufacturer: 0,
|
|
239
|
+
cardFeatures: 0,
|
|
240
|
+
reserved: 0,
|
|
241
|
+
};
|
|
242
|
+
let readWriteStandard: string[] = [];
|
|
243
|
+
let sectorCount = 0;
|
|
244
|
+
let blockCount = 0;
|
|
245
|
+
let messages: any = [];
|
|
246
|
+
nfcTag = intent.getParcelableExtra(EXTRA_TAG); // 先获取 Tag 实例
|
|
247
|
+
|
|
248
|
+
if (nfcTag) {
|
|
249
|
+
// 核心方法:通过 Tag.getTechList() 获取原生技术列表数组
|
|
250
|
+
const nativeTechList = nfcTag.getTechList();
|
|
251
|
+
// 转换为可直接使用的 string 数组(兼容原生返回格式)
|
|
252
|
+
techs = Array.isArray(nativeTechList) ? nativeTechList : [];
|
|
253
|
+
|
|
254
|
+
techs = getAndroidTechs(techs);
|
|
255
|
+
|
|
256
|
+
nfcInstance = getInstance(techs, true);
|
|
257
|
+
|
|
258
|
+
if (!nfcInstance) {
|
|
259
|
+
uni.showToast({ title: 'NFC 实例获取失败', icon: 'none' });
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// 一定要连接
|
|
264
|
+
nfcInstance?.connect?.();
|
|
265
|
+
|
|
266
|
+
if (isNdef.value) {
|
|
267
|
+
const otherInstance = getInstance(techs);
|
|
268
|
+
maxTransceiveLength = otherInstance?.getMaxTransceiveLength?.() ?? 0;
|
|
269
|
+
} else {
|
|
270
|
+
maxTransceiveLength = nfcInstance?.getMaxTransceiveLength?.() ?? 0;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
readWriteStandard = getReadWriteStandard(techs);
|
|
274
|
+
|
|
275
|
+
sectorCount = nfcInstance?.getSectorCount?.();
|
|
276
|
+
|
|
277
|
+
blockCount = nfcInstance?.getBlockCount?.();
|
|
278
|
+
|
|
279
|
+
const ndefMessage = intent.getParcelableArrayExtra(EXTRA_NDEF_MESSAGES);
|
|
280
|
+
|
|
281
|
+
if (ndefMessage && ndefMessage.length > 0) {
|
|
282
|
+
let records = ndefMessage?.[0]?.getRecords?.();
|
|
283
|
+
|
|
284
|
+
records = records.map((record: any) => {
|
|
285
|
+
const idObject = record?.getId?.();
|
|
286
|
+
|
|
287
|
+
const id = idObject
|
|
288
|
+
? plus.android.invoke(idObject, 'toString')
|
|
289
|
+
: '';
|
|
290
|
+
|
|
291
|
+
const tnfObject = record?.getTnf?.();
|
|
292
|
+
const tnf = tnfObject
|
|
293
|
+
? plus.android.invoke(tnfObject, 'toString')
|
|
294
|
+
: '';
|
|
295
|
+
const tnfDescription = getTnfDescription(tnf);
|
|
296
|
+
|
|
297
|
+
const payloadByte = record?.getPayload?.();
|
|
298
|
+
|
|
299
|
+
const typeObject = record?.getType?.();
|
|
300
|
+
const type = typeObject
|
|
301
|
+
? (plus.android.newObject('java.lang.String', typeObject) as any)
|
|
302
|
+
: '';
|
|
303
|
+
const typeDescription = getTypeDescription(
|
|
304
|
+
type as string,
|
|
305
|
+
payloadByte,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
let payload: any = payloadByte
|
|
309
|
+
? plus.android.newObject('java.lang.String', payloadByte)
|
|
310
|
+
: '';
|
|
311
|
+
if (type === 'application/vnd.wfa.wsc') {
|
|
312
|
+
payload = parseUniversalTLV(payloadByte, wifiTLVConfig);
|
|
313
|
+
} else if (type === 'text/vcard') {
|
|
314
|
+
payload = parseVCardPayload(payload);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
id,
|
|
319
|
+
tnf,
|
|
320
|
+
tnfDescription,
|
|
321
|
+
type,
|
|
322
|
+
typeDescription,
|
|
323
|
+
payload,
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
messages = [
|
|
327
|
+
{
|
|
328
|
+
records,
|
|
329
|
+
},
|
|
330
|
+
];
|
|
331
|
+
} else {
|
|
332
|
+
messages = [];
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (techs.includes('NFC-A')) {
|
|
336
|
+
// NFC-A 标签的 SAK 信息
|
|
337
|
+
const nfcAInstance = NfcA.get(nfcTag);
|
|
338
|
+
const sakShortObject =
|
|
339
|
+
plus.android.invoke(nfcAInstance, 'getSak') ?? 0;
|
|
340
|
+
|
|
341
|
+
const sakStr = plus.android.invoke(sakShortObject, 'toString');
|
|
342
|
+
|
|
343
|
+
sak = Number(sakStr) || 0;
|
|
344
|
+
|
|
345
|
+
sakType = getSakType(sak);
|
|
346
|
+
|
|
347
|
+
sakHex = getSakHex(sak);
|
|
348
|
+
|
|
349
|
+
const atqa = plus.android.invoke(nfcAInstance, 'getAtqa');
|
|
350
|
+
|
|
351
|
+
atqaInfo = parseAtqaAndroid(atqa);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// 返回数据
|
|
356
|
+
data.value = {
|
|
357
|
+
...data.value,
|
|
358
|
+
...transform,
|
|
359
|
+
...atqaInfo,
|
|
360
|
+
id,
|
|
361
|
+
sak,
|
|
362
|
+
sakHex,
|
|
363
|
+
sakType,
|
|
364
|
+
techs,
|
|
365
|
+
messages,
|
|
366
|
+
maxTransceiveLength,
|
|
367
|
+
readWriteStandard,
|
|
368
|
+
sectorCount,
|
|
369
|
+
blockCount,
|
|
370
|
+
};
|
|
371
|
+
// 回调通知外部
|
|
372
|
+
listener(data.value);
|
|
373
|
+
// 检查链接状态
|
|
374
|
+
checkConnected();
|
|
375
|
+
|
|
376
|
+
// 可将改行去除
|
|
377
|
+
uni?.__dev_tool_nfc_collection__?.(data.value);
|
|
378
|
+
} catch (_error) {
|
|
379
|
+
console.log('error: ', _error);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function initNfcAdapter() {
|
|
384
|
+
try {
|
|
385
|
+
if (!mainActivity) {
|
|
386
|
+
uni.showToast({ title: '无法获取主 Activity 实例', icon: 'none' });
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
nfcAdapter = NfcAdapter.getDefaultAdapter(mainActivity);
|
|
391
|
+
|
|
392
|
+
// 1. 设备不支持 NFC
|
|
393
|
+
if (!nfcAdapter) {
|
|
394
|
+
isSupportNFC.value = false;
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// 2. NFC 功能未开启
|
|
399
|
+
if (!nfcAdapter.isEnabled()) {
|
|
400
|
+
isSupportNFC.value = false;
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// 3. 初始化成功,注册监听
|
|
405
|
+
isSupportNFC.value = true;
|
|
406
|
+
} catch (_error) {
|
|
407
|
+
isSupportNFC.value = false;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function startHCE() {
|
|
412
|
+
if (!isSupportNFC.value) {
|
|
413
|
+
uni.showToast({
|
|
414
|
+
title: '设备不支持 NFC',
|
|
415
|
+
icon: 'none',
|
|
416
|
+
});
|
|
417
|
+
return Promise.reject({
|
|
418
|
+
errMsg: '设备不支持 NFC',
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
// 前置校验
|
|
422
|
+
if (!nfcAdapter) {
|
|
423
|
+
uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
|
|
424
|
+
return Promise.reject({
|
|
425
|
+
errMsg: '请先初始化 NFC 适配器 NFC',
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
//
|
|
429
|
+
if (isListening.value) {
|
|
430
|
+
uni.showToast({ title: 'NFC 监听已开启,无需重复操作', icon: 'none' });
|
|
431
|
+
return Promise.reject({
|
|
432
|
+
errMsg: 'NFC 监听已开启,无需重复操作',
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
try {
|
|
437
|
+
// 1. 注册 newintent 事件监听
|
|
438
|
+
plus.globalEvent.addEventListener('newintent', innerListener);
|
|
439
|
+
|
|
440
|
+
plus.globalEvent.addEventListener('resume', () => {
|
|
441
|
+
if (nfcAdapter) {
|
|
442
|
+
const filters = NFC_INTENT_FILTERS.map(
|
|
443
|
+
(filter) => new IntentFilter(filter),
|
|
444
|
+
);
|
|
445
|
+
nfcAdapter?.enableForegroundDispatch(
|
|
446
|
+
mainActivity,
|
|
447
|
+
nfcPendingIntent,
|
|
448
|
+
filters,
|
|
449
|
+
NFC_TECH_LISTS,
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
plus.globalEvent.addEventListener('pause', () => {
|
|
455
|
+
if (nfcAdapter) {
|
|
456
|
+
nfcAdapter?.disableForegroundDispatch(mainActivity);
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// 2. 构建前台调度 PendingIntent(缓存实例,避免重复创建)
|
|
461
|
+
if (!nfcPendingIntent) {
|
|
462
|
+
const intent = new Intent(mainActivity, mainActivity.getClass());
|
|
463
|
+
intent.addFlags(INTENT_FLAGS_SINGLE_TOP);
|
|
464
|
+
nfcPendingIntent = PendingIntent.getActivity(
|
|
465
|
+
mainActivity,
|
|
466
|
+
0,
|
|
467
|
+
intent,
|
|
468
|
+
PENDING_INTENT_FLAGS,
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// 3. 构建 Intent 过滤器
|
|
473
|
+
const filters = NFC_INTENT_FILTERS.map(
|
|
474
|
+
(filter) => new IntentFilter(filter),
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
// 4. 启用前台调度(核心:App 前台优先捕获 NFC 事件)
|
|
478
|
+
nfcAdapter?.enableForegroundDispatch(
|
|
479
|
+
mainActivity,
|
|
480
|
+
nfcPendingIntent,
|
|
481
|
+
filters,
|
|
482
|
+
NFC_TECH_LISTS,
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
// 5. 更新监听状态
|
|
486
|
+
isListening.value = true;
|
|
487
|
+
uni.showToast({
|
|
488
|
+
title: '开始监听NFC',
|
|
489
|
+
icon: 'none',
|
|
490
|
+
});
|
|
491
|
+
return Promise.reject({
|
|
492
|
+
errMsg: '开始监听NFC',
|
|
493
|
+
});
|
|
494
|
+
} catch (_error) {
|
|
495
|
+
uni.showToast({ title: 'NFC 监听开启失败', icon: 'none' });
|
|
496
|
+
isListening.value = false;
|
|
497
|
+
return Promise.reject({
|
|
498
|
+
errMsg: 'NFC 监听开启失败',
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function stopHCE() {
|
|
504
|
+
// 前置校验
|
|
505
|
+
if (!isSupportNFC.value) {
|
|
506
|
+
uni.showToast({
|
|
507
|
+
title: '设备不支持 NFC',
|
|
508
|
+
icon: 'none',
|
|
509
|
+
});
|
|
510
|
+
return Promise.reject({
|
|
511
|
+
errMsg: '设备不支持 NFC',
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
// 前置校验
|
|
515
|
+
if (!nfcAdapter) {
|
|
516
|
+
uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
|
|
517
|
+
return Promise.reject({
|
|
518
|
+
errMsg: '请先初始化 NFC 适配器',
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
//
|
|
522
|
+
if (!isListening.value) {
|
|
523
|
+
uni.showToast({ title: 'NFC 监听已关闭,无需重复操作', icon: 'none' });
|
|
524
|
+
|
|
525
|
+
return Promise.reject({
|
|
526
|
+
errMsg: 'NFC 监听已关闭,无需重复操作',
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
try {
|
|
531
|
+
// 1. 禁用前台调度
|
|
532
|
+
nfcAdapter.disableForegroundDispatch(mainActivity);
|
|
533
|
+
// 2. 更新监听状态
|
|
534
|
+
isListening.value = false;
|
|
535
|
+
isConnected.value = false;
|
|
536
|
+
uni.showToast({
|
|
537
|
+
title: '停止监听NFC',
|
|
538
|
+
icon: 'none',
|
|
539
|
+
});
|
|
540
|
+
clearInterval(checkInterval);
|
|
541
|
+
return Promise.resolve({
|
|
542
|
+
errMsg: '停止监听NFC',
|
|
543
|
+
});
|
|
544
|
+
} catch (_error) {
|
|
545
|
+
uni.showToast({ title: 'NFC 监听停止失败', icon: 'error' });
|
|
546
|
+
return Promise.resolve({
|
|
547
|
+
errMsg: 'NFC 监听停止失败',
|
|
548
|
+
error: _error,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function connect() {
|
|
554
|
+
if (!isSupportNFC.value) {
|
|
555
|
+
uni.showToast({ title: '设备不支持 NFC', icon: 'none' });
|
|
556
|
+
return Promise.reject({
|
|
557
|
+
errMsg: '设备不支持 NFC',
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (!nfcInstance) {
|
|
562
|
+
uni.showToast({ title: '请先靠近 NFC 标签', icon: 'none' });
|
|
563
|
+
return Promise.reject({
|
|
564
|
+
errMsg: '请先靠近 NFC 标签',
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (!isListening.value) {
|
|
569
|
+
uni.showToast({ title: '请先开启前台调度监听', icon: 'none' });
|
|
570
|
+
return Promise.reject({
|
|
571
|
+
errMsg: '请先开启前台调度监听',
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
try {
|
|
576
|
+
checkConnected();
|
|
577
|
+
if (!nfcInstance.isConnected()) {
|
|
578
|
+
// 补充连接状态判断
|
|
579
|
+
nfcInstance.connect();
|
|
580
|
+
isConnected.value = true;
|
|
581
|
+
uni.showToast({ title: 'NFC 连接成功', icon: 'none' });
|
|
582
|
+
return Promise.resolve({
|
|
583
|
+
errMsg: 'NFC 连接成功',
|
|
584
|
+
});
|
|
585
|
+
} else {
|
|
586
|
+
isConnected.value = true;
|
|
587
|
+
uni.showToast({ title: 'NFC 已处于连接状态', icon: 'none' });
|
|
588
|
+
return Promise.reject({
|
|
589
|
+
errMsg: 'NFC 已处于连接状态',
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
} catch (error) {
|
|
593
|
+
uni.showToast({ title: 'NFC 连接失败', icon: 'none' });
|
|
594
|
+
isConnected.value = false;
|
|
595
|
+
return Promise.reject({
|
|
596
|
+
errMsg: 'NFC 连接失败',
|
|
597
|
+
error,
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function close() {
|
|
603
|
+
if (!isSupportNFC.value) {
|
|
604
|
+
uni.showToast({ title: '设备不支持 NFC', icon: 'none' });
|
|
605
|
+
return Promise.reject({
|
|
606
|
+
errMsg: '设备不支持 NFC',
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (!nfcInstance) {
|
|
611
|
+
uni.showToast({ title: '无连接中的 NFC 标签', icon: 'none' });
|
|
612
|
+
return Promise.reject({
|
|
613
|
+
errMsg: '无连接中的 NFC 标签',
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
try {
|
|
618
|
+
if (nfcInstance.isConnected()) {
|
|
619
|
+
nfcInstance.close();
|
|
620
|
+
}
|
|
621
|
+
// 清空缓存,重置状态
|
|
622
|
+
nfcTag = null;
|
|
623
|
+
nfcInstance = null;
|
|
624
|
+
isConnected.value = false;
|
|
625
|
+
isNdef.value = false;
|
|
626
|
+
clearInterval(checkInterval);
|
|
627
|
+
uni.showToast({ title: 'NFC 连接已关闭', icon: 'none' });
|
|
628
|
+
return Promise.resolve({
|
|
629
|
+
errMsg: 'NFC 连接已关闭',
|
|
630
|
+
});
|
|
631
|
+
} catch (error) {
|
|
632
|
+
uni.showToast({ title: 'NFC 连接关闭失败', icon: 'none' });
|
|
633
|
+
return Promise.reject({
|
|
634
|
+
errMsg: 'NFC 连接关闭失败',
|
|
635
|
+
error,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function offHCEMessage() {
|
|
641
|
+
try {
|
|
642
|
+
if (!isSupportNFC.value) {
|
|
643
|
+
uni.showToast({ title: '设备不支持 NFC,无需移除监听', icon: 'none' });
|
|
644
|
+
return true;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// 1. 移除 newintent 事件监听
|
|
648
|
+
plus.globalEvent.removeEventListener('newintent', innerListener);
|
|
649
|
+
|
|
650
|
+
// 2. 停止前台调度,关闭连接
|
|
651
|
+
if (nfcAdapter && isListening.value) {
|
|
652
|
+
nfcAdapter.disableForegroundDispatch(mainActivity);
|
|
653
|
+
}
|
|
654
|
+
if (nfcInstance && nfcInstance.isConnected()) {
|
|
655
|
+
nfcInstance.close();
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// 3. 清空所有缓存,重置状态
|
|
659
|
+
nfcPendingIntent = null;
|
|
660
|
+
nfcTag = null;
|
|
661
|
+
nfcInstance = null;
|
|
662
|
+
isListening.value = false;
|
|
663
|
+
isConnected.value = false;
|
|
664
|
+
isNdef.value = false;
|
|
665
|
+
clearInterval(checkInterval);
|
|
666
|
+
uni.showToast({ title: 'NFC 监听已移除', icon: 'none' });
|
|
667
|
+
return true;
|
|
668
|
+
} catch (_error) {
|
|
669
|
+
uni.showToast({ title: 'NFC 监听移除失败', icon: 'none' });
|
|
670
|
+
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* 确保 NFC 已连接
|
|
677
|
+
* @param checkNdef 是否检查 NDEF 支持
|
|
678
|
+
*/
|
|
679
|
+
function ensureConnected(checkNdef = false) {
|
|
680
|
+
if (checkNdef && !isNdef.value) {
|
|
681
|
+
uni.showToast({ title: 'NFC 标签不支持 NDEF', icon: 'none' });
|
|
682
|
+
throw { errMsg: 'NFC 标签不支持 NDEF' };
|
|
683
|
+
}
|
|
684
|
+
if (!nfcInstance) {
|
|
685
|
+
uni.showToast({ title: '请先建立连接', icon: 'none' });
|
|
686
|
+
throw { errMsg: '请先建立连接' };
|
|
687
|
+
}
|
|
688
|
+
if (!isConnected.value) {
|
|
689
|
+
uni.showToast({ title: '请先建立连接', icon: 'none' });
|
|
690
|
+
throw { errMsg: '请先建立连接' };
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* 执行 NDEF 写入操作的通用流程
|
|
696
|
+
* @param createMessage 创建 NdefMessage 的函数
|
|
697
|
+
* @returns Promise
|
|
698
|
+
*/
|
|
699
|
+
async function executeNdefWrite(createMessage: () => any) {
|
|
700
|
+
try {
|
|
701
|
+
ensureConnected(true);
|
|
702
|
+
|
|
703
|
+
uni.showToast({
|
|
704
|
+
title: '开始写入数据,请勿断开连接',
|
|
705
|
+
icon: 'none',
|
|
706
|
+
duration: 3000,
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
const message = createMessage();
|
|
710
|
+
|
|
711
|
+
// 容量检查
|
|
712
|
+
if (maxTransceiveLength < message.getByteArrayLength()) {
|
|
713
|
+
uni.showToast({
|
|
714
|
+
title: '写入数据超出标签容量',
|
|
715
|
+
icon: 'none',
|
|
716
|
+
duration: 3000,
|
|
717
|
+
});
|
|
718
|
+
try {
|
|
719
|
+
nfcInstance.close();
|
|
720
|
+
} catch (_e) {
|
|
721
|
+
// ignore error
|
|
722
|
+
}
|
|
723
|
+
return Promise.reject({ errMsg: '写入数据超出标签容量' });
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
if (nfcInstance.isWritable()) {
|
|
727
|
+
nfcInstance.writeNdefMessage(message);
|
|
728
|
+
nfcInstance.close();
|
|
729
|
+
|
|
730
|
+
uni.showToast({
|
|
731
|
+
title: '数据写入成功',
|
|
732
|
+
icon: 'none',
|
|
733
|
+
duration: 3000,
|
|
734
|
+
});
|
|
735
|
+
return Promise.resolve({ errMsg: '数据写入成功' });
|
|
736
|
+
} else {
|
|
737
|
+
uni.showToast({
|
|
738
|
+
title: 'NFC 标签不允许写入',
|
|
739
|
+
icon: 'none',
|
|
740
|
+
duration: 3000,
|
|
741
|
+
});
|
|
742
|
+
nfcInstance.close();
|
|
743
|
+
return Promise.reject({ errMsg: 'NFC 标签不允许写入' });
|
|
744
|
+
}
|
|
745
|
+
} catch (_error) {
|
|
746
|
+
uni.showToast({
|
|
747
|
+
title: '数据写入失败',
|
|
748
|
+
icon: 'none',
|
|
749
|
+
duration: 3000,
|
|
750
|
+
});
|
|
751
|
+
try {
|
|
752
|
+
nfcInstance?.close();
|
|
753
|
+
} catch (_e) {
|
|
754
|
+
// ignore error
|
|
755
|
+
}
|
|
756
|
+
return Promise.reject({ errMsg: '数据写入失败', error: _error });
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* 非 ndef 数据写入
|
|
762
|
+
*
|
|
763
|
+
* TODO: 暂时无法提供通用的写入方法
|
|
764
|
+
*
|
|
765
|
+
* @param {ArrayBuffer} writeData
|
|
766
|
+
* @return {*}
|
|
767
|
+
*/
|
|
768
|
+
function write(writeData: ArrayBuffer) {
|
|
769
|
+
if (isNdef.value) {
|
|
770
|
+
uni.showToast({
|
|
771
|
+
title: 'NDEF 请勿使用该方法',
|
|
772
|
+
icon: 'none',
|
|
773
|
+
});
|
|
774
|
+
return Promise.reject({
|
|
775
|
+
errMsg: 'NDEF 请勿使用该方法',
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if (!nfcInstance) {
|
|
780
|
+
uni.showToast({
|
|
781
|
+
title: '请先建立连接',
|
|
782
|
+
icon: 'none',
|
|
783
|
+
});
|
|
784
|
+
return Promise.reject({
|
|
785
|
+
errMsg: '请先建立连接',
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
if (!isConnected.value) {
|
|
790
|
+
uni.showToast({
|
|
791
|
+
title: '请先建立连接',
|
|
792
|
+
icon: 'none',
|
|
793
|
+
});
|
|
794
|
+
return Promise.reject({
|
|
795
|
+
errMsg: '请先建立连接',
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
uni.showToast({
|
|
800
|
+
title: '开始写入数据,请勿断开连接',
|
|
801
|
+
icon: 'none',
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
try {
|
|
805
|
+
nfcInstance.connect();
|
|
806
|
+
if (!nfcInstance.isWritable()) {
|
|
807
|
+
uni.showToast({ title: 'NFC 标签不允许写入', icon: 'none' });
|
|
808
|
+
nfcInstance.close();
|
|
809
|
+
return Promise.reject({
|
|
810
|
+
errMsg: 'NFC 标签不允许写入',
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
if (nfcInstance.getMaxTransceiveLength() < writeData.byteLength) {
|
|
814
|
+
uni.showToast({ title: '写入数据超出标签容量', icon: 'none' });
|
|
815
|
+
nfcInstance.close();
|
|
816
|
+
return Promise.reject({
|
|
817
|
+
errMsg: '写入数据超出标签容量',
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
const result = nfcInstance.transceive(writeData);
|
|
821
|
+
nfcInstance.close();
|
|
822
|
+
uni.showToast({ title: '数据写入成功', icon: 'none' });
|
|
823
|
+
return Promise.resolve({
|
|
824
|
+
errMsg: '数据写入成功',
|
|
825
|
+
data: result,
|
|
826
|
+
});
|
|
827
|
+
} catch (error) {
|
|
828
|
+
uni.showToast({ title: '数据写入失败', icon: 'none' });
|
|
829
|
+
return Promise.reject({
|
|
830
|
+
errMsg: '数据写入失败',
|
|
831
|
+
error,
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* 通用的 ndef 写入方法
|
|
838
|
+
*
|
|
839
|
+
* @param {NFC.NdefData} data
|
|
840
|
+
*/
|
|
841
|
+
function writeNdef(data: NFC.NdefRecord[]) {
|
|
842
|
+
return executeNdefWrite(() => {
|
|
843
|
+
const records = data?.map((item) => {
|
|
844
|
+
const tnf = stringToBytes(item.tnf + '');
|
|
845
|
+
const id = item.id ? stringToBytes(item.id) : null;
|
|
846
|
+
const type = stringToBytes(item.type);
|
|
847
|
+
|
|
848
|
+
return new NdefRecord(tnf, type, id, item.payload);
|
|
849
|
+
});
|
|
850
|
+
return new NdefMessage(records);
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* 写入 NDEF 文本数据
|
|
856
|
+
*
|
|
857
|
+
* https://developer.android.google.cn/reference/kotlin/android/nfc/NdefRecord?hl=en#createtextrecord
|
|
858
|
+
*
|
|
859
|
+
* @param {string} text
|
|
860
|
+
* @param {string} [language='zh']
|
|
861
|
+
* @return {*}
|
|
862
|
+
*/
|
|
863
|
+
function writeNdefText(text: string, language: string = 'zh') {
|
|
864
|
+
return executeNdefWrite(() => {
|
|
865
|
+
return new NdefMessage([NdefRecord.createTextRecord(language, text)]);
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* 写入 NDEF URI 数据
|
|
871
|
+
* https://developer.android.google.cn/reference/kotlin/android/nfc/NdefRecord?hl=en#createuri
|
|
872
|
+
*
|
|
873
|
+
* 会自动根据
|
|
874
|
+
* https://
|
|
875
|
+
* tel:
|
|
876
|
+
* ...
|
|
877
|
+
* 进行区分
|
|
878
|
+
*
|
|
879
|
+
* @param {string} uri
|
|
880
|
+
* @return {*}
|
|
881
|
+
*/
|
|
882
|
+
function writeNdefUri(uri: string) {
|
|
883
|
+
return executeNdefWrite(() => {
|
|
884
|
+
return new NdefMessage([NdefRecord.createUri(uri)]);
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* Android 应用包名 写入
|
|
890
|
+
*
|
|
891
|
+
* @param {string} packageName - 数据
|
|
892
|
+
* @param {string} [typeName] - 类型名称,默认为 "a" (Android Application Record)
|
|
893
|
+
* @return {*}
|
|
894
|
+
*/
|
|
895
|
+
function writeNdefAndroidApp(packageName: string) {
|
|
896
|
+
return executeNdefWrite(() => {
|
|
897
|
+
// 创建 Android 应用记录 (AAR - Android Application Record)
|
|
898
|
+
const appRecord = NdefRecord.createApplicationRecord(packageName);
|
|
899
|
+
return new NdefMessage([appRecord]);
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* 写入 WiFi 配置到 NFC 标签
|
|
905
|
+
*
|
|
906
|
+
* @param {NFC.WSCConfig} { ssid, password, authType }
|
|
907
|
+
* @return {*}
|
|
908
|
+
*/
|
|
909
|
+
function writeNdefWifi({ ssid, password, authType }: NFC.WSCConfig) {
|
|
910
|
+
return executeNdefWrite(() => {
|
|
911
|
+
const mimeType = 'application/vnd.wfa.wsc';
|
|
912
|
+
const wifiData = generateWSCBytesForAndroid({
|
|
913
|
+
ssid,
|
|
914
|
+
password,
|
|
915
|
+
authType,
|
|
916
|
+
});
|
|
917
|
+
const wifiRecord = NdefRecord.createMime(mimeType, wifiData);
|
|
918
|
+
return new NdefMessage([wifiRecord]);
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* 写入 vCard 数据到 NFC 标签
|
|
924
|
+
*
|
|
925
|
+
* @param {NFC.VCardContactInfo} cardInfo
|
|
926
|
+
* @return {*}
|
|
927
|
+
*/
|
|
928
|
+
function writeNdefVcard(cardInfo: NFC.VCardContactInfo) {
|
|
929
|
+
return executeNdefWrite(() => {
|
|
930
|
+
const mimeType = 'text/vcard';
|
|
931
|
+
const cardString = formatCardInfo(cardInfo);
|
|
932
|
+
const cardData = stringToBytes(cardString);
|
|
933
|
+
const cardRecord = NdefRecord.createMime(mimeType, cardData);
|
|
934
|
+
return new NdefMessage([cardRecord]);
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
onMounted(() => {
|
|
939
|
+
initNfcAdapter();
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
onUnmounted(() => {
|
|
943
|
+
stopHCE();
|
|
944
|
+
offHCEMessage();
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
return {
|
|
948
|
+
data,
|
|
949
|
+
isNdef,
|
|
950
|
+
isSupportNFC,
|
|
951
|
+
isListening,
|
|
952
|
+
isConnected,
|
|
953
|
+
nfcInstance,
|
|
954
|
+
startHCE,
|
|
955
|
+
stopHCE,
|
|
956
|
+
connect,
|
|
957
|
+
close,
|
|
958
|
+
write,
|
|
959
|
+
writeNdef,
|
|
960
|
+
writeNdefText,
|
|
961
|
+
writeNdefUri,
|
|
962
|
+
writeNdefAndroidApp,
|
|
963
|
+
writeNdefWifi,
|
|
964
|
+
writeNdefVcard,
|
|
965
|
+
};
|
|
966
|
+
}
|