Android NFC读写实战:从标签类型到系统分发的完整指南
发布时间:2026/9/9 16:57:11来源:尧图网络
简介NFC近场通信在Android开发中常用于移动支付、智能卡模拟与点对点数据传输其读写操作是入门者的常见难点。这份资料面向具备基础Android开发能力的初学者以NFCDemo工程为主线系统讲解NfcAdapter、Tag、NDEF消息等核心API覆盖从标签读取到NDEF写入的完整流程并涉及MIFARE Classic、ISO/IEC 14443等标签技术的选型要点。压缩包共36个文件约72KB以Java源码和XML资源为主包含3个Java源文件、AndroidManifest配置、4个XML布局与资源文件另附APK可直接安装测试便于对照代码理解实际效果。已有415人学习下载适合希望快速上手NFC读写、并想结合示例工程进行真机验证的开发者。通过该工程读者可掌握NFC权限配置、Intent过滤器设置以及NDEF消息解析与写入的代码写法为后续开发门禁模拟、智能海报等NFC应用打下基础。 最近半年我接连做了几个和NFC相关的Android项目从最初单纯的“手机贴着标签读出编号”到最后完整跑通读写流程期间踩过的坑和绕过的弯比写业务代码的时间多得多。很多人最初和我一样以为Android NFC读写就是往Manifest里加个权限、在onNewIntent里拿一下Tag对象就完事了但真到设备上调试才发现无论是卡片的物理类型、NDEF消息的封装格式还是系统对标签的分发机制任何一个环节不通结果都是“手机贴上去毫无反应”。这篇文章就是一次完整的NFC读写实战复盘。我会把NFC卡片的工作方式、Android系统的标签分发机制、读卡写卡的核心代码、以及真机上最容易让人抓狂的排查思路全部拆开来讲。不管你是刚从零开始接NFC功能还是已经写了些代码但卡在某个环节这篇文章都值得你花十分钟看完能帮你少走一大段弯路。1. 13.56MHz的物理世界NFC标签类型决定了你的代码怎么写1.1 先搞懂NFC到底在干什么NFC全称是Near Field Communication工作在13.56MHz这个频段通信距离通常在4cm以内。你可以把一张NFC标签想象成一个没有电池的微型存储芯片外面绕了一圈天线。手机靠近它时手机会通过射频场给这张标签“无线供电”标签被激活后再通过调制反射的方式把数据传回给手机。整个过程就是读卡器模式和标签模式之间的对话而在Android应用层你不需要直接处理射频调制这些底层的信号变化系统已经封装好了但理解这个过程能帮你定位很多“为什么读不到”的问题。手机贴近标签时如果是手机主动发指令、标签被动响应这叫主动通信模式。NFC标准里还定义了卡模拟模式也就是手机本身充当一张卡片比如各种Pay支付场景手机变成一张虚拟的银行卡。我最早做项目时没分清这两个模式差点把卡模拟的HCE逻辑和标签读写的逻辑混在一起后来才明白这是两条完全不同的技术路线。1.2 标签类型一张表看清要害Android系统对NFC标签的封装并不是只有一种接口而是按照底层芯片类型和技术规范分成了若干类。写代码之前第一件必须做的事是搞清楚你手里那张卡到底是哪一种。我习惯用一张表来区分标签类型典型芯片容量特点常见用途Type 1Topaz96字节速度慢结构简单Android设备上比较少见简单的单用途标签Type 2NTAG213/215/216MIFARE Ultralight144~888字节成本低最常见支持NDEF格式商品溯源、名片、离线支付凭证Type 3Sony FeliCa较大日系标准国内不常见日本交通卡、电子货币Type 4DESFire等几KB支持文件系统、加密和访问控制功能最强门禁、公交一卡通MIFARE Classic原NXP MIFARE Classic 1K1024字节虽走ISO 14443-A协议但不在NDEF标准体系内早期门禁、校园卡、会员卡这里最需要警惕的是最后一类MIFARE Classic。它虽然外观上也是一张IC卡手机也能读到它的UID但它内部不是标准的NDEF文件结构而是分成16个扇区、每个扇区4个块且每一扇区都必须用密钥认证通过后才能读写数据。很多“读不出内容”的问题根源就在这张卡根本不存在NDEF消息Android默认的NDEF解析逻辑拿不到任何有效内容。1.3 动手前先用工具把卡“验明正身”我接手过的NFC项目里有一半以上是需求方自己也不知道卡片具体型号只扔给我一句“你就用手机读一下卡号”。这种时候千万别急着写代码。正确做法是先用手机系统自带的“标签信息”功能或者装一个NFC TagInfo、NFC Reader Tool这类工具把卡片贴近手机背面先看三样关键信息标签类型、IC芯片型号、是否已经写入NDEF数据。以我自己的实测经验一张全新的NTAG213用NFC TagInfo读出来会显示“NXP NTAG213”容量是144字节状态是“未格式化NdefFormatable”。而一张用了很久的MIFARE Classic 1K门禁卡会显示“NXP MIFARE Classic 1K”同时“NDEF”字段是空的只有UID可读。这两种卡在代码里的处理路径完全不同前期识别这一步能帮你省掉大量调试时间。切记代码写得再好也救不了卡型不匹配的方案。2. 系统到底把读卡事件交给了谁Android NFC的三种分发机制2.1 NfcAdapter与四种Tag Technology类代码层面所有的NFC操作都是从NfcAdapter这个入口开始的。在Activity里你要先获取NfcAdapter实例NfcAdapter nfcAdapter NfcAdapter.getDefaultAdapter(this); if (nfcAdapter null) { // 设备不支持NFC直接提示用户换设备 return; } if (!nfcAdapter.isEnabled()) { // 用户系统设置里关闭了NFC开关提示去打开 return; }拿到NfcAdapter之后系统在检测到标签时会回调给你一个android.nfc.Tag对象。这个Tag对象本身不直接提供数据读写能力它是一个“分发器”通过它你可以获取对应卡型的Technology类实例。常见的Technology接口包括Ndef、NdefFormatable、MifareClassic、MifareUltralight、NfcA、NfcB、NfcF、IsoDep等。换句话说同样是贴卡系统会根据底层识别到的芯片类型把能力封装成不同的类交给你使用。这里的核心原则是能用Ndef接口就优先用Ndef接口它是Android对NDEF标准标签的统一抽象兼容性最好。只有遇到MIFARE Classic这类特殊卡才需要绕过Ndef直接用MifareClassic接口做扇区读写。2.2 三种Intent优先级别再傻傻分不清Android系统检测到NFC标签后并不会直接通知你的App而是先通过一套优先级机制决定把“标签发现”事件交给哪个Activity。这套机制包括三个从高到低的Intent第一个是NDEF_DISCOVERED优先级最高。系统只有在标签内部发现了符合NDEF格式的消息且消息中的URI或MIME类型与你所声明的intent-filter匹配时才会触发。第二个是TECH_DISCOVERED优先级第二。只要标签的技术集合比如包含Ndef、MifareClassic等与你声明的tech-list匹配就会触发它不关心NDEF消息内容。第三个是TAG_DISCOVERED优先级最低是兜底机制当前面两个都不匹配时它会把所有标签都交给你的Activity。Manifest中声明方式如下activity android:name.NfcReadActivity !-- NDEF分发只有标签内NDEF记录匹配指定URI时才触发 -- intent-filter action android:nameandroid.nfc.action.NDEF_DISCOVERED/ category android:nameandroid.intent.category.DEFAULT/ data android:schemehttps android:hostexample.com/ /intent-filter !-- TECH分发标签技术集合匹配时触发 -- intent-filter action android:nameandroid.nfc.action.TECH_DISCOVERED/ /intent-filter meta-data android:nameandroid.nfc.action.TECH_DISCOVERED android:resourcexml/nfc_tech_filter/ /activity对应的res/xml/nfc_tech_filter.xml文件resources tech-list techandroid.nfc.tech.Ndef/tech /tech-list tech-list techandroid.nfc.tech.NdefFormatable/tech /tech-list tech-list techandroid.nfc.tech.MifareClassic/tech /tech-list tech-list techandroid.nfc.tech.NfcA/tech /tech-list /resources这里有个新手最容易踩的坑你在Manifest里声明了NDEF_DISCOVERED本来想看文本记录但文本类型的NDEF记录并不会匹配任何URI规则所以你的页面压根不会被系统拉起。想接收所有NFC标签最稳妥的做法还是声明TECH_DISCOVERED并把要支持的tech全部列进去。这属于经验之谈我见过不止一个同事被这个细节坑了整整一天。2.3 前台调度和Reader Mode可控性完全不同的两套方案静态Manifest分发有个比较大的副作用当手机界面停留在其他App时系统可能会弹出“完成操作方式”的选择框把用户引导到别的NFC应用里甚至被系统自带的“钱包”类应用抢占。为了避免这种不可控行为实际项目里我更推荐在页面处于前台时主动接管NFC标签的读取。一种方式是前台调度enableForegroundDispatch。它的本质是当你的Activity处于前台时把NFC事件优先派发给你暂停Manifest中声明的静态分发。代码模式大概是PendingIntent pendingIntent PendingIntent.getActivity( this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE); IntentFilter ndefFilter new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); IntentFilter techFilter new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED); IntentFilter tagFilter new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); String[][] techLists new String[][] { new String[] {android.nfc.tech.Ndef}, new String[] {android.nfc.tech.NdefFormatable}, new String[] {android.nfc.tech.MifareClassic}, new String[] {android.nfc.tech.NfcA} }; nfcAdapter.enableForegroundDispatch(this, pendingIntent, new IntentFilter[] {ndefFilter, techFilter, tagFilter}, techLists);注意在onPause里必须调用disableForegroundDispatch否则你的Activity一退到后台系统NFC调度就会处于不可控状态轻则事件回调不到预期页面重则直接把系统NFC服务搞出异常界面。很多线上反馈“读卡没反应”查到最后都是这种配对没做对。另一种方式是enableReaderMode这是我从Android 5.0之后最偏爱的方案。它的控制粒度更细可以直接指定只监听NFC-A还是NFC-B还能跳过系统对NDEF格式的预检查nfcAdapter.enableReaderMode(this, tag - { handleTag(tag); }, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_NFC_B | NfcAdapter.FLAG_READER_NFC_F | NfcAdapter.FLAG_READER_NFC_V | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null);FLAG_READER_SKIP_NDEF_CHECK这个标志很多人会忽略。如果不加它系统在检测到标签时仍会先花时间去解析一次NDEF数据虽然耗时通常只有几十毫秒但对某些特殊格式的卡片或对响应时间敏感的扫码枪式交互场景它可能带来额外的不确定性。加了这个标志后系统直接把原始Tag对象交给你解析逻辑完全由你掌控。两种机制的取舍我整理成了一张对照表对比项前台调度Reader Mode触发条件Activity前台pendingIntent匹配Activity前台Reader Mode已启用是否依赖Manifest过滤不需要运行时指定不需要能否避开系统钱包类App抢占不一定部分机型仍会被干扰能接管更加彻底是否跳过系统NDEF预解析不跳过可以通过FLAG跳过适合场景页面中存在多类NFC操作需要保留系统默认行为扫码枪式连续读写、要求稳定触发的场景3. 读卡核心实现NDEF消息是怎么被解析出来的3.1 从Intent中拿到Tag对象无论走哪种分发方式最终你都需要在Activity里接收Intent然后从Intent里取出Tag对象。最稳定的方式是在onCreate和onNewIntent两个地方都解析一次因为Activity如果已经在栈顶系统不会重新走onCreate而是直接回调onNewIntent。我的习惯是在onCreate里调一次handleIntent再在onNewIntent里调一次避免冷启动和热启动行为不一致。Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); handleNfcIntent(intent); } private void handleNfcIntent(Intent intent) { if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) || NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()) || NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { Tag tag intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); if (tag ! null) { processTag(tag); } } }3.2 NDEF消息拆包不只是取字节数组拿Ndef接口来说读取NDEF数据的核心逻辑是拿到NdefMessage然后遍历NdefRecord。一个NDEF Tag在Android语境下是一个NdefMessage它包含一个或多个NdefRecord。每个NdefRecord由三部分组成TNFType Name Format类型名格式、type、id、payload。TNF决定了type字段的语义比如TNF_WELL_KNOWN表示type是RTD_TEXT或RTD_URITNF_MIME_MEDIA表示type是一个MIME类型。我写了一个通用的解析方法基本覆盖了日常项目里最常见的记录类型private ListString parseNdefMessage(NdefMessage message) { ListString results new ArrayList(); for (NdefRecord record : message.getRecords()) { if (record null) continue; switch (record.getTnf()) { case NdefRecord.TNF_WELL_KNOWN: if (Arrays.equals(record.getType(), NdefRecord.RTD_TEXT)) { results.add(parseTextRecord(record)); } else if (Arrays.equals(record.getType(), NdefRecord.RTD_URI)) { results.add(parseUriRecord(record)); } break; case NdefRecord.TNF_MIME_MEDIA: results.add(new String(record.getPayload(), StandardCharsets.UTF_8)); break; case NdefRecord.TNF_ABSOLUTE_URI: results.add(new String(record.getPayload(), StandardCharsets.UTF_8)); break; default: // 其他TNF类型按十六进制输出payload StringBuilder sb new StringBuilder(); for (byte b : record.getPayload()) { sb.append(String.format(%02X, b)); } results.add(sb.toString()); break; } } return results; }解析文本记录时payload的第一个字节不是文本内容而是状态字节。状态字节的最高位表示文本编码方式是UTF-8还是UTF-16低七位表示语言码的长度。我见过不少人在这一步直接取payload的全部字节转String结果读出来的中文全是乱码。正确做法如下private String parseTextRecord(NdefRecord record) { byte[] payload record.getPayload(); if (payload.length 0) return ; int status payload[0] 0xFF; int languageCodeLength status 0x3F; String encoding (status 0x80) ! 0 ? UTF-16 : UTF-8; try { return new String(payload, languageCodeLength 1, payload.length - languageCodeLength - 1, encoding); } catch (UnsupportedEncodingException e) { return ; } }为什么Android平台会这样设计因为NDEF是一个跨平台、跨设备的国际标准标签可能被iOS设备、NFC标签打印机、非手机读写器任何一方写入编码统一走NDEF规范才能保证互认。你在代码里看似是“多此一举”的解析步骤实际是在遵守一套全世界设备互通的协议约定。3.3 非NDEF卡怎么读以MIFARE Classic为例前面说过MIFARE Classic不是标准NDEF结构你调用Ndef.get(tag)大概率得到null。这时需要直接使用MifareClassic接口。它会按扇区划分每个扇区有4个块每块16字节。读数据前必须先对所在扇区做密钥认证MifareClassic mfc MifareClassic.get(tag); try { mfc.connect(); boolean auth mfc.authenticateSectorWithKeyA(0, MifareClassic.KEY_DEFAULT); if (auth) { byte[] blockData mfc.readBlock(0); // 块0通常包含UID块1~2一般是厂商数据或业务数据 } } catch (IOException e) { e.printStackTrace(); } finally { try { mfc.close(); } catch (IOException ignored) {} }这里要提醒一句MIFARE Classic的密钥机制是历史遗留设计早期该卡型的加密算法被逆向之后市面上流传着大量所谓“默认密钥”。实际开发中我不建议你去研究如何绕过别人的密钥这不只是合规问题而是这种卡型的安全等级已经无法满足正规业务需求。如果项目需要做门禁、会员卡这类身份凭证优先选择符合标准、支持加密认证的Type 4标签或者直接走云平台端到端密钥管理方案。4. 写卡核心实现从空标签到一条可用的NDEF消息4.1 新标签和旧标签的写入路径完全不同NFC标签的写入逻辑比很多人想象的要绕一层。对Ndef.get(tag)非null的标签说明它已经格式化并支持直接覆盖写入NDEF消息但如果标签是全新的出厂状态下它通常是NdefFormatable而不是Ndef意味着它还没有NDEF文件结构必须先通过NdefFormatable接口执行格式化。很多新手直接拿Ndef.get(tag)后connect、write报了异常就开始怀疑代码写错了其实是卡还没格式化。我的处理逻辑是这样的private void writeNdefMessageToTag(Tag tag, NdefMessage message) { Ndef ndef Ndef.get(tag); if (ndef ! null) { try { ndef.connect(); if (!ndef.isWritable()) { // 标签被写保护无法覆盖 showToast(标签只读无法写入); return; } int msgSize message.toByteArray().length; if (ndef.getMaxSize() msgSize) { showToast(数据超出标签容量 msgSize ndef.getMaxSize()); return; } ndef.writeNdefMessage(message); showToast(写入成功); } catch (IOException | FormatException e) { showToast(写入失败 e.getMessage()); } finally { try { ndef.close(); } catch (IOException ignored) {} } } else { // 新标签尝试格式化后写入 NdefFormatable formatable NdefFormatable.get(tag); if (formatable ! null) { try { formatable.connect(); formatable.format(message); showToast(格式化并写入成功); } catch (IOException | FormatException e) { showToast(格式化失败 e.getMessage()); } finally { try { formatable.close(); } catch (IOException ignored) {} } } } }NdefFormatable.format(message)这一步很关键它会把标签自带的厂商数据区重新布局建立NDEF文件系统然后再把消息写入。实测下来同一张NTAG213格式化一次之后再写入后续就可以直接用Ndef接口覆盖了不会再走NdefFormatable分支。4.2 构造NdefMessage时最容易忽略的编码问题构造NDEF消息倒是简单Android提供了几个现成的快捷方法// 写一条文本记录 NdefRecord textRecord NdefRecord.createTextRecord(zh, 你好NFC); NdefMessage message new NdefMessage(new NdefRecord[]{textRecord});这里我踩过一个很实际的坑传入的语言码“zh”只是标签里的元信息它和文本内容的字符集没有直接关系。createTextRecord方法内部会自动把字符串编码成UTF-8字节。也就是说一段中文文本在UTF-8编码下每个汉字占3个字节。一张NTAG213的NDEF用户可用空间通常是137字节左右去掉记录头、语言码这些开销实际能存的中文大约只有43个汉字。很多人写入超过容量时就报错根本不是代码问题而是没算这个账。如果业务上需要写入结构化数据比如JSON字符串我建议控制好长度并考虑压缩或只在标签内存放关键ID把详细数据放到服务端。NFC标签本质上是“钥匙”不是“仓库”这个思路能帮你避免大量容量焦虑。4.3 自定义记录类型与一次写入的永久性风险除了标准文本和URINDEF还支持自定义TNF类型例如TNF_EXTERNAL_TYPE它的type字段格式是“域名:类型名”。这在同一系统内的多设备识别场景很有用NdefRecord customRecord NdefRecord.createExternal( example.com, myType, payload数据.getBytes(StandardCharsets.UTF_8));但这里引出另一个必须注意的行业常识很多NFC标签尤其是NTAG系列在写入后可以通过置位锁定位变成永久只读。一旦锁定整张标签的内容将不可覆盖、不可格式化只能读取。有些客户会说“那你写完之后帮我把卡锁上防止别人改”——这个需求在合规范围内可以做但务必在项目启动前和需求方说清楚后果因为误锁一张批量生产的卡损失的不只是一张卡的成本还有整个生产流程的返工时间。我在产线对接项目里就见过真实案例写卡程序把锁定逻辑和正常写入逻辑放在同一段代码里结果一个分支判断错误导致整批300张卡全部被锁定内容还没写完。后来我在写卡流程里加了“是否需要锁定”的二次确认参数并且写卡和锁卡严格分属两个接口调用才彻底把这种事故堵死。5. 真机排查为什么你的手机贴上去毫无反应到了实战环节我把自己排查NFC问题时的思路整理成了一套“从物理层到应用层”的排查链路每一步都对应一类非常高频的真实问题。5.1 第一步先排除物理因素和系统抢占手机贴卡没反应我最先会看两件事。一是手机本身是否支持NFCNFC开关是否打开——这个看起来是废话但真有人把手机壳对准卡的位置贴了半天才发现是旧手机不支持NFC。二是贴卡位置。NFC天线通常内置在手机背面上半部、摄像头附近每款机型的感应区位置不一样。我用过几台测试机有的是正中偏上有的是偏左贴错位置会明显导致感应距离变短。另一个非常真实的干扰源是系统自带的“钱包”类应用以及手机上已安装的其他NFC应用。这类App在后台做了前台调度或系统级的NFC事件监听会把你辛辛苦苦写的Activity踢出分发链路。我遇到过的典型现象是贴卡后系统弹出“打开钱包吗”“打开XX门禁吗”的系统选择框而自己的App毫无动静。这时候最有效的办法就是改用enableReaderMode它能在当前页面内彻底接管标签事件从根源上避开系统推荐应用的干扰。5.2 第二步确认标签有没有NDEF数据如果代码能收到Intent但解析出来的数据是空的先用NFC TagInfo或NFC Reader Tool这类工具确认卡片状态。我强烈建议在自己的开发调试工具里加一个简单的“卡片信息打印”功能把Tag的techList、UID、Ndef是否存在、Ndef最大容量这些信息全部打到日志里。有了这些基础信息很多问题当场就能定位不用反复贴卡试错。techList的打印方法private void dumpTagInfo(Tag tag) { Log.d(NFC, UID: bytesToHex(tag.getId())); Log.d(NFC, TechCount: tag.getTechList().length); for (String tech : tag.getTechList()) { Log.d(NFC, Tech: tech); } Ndef ndef Ndef.get(tag); if (ndef ! null) { Log.d(NFC, Ndef maxSize: ndef.getMaxSize()); } else { Log.d(NFC, Ndef is null); } }这段日志是我项目里的首选调试手段。线上用户反映“读不到卡”我一般先让他把这段日志发回来再针对性地判断是卡型不兼容、数据格式问题还是NFC开关被系统服务锁住了。5.3 第三步按现象对照原因现象最可能的原因处理建议贴卡完全没反应日志里没有任何Intent手机不支持NFC、开关关闭、贴卡位置不对、天线区域有金属干扰换设备测试、检查系统NFC开关、换裸机贴卡位置系统弹窗问“用哪个应用打开”自己的App没弹分发机制被其他NFC应用抢占或Manifest过滤条件没匹配改用enableReaderMode检查NDEF/TECH过滤声明能进日志但tag.getTechList()只有NfcA没有Ndef卡片是无NDEF结构的MIFARE Classic或空白NTAG按卡型走MifareClassic或NdefFormatable流程Ndef.get(tag)不为null但writeNdefMessage报错标签已被写保护、容量不足、数据长度超限检查isWritable、maxSize、消息字节数同一张卡第一次写成功第二次覆盖不了标签已被锁定为只读状态只能当作一次性卡使用无法恢复写入读出来的中文是乱码NDEF文本记录编码解析错误按状态字节判断UTF-8/UTF-16后正确截取payload5.4 关于Android版本差异两个容易被忽略的细节Android 10之后系统对后台读取NFC标签的行为限制得更严格。如果你的应用退到后台还指望它继续响应标签这本身就是不合规的交互方式尽量保证读写过程发生在应用处于前台的场景里。另一个是PendingIntent的标志问题。Android 12开始系统强制要求PendingIntent必须显式指定FLAG_IMMUTABLE或FLAG_MUTABLE。我见过有人把老项目的targetSdkVersion升上去之后前台调度突然失效崩溃在enableForegroundDispatch这一行往往就是PendingIntent缺少这个标志PendingIntent pendingIntent PendingIntent.getActivity( this, 0, intent, PendingIntent.FLAG_MUTABLE);如果不需要Intent携带的数据被外部应用修改用FLAG_IMMUTABLE更安全。这个配置虽然只影响少数场景但排查起来极其隐蔽值得记在自查清单里。最后再分享几个我实际做项目时的习惯NFC读写这种功能API本身不算复杂真正的复杂度来自“卡片的物理多样性”和“系统的分发不可控性”。我个人的习惯是项目启动的第一天就从网上买几片NTAG213、NTAG215和一张自带NDEF格式的Type 4卡片先把最简单的文本读写跑通确认开发板、系统版本、真机型号这些基础设施没问题再上复杂卡型。前期在调试工具里把标签类型、NDEF容量、techList全部打日志这个习惯帮我节省了大量线上排查时间。另外我强烈建议写卡模块单独做成一个工具页面和生产环境的分发逻辑解耦一方面方便你快速造测试卡另一方面把“格式化”和“锁定”这类高危操作隔离开避免误操作把卡弄废。NFC这个领域很多问题都不是代码写不对而是设备和卡片的物理差异堆出来的“缘分问题”。把基础认知打牢再在调试习惯上下点功夫你就能比大多数人少踩一半的坑。本文还有配套的精品资源点击获取
网站建设高端定制企业官网