uniapp APP端实现NFC读卡功能

📅 2026/7/2 11:40:30
uniapp APP端实现NFC读卡功能
template view classmain u-button typeprimary text开启NFC clickopenNfc/u-button !-- NFC读取弹窗 -- u-popup :showshowNfcPopup modecenter :zoomfalse closeshowNfcPopup false closeOnClickOverlay view v-ifshowNfcPopup classnfc-popup-content view classnfc-icon-wrapper view classnfc-icon text classiconfont icon-nfc/text view classpulse-ring/view view classpulse-ring delay-1/view view classpulse-ring delay-2/view /view /view text classnfc-titleNFC 识别中/text text classnfc-desc请将设备靠近感应区/text view classscan-line/view /view /u-popup /view /template script import nfcReader from /utils/nfcReader export default { data() { return { nfcData: null,//NFC数据 showNfcPopup:false } }, onLoad() { this.initNFCReader()//初始化NFC }, onUnload() { // 移除全局事件监听 nfcReader.destroy(); }, methods: { openNfc() { if (nfcReader.startRead()) { this.showNfcPopuptrue } }, // NFC初始化 initNFCReader() { nfcReader.init({ onRead: result this.handleNFCRead(result), onError: error this.handleNFCError(error) }); }, // NFC读取到的数据 handleNFCRead(result) { this.nfcData result; console.log(nfc_id:, result.nfcId); console.log(nfc_id_reverse:, result.reversedNfcId); console.log(NFC 数据, result.nfcText); this.showNfcPopup false; }, handleNFCError(e) { console.error(NFC读取失败, e); uni.showToast({ icon: none, title: NFC读取失败请重试 }); }, } } /script style langscss scoped .nfc-popup-content { width: 500rpx; background: #1a2332; border-radius: 40rpx; padding: 60rpx 40rpx; display: flex; flex-direction: column; align-items: center; color: #fff; position: relative; overflow: hidden; } .nfc-icon-wrapper { position: relative; width: 160rpx; height: 160rpx; margin-bottom: 30rpx; } .pulse-ring { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 4rpx solid #00cfff; border-radius: 50%; animation: nfcPulse 2s ease-out infinite; opacity: 0; } .pulse-ring.delay-1 { animation-delay: 0.6s; } .pulse-ring.delay-2 { animation-delay: 1.2s; } keyframes nfcPulse { 0% { transform: scale(0.8); opacity: 0.8; } 100% { transform: scale(1.8); opacity: 0; } } .scan-line { position: absolute; bottom: 0; left: 0; width: 100%; height: 4rpx; background: linear-gradient(90deg, transparent, #00cfff, transparent); box-shadow: 0 0 20rpx #00cfff; animation: nfcScan 1.5s linear infinite; } keyframes nfcScan { 0% { bottom: 0%; opacity: 1; } 50% { bottom: 100%; opacity: 0.5; } 100% { bottom: 0%; opacity: 1; } } .nfc-icon { position: relative; z-index: 2; width: 160rpx; height: 160rpx; background: #2a3a4a; border-radius: 50%; display: flex; align-items: center; justify-content: center; animation: iconBreath 1.5s ease-in-out infinite; } keyframes iconBreath { 0%, 100% { transform: scale(1); } 50% { transform: scale(0.9); } } /stylenfcReader.jsconst TECH_DISCOVERED android.nfc.action.TECH_DISCOVERED; const TECH_LISTS [ [android.nfc.tech.IsoDep], [android.nfc.tech.NfcA], [android.nfc.tech.NfcB], [android.nfc.tech.NfcF], [android.nfc.tech.Nfcf], [android.nfc.tech.NfcV], [android.nfc.tech.NdefFormatable], [android.nfc.tech.MifareClassi], [android.nfc.tech.MifareUltralight] ]; let NfcAdapter null; let main null; let nfcAdapter null; let pendingIntent null; let intentFiltersArray null; let readyRead false; let noNFC false; let readDelay 1000; let callbacks { onRead: null, onError: null }; let handlers { newintent: null, pause: null, resume: null }; function toast(content) { uni.showToast({ title: content, icon: none }); } function normalizeNfcValue(value) { return String(value || ).replace(/[\s:-]/g, ).toUpperCase(); } function reverseNfcHex(value) { const normalizedValue normalizeNfcValue(value); if (!normalizedValue || normalizedValue.length % 2 ! 0) return normalizedValue; return normalizedValue.match(/.{2}/g).reverse().join(); } function byteArrayToHexString(inarray) { if (!inarray) return ; const hex [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F]; let out ; for (let j 0; j inarray.length; j) { const inn inarray[j] 0xff; let i (inn 4) 0x0f; out hex[i]; i inn 0x0f; out hex[i]; } return out; } function getNfcRecordText(record) { const payload record.getPayload(); if (!payload || payload.length 0) return ; const text plus.android.newObject(java.lang.String, payload, UTF-8).toString(); const type plus.android.newObject(java.lang.String, record.getType(), UTF-8).toString(); if (type T payload.length 1) { const languageLength payload[0] 0x3f; return text.substring(languageLength 1).trim(); } return text.trim(); } function readIntent(intent) { const bytesId intent.getByteArrayExtra(NfcAdapter.EXTRA_ID); const nfcId byteArrayToHexString(bytesId); const rawmsgs intent.getParcelableArrayExtra(android.nfc.extra.NDEF_MESSAGES); let nfcText ; if (rawmsgs ! null rawmsgs.length 0) { const records rawmsgs[0].getRecords(); if (records ! null records.length 0) { nfcText getNfcRecordText(records[0]); } } return { nfcId, reversedNfcId: reverseNfcHex(nfcId), nfcText }; } function runNfc() { try { const intent main.getIntent(); console.log(action type: intent.getAction()); if (TECH_DISCOVERED intent.getAction() readyRead) { readyRead false; const result readIntent(intent); if (typeof callbacks.onRead function) callbacks.onRead(result); } } catch (e) { readyRead true; if (typeof callbacks.onError function) callbacks.onError(e); } } function enableForegroundDispatch() { if (nfcAdapter main) { nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, TECH_LISTS); } } function disableForegroundDispatch() { if (nfcAdapter main) { nfcAdapter.disableForegroundDispatch(main); } } function bindEvents() { handlers.newintent function() { console.log(newintent running); setTimeout(runNfc, readDelay); }; handlers.pause function() { console.log(pause running); disableForegroundDispatch(); }; handlers.resume function() { console.log(resume running); enableForegroundDispatch(); }; plus.globalEvent.addEventListener(newintent, handlers.newintent); plus.globalEvent.addEventListener(pause, handlers.pause); plus.globalEvent.addEventListener(resume, handlers.resume); } function unbindEvents() { if (typeof plus undefined || !plus.globalEvent || !plus.globalEvent.removeEventListener) return; if (handlers.newintent) plus.globalEvent.removeEventListener(newintent, handlers.newintent); if (handlers.pause) plus.globalEvent.removeEventListener(pause, handlers.pause); if (handlers.resume) plus.globalEvent.removeEventListener(resume, handlers.resume); handlers.newintent null; handlers.pause null; handlers.resume null; } export default { init(options {}) { this.destroy(); callbacks.onRead options.onRead || null; callbacks.onError options.onError || null; readDelay options.readDelay || 1000; try { if (typeof plus undefined || !plus.android) { noNFC true; return false; } main plus.android.runtimeMainActivity(); const Intent plus.android.importClass(android.content.Intent); const PendingIntent plus.android.importClass(android.app.PendingIntent); const IntentFilter plus.android.importClass(android.content.IntentFilter); NfcAdapter plus.android.importClass(android.nfc.NfcAdapter); nfcAdapter NfcAdapter.getDefaultAdapter(main); if (nfcAdapter null) { noNFC true; toast(设备不支持NFC); return false; } if (!nfcAdapter.isEnabled()) { noNFC true; toast(请在系统设置中先启用NFC功能); return false; } noNFC false; const intent new Intent(main, main.getClass()); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); pendingIntent PendingIntent.getActivity(main, 0, intent, 0); const ndef new IntentFilter(TECH_DISCOVERED); ndef.addDataType(*/*); intentFiltersArray [ndef]; bindEvents(); enableForegroundDispatch(); return true; } catch (e) { noNFC true; if (typeof callbacks.onError function) callbacks.onError(e); return false; } }, startRead() { if (noNFC) { toast(请检查设备是否支持并开启NFC); return false; } readyRead true; // toast(请将NFC标签靠近); return true; }, destroy() { try { unbindEvents(); disableForegroundDispatch(); } catch (e) { if (typeof callbacks.onError function) callbacks.onError(e); } main null; nfcAdapter null; pendingIntent null; intentFiltersArray null; readyRead false; }, isAvailable() { return !noNFC; }, normalizeNfcValue, reverseNfcHex };