当前位置: 首页 > news >正文

uniapp APP端实现NFC读卡功能

<template> <view class="main"> <u-button type="primary" text="开启NFC" @click="openNfc"></u-button> <!-- NFC读取弹窗 --> <u-popup :show="showNfcPopup" mode="center" :zoom="false" @close="showNfcPopup = false" closeOnClickOverlay > <view v-if="showNfcPopup" class="nfc-popup-content"> <view class="nfc-icon-wrapper"> <view class="nfc-icon"> <text class="iconfont icon-nfc"></text> <view class="pulse-ring"></view> <view class="pulse-ring delay-1"></view> <view class="pulse-ring delay-2"></view> </view> </view> <text class="nfc-title">NFC 识别中</text> <text class="nfc-desc">请将设备靠近感应区</text> <view class="scan-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.showNfcPopup=true } }, // 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 lang="scss" 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); } } </style>

nfcReader.js

const 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 };
http://www.jsqmd.com/news/1108699/

相关文章:

  • VS Code 插件市场 AI 类插件上架量暴增 6 倍:2026 年开发者工具链选型避坑指南
  • 同网段与不同网段通信及vlan
  • Spring Boot安全实战:防范路由暴露、SQL注入与Thymeleaf SSTI三大核心漏洞
  • 2026 OpenClaw (小龙虾) 全能安装与配置指南
  • Brand Mind用RAG压测100次AI态度变化
  • AI编程工具与数据标注平台实战解析
  • 3分钟终极指南:用ncmdumpGUI轻松解密网易云NCM音乐文件
  • STM32与PCF8591实现多通道ADC/DAC信号转换方案
  • 如何通过tModLoader将你的泰拉瑞亚创意变为现实
  • AI系统故障诊断与智能运维实践指南
  • 《HarmonyOS技术精讲-ArkWeb》安全防线:隐私保护与沙箱机制
  • 如何免费解锁Wand专业版:开源增强工具让你的游戏修改体验更完美
  • ST25R3918与R7FA2L1AB2DFP的NFC方案设计与实现
  • 重构泰拉瑞亚生态:tModLoader深度架构解析与创新应用
  • AI开发平台怎么选?中小企业最关心的5大能力
  • 计算机毕业设计之耕地资源数据管理系统
  • 2026公考培训机构深度横评:从教研实力到退费保障,谁值得托付?
  • 腾讯会议互动安全主持操作指南
  • GBase 8a之视频数据存取demo
  • CVE-2023-29552漏洞修复实战:SLP协议拒绝服务漏洞原理与防护
  • 一站式 AI 电商内容生产工具易元 AI 详解:素材管理、视频脚本、信息流营销一体化解决方案
  • GPU加速创意革命:MediaPipe TouchDesigner插件如何突破实时视觉交互的边界
  • 基于HFish蜜罐与Python构建自动化威胁情报源实战指南
  • 花了三天时间,我把市面上4款网页转Figma工具全测了一遍
  • 公共安全展馆设备【触电救助体验系统】
  • 为什么1V输入,LED就是不亮?
  • 办公自动化工具 OpenClaw |Windows 与 Mac 双端部署实操手册
  • Sunshine游戏串流服务器深度解析:5大架构设计与性能优化策略
  • 3步实现游戏参数自由调整:开源增强工具全攻略
  • MediaPipe TouchDesigner插件终极指南:5步打造GPU加速视觉交互应用