iOS NFC 实战手册:如何用 React Native 读写和锁定 NFC 标签

iOS NFC 实战手册:如何用 React Native 读写和锁定 NFC 标签

💡 原文英文,约13300词,阅读约需49分钟。
📝

内容提要

本文是iOS NFC开发实战手册,基于TapCard项目。NFC标签可用容量仅约137字节,无模拟器,必须真机测试;需付费开发者账号、App ID、entitlement和描述文件,配置错误只报签名错误。作者手写NDEF解码器,因流行库会丢弃语言代码、截断emoji。写入需先查询容量再写并回读验证。还介绍焦点计时器、标签永久锁定、自建Swift原生模块、删除依赖并保留证据,以及EAS构建对比和Android预览。

🔎

延伸解读

iOS NFC 的隐藏成本:配置与真机测试

文章指出,iOS NFC 开发的主要障碍不在代码,而在苹果的配置流程:需要付费开发者账号、显式 App ID、启用 NFC 能力并重新生成描述文件。任何一步出错,构建只会报签名错误,不会提示 NFC。此外,NFC 无法在模拟器运行,必须用真机测试,硬件缺失会直接阻塞开发。这意味着项目排期需为账号申请、配置调试和实体标签采购留出时间,而非仅关注编码。

容量陷阱:137 字节而非 144 字节

NTAG213 标称 144 字节用户内存,但实际可写入的 NDEF 消息最大仅 137 字节,因为标签自身簿记占用了部分空间。文章作者曾误用 144 字节做容量检查,导致普通 vCard(约 202 字节)被错误判断为可写入。正确做法是在写入前查询标签的真实容量,并区分“假设值”与“标签报告值”。这提醒开发者:产品设计必须考虑标签容量限制,并明确告知用户。

自写 NDEF 解码器的理由与测试策略

作者发现流行库会丢弃文本记录的语言代码、错误解码 UTF-16 并截断 emoji(将 U+1F600 变成 U+F600)。因此他手写解码器,并用三类测试保障:正确性测试、与库一致时的吻合测试,以及锁定库错误行为的“分歧测试”。分歧测试会在上游修复时失败,从而提醒开发者重新评估自写代码的必要性。这种测试策略将依赖缺陷转化为可维护的决策记录。

焦点计时器:用地理摩擦替代应用封锁

文章中的焦点计时器要求用户走到 NFC 标签处才能结束会话,利用的是地理摩擦而非点击手势。它无法真正封锁其他应用,因为 iOS 的 family-controls 权限仅授予特定应用。因此它转而强制记录:提前结束会留下永久标记,清除历史也需要标签。这种设计将承诺机制建立在可验证的物理条件上,而非依赖用户自律。

Q&A

iOS 上开发 NFC 功能需要哪些前置条件?

需要一台 iPhone 7 或更新机型(Core NFC 仅限 iPhone,iPad 不支持)、付费的 Apple 开发者账号(免费账号无法使用 NFC)、以及 NTAG213 标签用于测试。此外还需要在 Apple 开发者门户注册显式 App ID、勾选 NFC Tag Reading 能力、重新生成描述文件,并在 app.json 中配置 NFCReaderUsageDescription 和 entitlements。

为什么 iOS 模拟器无法测试 NFC 功能?

NFC 硬件在 iOS 模拟器和 Android 模拟器上都不存在,API 会直接报告不可用,没有任何模拟路径。因此所有 NFC 相关代码都必须用真机加实体标签测试,无法在 CI 中演示,也无法编写证明标签被读取的测试。建议把代码拆成两部分:与硬件交互的部分只能在真机上测,其余纯数据处理逻辑可以在电脑上测试。

为什么作者要自己手写 NDEF 解码器而不用现成库?

因为流行的 react-native-nfc-manager 库的 NDEF 解码器存在两个问题:一是丢弃文本记录中的语言代码,导致无法回答“这是什么语言”;二是其字节转字符串的辅助函数使用 String.fromCharCode,只保留低 16 位,会把 emoji 等 4 字节 UTF-8 字符截断成错误码点(如 U+1F600 变成 U+F600)。作者因此手写约 530 行纯 TypeScript 解码器,并保留库用于与硬件通信的部分。

NTAG213 标签的实际可用容量是多少?为什么不是 144 字节?

NTAG213 芯片的用户内存是 144 字节,但实际可写入的最大 NDEF 消息只有 137 字节。因为标签自身需要一些簿记字节(TLV 框架)来包装消息,所以写入时能用的容量比用户内存小。作者最初误用 144 字节做容量检查,导致错误地告诉用户名片能放下,实际上一张普通 vCard 约 202 字节,根本放不下。

在 iOS 上写入 NFC 标签的正确步骤是什么?

正确顺序是:1. 先查询标签是否可写以及真实容量;2. 如果只读或容量不足则提前拒绝,避免写入失败导致标签半写;3. 执行写入;4. 在同一会话内回读并比对记录内容(而非原始字节)。这四步必须在同一个 NFC 会话中完成,因为 iOS 每次 requestTechnology 都会弹出系统弹窗,分开会导致多次弹窗和点击。

如何用 NFC 标签实现一个无法轻易结束的专注计时器?

把标签放在不方便拿的地方(如楼下抽屉),点击标签开始专注会话,要结束必须走回去再点同一个标签。核心规则是:同一个标签在空闲时启动会话、在专注时结束会话;只接受绑定的那个标签,其他标签无效;计时器只向上累计,不倒数;允许提前结束但会留下永久可见的“提前结束”标记,且清除历史记录也必须用标签。这样利用地理摩擦而非手势来约束行为。

🏷️

标签

➡️

继续阅读