Delphi 中 NFC 读写功能的演进之路:从基础探测到全平台稳定支持
在移动设备日益普及的今天,近场通信(NFC)已不再只是支付场景中的“配角”。无论是智能门禁、资产追踪,还是产品防伪与设备快速配对,NFC 都以其低功耗、高安全性和即触即通的特性,成为嵌入式应用中不可或缺的一环。而对于使用 Delphi 进行跨平台开发的工程师来说,如何在不同版本中高效实现 NFC 的读写操作,始终是一个既现实又充满挑战的问题。
Delphi 自 XE8 起逐步引入对 NFC 的支持,但这条路径并非一蹴而就。从最初只能检测标签存在,到如今可在 Android 和 iOS 上完成完整的 NDEF 消息读写,其背后是组件封装、API 抽象和平台适配的持续演进。尤其是
TNFCManager
的引入与完善,极大降低了开发者调用底层系统接口的门槛。然而,版本间的差异依然显著——某些功能在 10.2 中尚需手动构造字节数组,在 10.4 中却已可通过标准类轻松实现。若忽视这些变化,轻则代码冗余难维护,重则导致功能缺失或兼容性崩溃。
那么,究竟哪个版本才真正具备生产级的 NFC 支持?从 XE8 到 11 Alexandria,我们该如何选择技术路线?又该如何规避那些隐藏在文档之外的“坑”?
TNFCManager:Delphi 中 NFC 功能的核心引擎
一切始于
TNFCManager
——这个位于
System.NFC
单元中的关键类,是 Delphi 实现 NFC 功能的统一入口。它并不是一个简单的包装器,而是通过抽象层将 Android 的
android.nfc
与 iOS 的 Core NFC 框架融合为一套一致的编程模型。这种设计让开发者可以用相同的逻辑处理两端的事件流,而不必深陷 JNI 调用或 Objective-C 回调的泥潭。
它的基本工作流程非常直观:启动发现模式 → 等待标签靠近 → 触发事件 → 处理数据 → 停止扫描。整个过程采用异步事件驱动机制,避免阻塞主线程,非常适合 UI 密集型应用。例如:
procedure TForm1.NFCManager1TagDetected(const Sender: TObject;
const ATag: TNFCTag);
begin
if ATag.HasNDEF then
ShowMessage('发现可读标签,记录数:' + IntToStr(ATag.NDEFMessage.Records.Count));
end;
这段代码看似简单,但背后涉及多个层面的协调:权限检查、硬件状态监听、Intent 过滤(Android)、会话管理(iOS),甚至包括标签类型自动识别。比如当一张 MIFARE Ultralight 标签靠近时,
TNFCManager
会尝试解析其是否符合 NDEF 格式,并将结果暴露给
HasNDEF
属性。如果成功,则可通过
NDEFMessage
获取结构化数据。
更进一步地,它还内置了对常见 NDEF 类型的支持。例如:
-
"T"
表示文本记录(TNFTWellKnown)
-
"U"
表示 URI 记录
- MIME 类型如
"text/vcard"
可用于电子名片
这意味着你无需自己解析 ISO/IEC 14443-A 协议细节,就能提取出用户姓名或网址链接。对于大多数业务场景而言,这已经足够。当然,如果你需要访问原始块数据(如 MIFARE Classic 的加密扇区),仍需借助 JNI 或原生扩展,但这属于高级用例,不在默认封装范围内。
值得一提的是,
TNFCManager
在生命周期管理上也有讲究。理想的做法是在窗体显示时启动扫描(
StartDiscovery
),隐藏时停止(
StopDiscovery
)。否则,即使 App 已退至后台,系统仍可能持续唤醒 NFC 控制器,造成不必要的电量消耗。这一点在 Android 上尤为明显。
版本演进实录:从残缺支持到生产可用
回顾 Delphi 各版本对 NFC 的支持程度,就像翻阅一部微型技术编年史。每个版本都留下了特定时代的烙印,也决定了你能走多远。
XE8 到 10.1 Berlin:有心无力的时代
XE8 是第一个提供
TNFCManager
的版本,但它更像是一个“占位符”。你可以检测到标签的存在,也能获取一些原始字节流,但无法判断内容含义。想读取一条简单的文本信息?抱歉,得你自己去解析 NDEF 结构,还得熟悉 TLV 编码规则。
更麻烦的是,iOS 几乎完全缺席。那时苹果尚未推出 Core NFC 框架(直到 iOS 11 才发布),所以 Delphi 在 iPhone 上根本无能为力。即便在 Android 上,你也必须手动修改
AndroidManifest.xml
添加权限声明:
<uses-permission android:name="android.permission.NFC"/>
而且没有 IDE 自动注入机制,稍不注意就会遗漏。再加上缺少 NDEF 解析工具类,很多开发者最终选择了第三方库,比如
DSharp.Android.NFC
,来填补官方能力的空白。
可以说,这一阶段的 NFC 支持仅适合做概念验证,离实际部署还有很大距离。
10.2 Tokyo:曙光初现
转机出现在 10.2 Tokyo。Embarcadero 引入了两个重要类:
TNDEFMessage
和
TNDEFRecord
,终于让标准 NDEF 数据的读取变得可行。你现在可以这样写代码:
if ATag.HasNDEF then
begin
for RecordItem in ATag.NDEFMessage.Records do
begin
case RecordItem.TNF of
TNFTWellKnown:
if TEncoding.ASCII.GetString(RecordItem.TypeData) = 'T' then
ShowMessage('文本内容: ' + ExtractTextFromPayload(RecordItem.Payload));
end;
end;
end;
这里的
ExtractTextFromPayload
需要你自己实现,因为 Payload 第一个字节通常是语言码长度,接着是语言标识(如 “en”),然后才是真正的文本内容。虽然仍有手动处理成分,但至少已有明确的数据结构可供操作。
不过,写入功能依旧受限。
TNFCManager.Write()
方法虽已存在,但参数要求传入完整的 NDEF 字节数组,意味着你必须按照 NDEF 规范自行拼接 header、type length、payload length 等字段。这对新手极不友好,极易出错。
此外,iOS 依然无法使用,因为 Core NFC 尚未被集成。因此,10.2 更像是为 Android 平台打造的一个过渡版本,适合只需要读取文本或 URL 的项目。
10.4 Sydney:真正的转折点
如果说 10.2 是破冰,那 10.4 Sydney 就是全面解冻。这是首个真正意义上支持 全平台双向通信 的版本。无论你在 Android 还是 iOS 上,都可以流畅地读写 NDEF 标签。
iOS 方面,Delphi 终于接入了
CoreNFC.framework
,允许应用发起 NFC 会话。不过出于隐私考虑,苹果强制要求用户主动点击按钮才能启动扫描界面,不能后台静默监听。这点不同于 Android,务必在设计交互时加以考虑。
更重要的是,API 设计趋于统一。现在你可以用几乎相同的方式构建并写入一条 NDEF 消息:
procedure TForm1.WriteTextToNFC(const Text: string);
var
RecordItem: TNDEFRecord;
NDEFMsg: TNDEFMessage;
begin
RecordItem := TNDEFRecord.Create;
try
RecordItem.TNF := TNFTWellKnown;
RecordItem.TypeData := TEncoding.ASCII.GetBytes('T');
RecordItem.Payload := TEncoding.UTF8.GetBytes(#$02 + 'en' + Text);
NDEFMsg := TNDEFMessage.Create([RecordItem]);
try
NFCManager1.Write(NDEFMsg,
procedure(const Success: Boolean)
begin
TThread.Queue(nil,
procedure
begin
ShowMessage(ifthen(Success, '写入成功', '写入失败'));
end);
end);
finally
NDEFMsg.Free;
end;
finally
RecordItem.Free;
end;
end;
这段代码在 Android 和 iOS 上都能运行。回调机制确保了异步操作的安全性,UI 更新不会因跨线程访问而出错。同时,IDE 开始自动插入必要的权限描述,减少配置疏漏的风险。
当然,仍有注意事项:
- 写入前应先检查
ATag.IsWritable
,有些标签是只读的;
- iOS 必须由用户触发扫描动作,无法自动唤醒;
- 某些老旧标签(如非标准格式的 MIFARE)可能无法正确识别。
但对于绝大多数企业级应用场景,如工牌识别、设备绑定、信息展示等,10.4 已经完全胜任。
11 Alexandria:稳中求进
到了 11 Alexandria,NFC 模块进入了优化期。虽然没有颠覆性新功能,但在稳定性、性能和调试体验上有明显提升。
最值得称道的是内存管理的改进。早期版本在频繁启停扫描或处理大量标签时偶现内存泄漏,而在 11 中这些问题基本得到修复。NDEF 解析器也更加高效,CPU 占用更低,尤其适合长时间运行的服务类应用。
新增的功能亮点包括:
- 对
NFCForum Type 4
标签的支持增强,这类标签常用于智能身份证或金融卡;
- 更详细的异常信息输出,便于定位问题;
- 在无 NFC 硬件的模拟器上,提供友好的提示而非直接崩溃;
- 日志系统加强,有助于分析标签响应时间、协议错误等细节。
尽管如此,平台限制依然存在。例如,MIFARE Classic 的加密扇区仍然无法通过标准 API 访问,需依赖 JNI 扩展或专用库破解。而 iOS 依旧不允许后台读取,所有扫描必须由用户显式启动。
但从工程角度看,11 Alexandria 是目前最适合用于生产环境的版本之一。它的 API 成熟、行为稳定、文档齐全,配合现代 FireMonkey 设计理念,能够支撑起复杂的企业级 NFC 应用。
实战建议:如何构建可靠且可维护的 NFC 应用
理论归理论,落地才是关键。以下是一些来自实战的经验法则,能帮你避开许多“纸上谈兵”看不到的陷阱。
权限配置别想当然
虽然 Delphi IDE 会尝试自动添加权限,但最好还是手动确认一遍:
-
Android
:确保
AndroidManifest.template.xml包含:
xml <uses-permission android:name="android.permission.NFC"/> -
iOS
:在
Info.plist添加键值对:
xml <key>NFCReaderUsageDescription</key> <string>本功能用于读取员工工牌,请允许使用 NFC</string>
少任何一个,App 都可能在运行时报错或静默失败。
先检测再行动
永远不要假设设备一定支持 NFC。哪怕是在旗舰机型上,也可能因硬件故障或系统策略禁用该功能。正确的做法是:
if not TNFCManager.IsSupported then
begin
ShowMessage('当前设备不支持 NFC 功能');
Exit;
end;
这句判断应放在任何 NFC 操作之前执行。它不仅能防止程序崩溃,还能引导用户换设备或关闭相关按钮,提升体验。
生命周期要匹配 UI
NFC 扫描不是一次性任务。如果在窗体关闭后仍未调用
StopDiscovery()
,系统可能会继续监听,导致资源浪费甚至后台耗电。建议遵循如下模式:
procedure TForm1.FormShow(Sender: TObject);
begin
inherited;
if TNFCManager.IsSupported then
NFCManager1.StartDiscovery;
end;
procedure TForm1.FormHide(Sender: TObject);
begin
inherited;
if NFCManager1.IsRunning then
NFCManager1.StopDiscovery;
end;
这样既能保证及时响应,又能避免过度占用硬件资源。
错误处理不可省略
NFC 操作失败的原因多种多样:标签距离太远、格式不兼容、写保护开启、甚至系统临时中断。与其让用户看到白屏或无反应,不如主动捕获异常并给出提示:
try
NFCManager1.Write(...);
except
on E: ENFCException do
ShowMessage('NFC 错误: ' + E.Message);
end;
结合重试机制(如三次尝试后提示更换位置),可大幅提高成功率。
测试必须用真机
模拟器无法模拟 NFC 硬件信号。即使 Delphi 提供了部分模拟行为,也无法替代真实世界的物理交互。强烈建议准备几种典型标签进行测试:
- NTAG215(常用,兼容性好)
- MIFARE Ultralight C(带加密)
- NFC Forum Type 4(用于身份证场景)
同时可用第三方 App(如 NFC Tools)验证标签内容是否正确写入,形成闭环验证。
写在最后
从 XE8 的蹒跚学步,到 11 Alexandria 的稳健前行,Delphi 的 NFC 支持走过了一条典型的渐进式演化之路。今天的
TNFCManager
已不再是那个功能残缺的实验品,而是一个足以支撑生产环境的成熟组件。
如果你正在规划一个新的 NFC 项目,答案很明确: 请使用 Delphi 10.4 或更高版本 。它们不仅提供了统一的跨平台 API,还兼顾了安全性、性能与开发效率。而对于仍在维护旧项目的团队,则应评估升级成本——毕竟,用现代方式重构一段复杂的 JNI 调用,往往比持续修 bug 更划算。
技术的价值不在于它有多先进,而在于它能否让人专注于解决问题本身。Delphi 在 NFC 领域的进步,正是朝着这个方向迈出的坚实一步。

931


被折叠的 条评论
为什么被折叠?



