十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

NFC一碰连原理与NTAG215标签DIY实战:从Android读写到智能家居自动化

NFC一碰连原理与NTAG215标签DIY实战:从Android读写到智能家居自动化 之前买了一个米家智能肩颈按摩仪到手后最让我感兴趣的其实不是它那9种按摩模式和温感热敷反而是侧面那个“NFC一碰连”。碰一下手机APP自己弹出来该连的设备连上该开的模式开好整个过程不用打开应用找半天也不用等蓝牙配对。这种感觉就像手机本来就知道你要干什么。这个体验背后其实就是 NFC 技术。很多朋友每天都在用 NFC但对它的理解可能还停留在“手机可以刷公交”“门禁卡能复制到手机上”这个层面。这篇教程就借着米家这款产品的功能场景把 NFC 的原理、标签结构、手机端读写方式以及怎么用 NTAG215 这类标签 DIY 一个属于自己的“一碰连”快捷区完整讲一遍。内容适合对 NFC 原理感兴趣的入门开发者也适合想自己动手做 NFC 自动化场景的智能家居玩家。1. NFC 是什么先搞懂“一碰连”背后的技术1.1 NFC 的定义与核心特征NFCNear Field Communication近场通信是一种短距离高频无线通信技术工作频率为 13.56MHz有效通信距离通常在 4 厘米以内。它是在 RFID射频识别技术基础上演化而来的兼容了部分 ISO/IEC 14443、ISO/IEC 15693 等国际标准。NFC 有非常明显的几个特点距离近一般要贴到 4 厘米甚至更近才能触发误触的概率很低。功耗低被动式标签不需要内置电池靠读写器发射的射频场供电。双向通信两个 NFC 设备之间可以互相交换数据不只是手机读标签。建立连接快相比蓝牙配对、Wi-Fi 配置NFC 的握手过程几乎是瞬时的。手机上的“一碰连”体验本质上就是手机里的 NFC 控制器在感应到目标设备或标签后读取里面的 NDEF 数据再根据数据内容去启动对应的 APP、执行对应的动作。1.2 米家智能肩颈仪的 NFC 场景把 NFC 放在米家智能肩颈仪这类产品上解决的是一个很实际的痛点智能硬件越来越多每个硬件都要先“绑定 APP”再在 APP 里“连接设备”操作路径太长。尤其是一些肩颈仪、按摩披肩、筋膜枪之类的产品使用者往往只是想快速开始一次热敷按摩而不是研究怎么配网。用 NFC 一碰连的方式产品会在机身上嵌入一个 NFC 标签或 NFC 模块。手机碰一下APP 捕获到设备的 NFC 信息自动打开对应页面并完成连接初始化。用户省去了手动搜索蓝牙设备、输入 Wi-Fi 密码这些步骤这才是“一碰连”体验的核心价值。如果你愿意自己也能 DIY 出类似体验在床头贴一张 NFC 标签手机碰一下自动打开米家 APP在工位贴一张碰一下自动播放音乐。后面的实战章节会完整演示。2. NFC 的通信机制读卡器、标签与手机2.1 主动模式与被动模式NFC 通信有两种模式模式参与方说明主动模式双方设备都有电源通信双方交替产生射频场常用于两台手机之间传输文件。被动模式一个读卡器 一个无源标签读卡器产生射频场无源标签从射频场取电并回复数据常用于门禁卡、NFC 贴纸、智能设备初始化。手机读取 NFC 标签就是典型的被动模式。手机当作读写器标签不需要电池所以才可以把标签做得像一张卡片或贴纸一样薄。2.2 NDEF 是什么NDEFNFC Data Exchange FormatNFC 数据交换格式是 NFC 论坛定义的一种标准数据格式。不管是标签、手机还是智能硬件只要支持 NDEF就可以互相理解对方的数据内容。一个 NDEF 消息Message可以包含多条记录Record每条记录的类型可以是Text 类型一段纯文本。URI 类型一个网址或 URL 前缀比如https://、mailto:、tel:。MIME 类型自定义的媒体类型类似application/vnd.example-format。AAR 类型Android Application Record用于指定需要打开哪个 Android 应用。最常见的一个场景把一条 NDEF 记录写入 NTAG215 标签记录内容是https://example.com手机碰一下就会用浏览器打开这个 URL。如果是 AAR 记录则会直接拉起对应的 APP。3. NFC 标签与数据存储结构3.1 常见 NFC 标签类型NFC Forum 把标签分成五类目前消费市场上最容易买到的是 NTAG21x 系列比如 NTAG213、NTAG215、NTAG216它们都属于 Type 2 标签。型号用户可用内存典型场景NTAG213144 字节名片、网址分享、小数据存储NTAG215504 字节常用于游戏手办、音乐墙、较长的 NDEF 数据NTAG216888 字节需要更多存储空间的 DIY 场景米家智能肩颈仪这类厂商标配设备机身里嵌入的可能是 NTAG 系列标签也可能是成本更低的 NFC 芯片模块甚至有些设备用的是带加密算法的 NFC 芯片具体取决于产品定位和防伪需求。3.2 标签的 Page页结构Type 2 标签的存储空间按“页Page”划分每一页固定为 4 字节。以 NTAG215 为例从第 0 页开始前几页有固定的用途页地址存储内容说明Page 0x00UID 前 4 字节出厂唯一标识只读Page 0x01UID 后 4 字节 BCC1校验字节出厂写入Page 0x02UID 末尾 4 字节 内部字节含芯片内部配置字段Page 0x03CCCapability Container描述标签容量和 NDEF 支持情况Page 0x04 之后用户数据区可写入 NDEF 消息、文本、URL 等打开 NFC 读写工具看标签信息时通常能看到每个页的十六进制数据。比如一枚 NTAG215 的 CC 页可能显示为E1 10 6E 00表示标签支持 NDEF、容量规格等。不同品牌的 NTAG 芯片具体字节可能有差异但 Page 结构基本遵循 Type 2 规范。3.3 为什么“破解”“复制”标签不靠谱网上经常能看到“NFC 破解”“门禁卡复制”之类的说法。从技术原理上看普通 NTAG 标签因为是明文存储、无加密确实可以被设备读出并写入新的空白标签这就是很多人能复制门禁卡的原因。但需要注意的是复制他人标签可能涉及违法不要用来做破坏或绕开管理的事情。很多新的门禁卡、智能锁、公交卡采用的是 CPU 卡或加密卡内部有密钥体系和防克隆机制普通 NTAG 工具根本无法读取。NFC 支付依赖的是安全单元SE或 HCE 动态加密不是简单把卡号写在标签里。作为开发者正确使用 NFC 的方式是做合法授权场景下的自动化、设备初始化、数据交换而不是绕过别人的安全边界。4. Android 手机如何读写 NFC 标签4.1 读取 NDEF 标签的基础代码在 Android 上开发 NFC 功能首先需要在AndroidManifest.xml中声明 NFC 权限并添加 NDEF_DISCOVERED 的 intent-filter。这样当手机碰到带有对应类型 NDEF 数据的标签时系统会自动把标签内容交给应用处理。!-- 文件路径app/src/main/AndroidManifest.xml -- uses-permission android:nameandroid.permission.NFC / application activity android:name.NfcReadActivity intent-filter action android:nameandroid.nfc.action.NDEF_DISCOVERED / category android:nameandroid.intent.category.DEFAULT / data android:mimeTypetext/plain / /intent-filter /activity /applicationKotlin 读取 NDEF 数据的核心逻辑如下// 文件路径NfcReadActivity.kt class NfcReadActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_nfc_read) handleIntent(intent) } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) handleIntent(intent) } private fun handleIntent(intent: Intent?) { if (intent null) return val rawMessages intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES) ?: return val textResult StringBuilder() for (rawMsg in rawMessages) { val msg rawMsg as NdefMessage for (record in msg.records) { if (record.tnf NdefRecord.TNF_WELL_KNOWN) { when (record.type.toString(Charsets.US_ASCII)) { NdefRecord.RTD_TEXT - { textResult.append(parseTextRecord(record)).append(\n) } NdefRecord.RTD_URI - { textResult.append(parseUriRecord(record)).append(\n) } } } } } binding.tvResult.text 读取到的内容\n$textResult } private fun parseTextRecord(record: NdefRecord): String { val payload record.payload val statusByte payload[0].toInt() and 0xFF val languageCodeLength (statusByte and 0x3F).toInt() return String(payload, languageCodeLength 1, payload.size - languageCodeLength - 1, Charsets.UTF_8) } private fun parseUriRecord(record: NdefRecord): String { val payload record.payload // payload 第一个字节是 URI 前缀标识符后面是去掉前缀的 URL val prefixCode payload[0].toInt() val prefix uriPrefixMap[prefixCode] ?: val uri String(payload, 1, payload.size - 1, Charsets.UTF_8) return prefix uri } }这段代码的核心作用是当手机贴近 NFC 标签时系统会通过NdefMessage把标签里的记录解析出来再按文本或 URI 类型展示。注意onNewIntent的覆盖很重要因为应用在前后台之间切换时可能会多次收到新的 NFC 扫描结果。4.2 写入 NDEF 标签的代码示例除了读取Android 也支持把数据写入兼容的 NFC 标签。写入前需要检查标签是否可写、是否已只读并且建议尽量避免覆盖含有重要数据的标签。下面是一个写入文本记录的 Kotlin 示例// 文件路径NfcWriteActivity.kt class NfcWriteActivity : AppCompatActivity() { private var nfcAdapter: NfcAdapter? null private var pendingTag: Tag? null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_nfc_write) nfcAdapter NfcAdapter.getDefaultAdapter(this) // 通过 enableForegroundDispatch 在页面可见时优先处理 NFC 事件 // 具体需要在 onResume/onPause 中调用 enable/disable } fun writeTextToTag(view: View) { val pendingIntent PendingIntent.getActivity( this, 0, Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE ) val filters arrayOf(IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)) nfcAdapter?.enableForegroundDispatch(this, pendingIntent, filters, null) } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) if (intent.action NfcAdapter.ACTION_TAG_DISCOVERED) { val tag intent.getParcelableExtraTag(NfcAdapter.EXTRA_TAG) if (tag ! null) { writeNdef(tag, 米家智能肩颈仪 一碰连) } } } private fun writeNdef(tag: Tag, content: String) { val textRecord NdefRecord.createTextRecord(zh, content) val message NdefMessage(arrayOf(textRecord)) val ndef Ndef.get(tag) if (ndef ! null) { try { ndef.connect() if (!ndef.isWritable) { Toast.makeText(this, 标签只读写入失败, Toast.LENGTH_SHORT).show() return } ndef.writeNdefMessage(message) Toast.makeText(this, 写入成功, Toast.LENGTH_SHORT).show() } catch (e: Exception) { Toast.makeText(this, 写入失败${e.message}, Toast.LENGTH_SHORT).show() } finally { try { ndef.close() } catch (_: Exception) { } } } else { Toast.makeText(this, 该标签不支持 NDEF 写入, Toast.LENGTH_SHORT).show() } } }写入之前一定要通过isWritable判断不能直接写。有些标签出厂时被厂商锁定为只读这种情况需要更换标签或在标签策略里选择支持多次写入的型号。5. 实战用 NTAG215 DIY 一个“一碰连”快捷区5.1 场景设计与材料准备先明确我们要实现的目标在工位上贴一张 NFC 标签手机碰一下自动打开米家 APP在茶几或床头贴一张手机碰一下自动播放指定歌单或打开音乐应用如果动手能力更强还能做成“音乐墙”用多张 NTAG215 标签对应不同的歌曲快捷链接。准备材料如下NTAG215 空白标签贴纸若干推荐买 25mm 或 30mm 直径的圆形贴纸。一部支持 NFC 的 Android 手机MIUI、ColorOS、HarmonyOS 等主流系统均可。NFC Tools、NFC TagWriter 等读写工具 APP任选一种即可。如果打算自己开发写入工具用 Android Studio 搭建工程。5.2 方案一直接用 NFC Tools 写入 URL 或 APP 启动对于多数用户来说不需要写任何代码用 NFC Tools 这类工具 APP 就能完成写入操作流程如下手机开启 NFC 和“NFC 读写”相关开关。打开 NFC Tools选择“写入Write”功能。选择“添加记录Add a record”。如果希望碰标签后打开某个 URL选择 URI输入完整的网页地址。如果希望碰标签后打开某个应用选择“应用Application”类型从手机已安装应用列表里选择“米家”或“酷狗音乐”。点击“写入Write”把手机贴近空白标签等待写入完成。写入成功后锁屏状态下再碰一下标签系统会提示打开对应 APP。这里有一个细节值得注意NFC Tools 的“应用”类型在 Android 底层本质上就是 AARAndroid Application Record或 URI 方式。推荐选择“应用”而不是手动输入 URL因为 AAR 会直接让系统拉起指定应用减少中间跳转。5.3 方案二用代码写入 AAR 记录指定打开米家如果你的需求是定制化批量写入比如要在 50 张标签上写入品牌信息、设备序列号、启动特定应用那用代码更合适。写入 AAR 记录的 NDEF 消息核心代码可以这样写// 文件路径NfcWriteAarActivity.kt private fun createAppLaunchMessage(packageName: String, payloadText: String): NdefMessage { // 1. 创建 AAR 记录指定打开的 APP val aarRecord NdefRecord.createApplicationRecord(packageName) // 2. 创建一段文本记录作为业务数据 val textPayload NdefRecord.createTextRecord(zh, payloadText) // 3. AAR 需要放在记录列表的最后系统先读取前面的记录再拉起指定应用 return NdefMessage(arrayOf(textPayload, aarRecord)) } // 调用示例把米家 APP 作为启动目标 val message createAppLaunchMessage(com.xiaomi.smarthome, 米家智能肩颈仪 一碰连)这段代码的关键是createApplicationRecord。Android 系统在扫描到 NDEF 消息时如果识别到 AAR 记录会直接尝试启动packageName对应的应用如果没有安装则会去应用市场搜索。5.4 方案三碰一下自动播放音乐DIY 音乐墙网络上很火的“NFC 音乐墙”是用多张 NTAG215 标签对应不同歌曲链接。比如把标签贴在墙上或手机壳上每一张标签里写入一首歌的 URL手机碰一下就能直接播放对应歌曲。写入内容时需要在标签里保存类似下面的 NDEF 数据记录 1URI 类型 https://music.example.com/song/123456 记录 2AAR 类型 com.kugou.android 或 com.kugou.android如果使用现成的音乐 APP 快捷链接格式比如酷我音乐、酷狗音乐生成的歌曲分享链接直接把这些链接写入标签即可。建议在写入前把标签容量算好一首普通歌曲的分享 URL 很短NTAG215 的 504 字节完全够用但如果是超长的营销参数链接就需要优先选用 NTAG216。5.5 配合系统自动化实现真正“无感触发”仅仅打开 APP 还不够还可以配合系统自动化能力。以小米 MIUI 为例可以在“手机管家 - 快捷功能 - 万能遥控 / 触达”里设置 NFC 标签触发规则也可以使用“米家 APP - 自动化”功能把 NFC 标签作为触发条件然后联动智能家居设备。一个比较实用的组合是在床头贴一张标签碰一下触发家中灯光切换成“助眠模式”。在书桌贴一张标签碰一下启动“专注模式”自动打开白噪音 APP、打开勿扰模式、调整灯光色温。在健身区贴一张标签碰一下打开米家 APP 里的“肩颈放松”模式同时联动加湿器和香薰机。这种组合的关键思路是把 NFC 标签当成一个“物理快捷键”。手机不需要主动打开任何 APP只要碰一下就触发一套完整的自动化流程。对智能家居玩家来说体验会比喊“小爱同学”更直接、更稳定因为不需要语音识别也不会受环境噪音干扰。5.6 完整项目示例用 Kotlin 实现 NFC 标签读写器下面整理一个最简单的完整工程示例。继续使用 Kotlin只保留读写两个核心页面。项目结构 NfcDemo/ ├── app/ │ ├── src/main/ │ │ ├── java/com/example/nfcdemo/ │ │ │ ├── MainActivity.kt │ │ │ ├── NfcReadActivity.kt │ │ │ └── NfcWriteActivity.kt │ │ ├── res/ │ │ │ ├── layout/ │ │ │ │ ├── activity_main.xml │ │ │ │ ├── activity_nfc_read.xml │ │ │ │ └── activity_nfc_write.xml │ │ └── AndroidManifest.xml │ └── build.gradle.kts └── build.gradle.ktsMainActivity 的布局放两个按钮分别跳转到读取和写入页面。NfcReadActivity 和 NfcWriteActivity 的核心代码在上文已经给出这里补充一个清单方便对照检查功能关键类关键方法获取 NFC 适配器NfcAdaptergetDefaultAdapter(context)前台调度NfcAdapterenableForegroundDispatch / disableForegroundDispatch解析消息NdefMessage / NdefRecordgetRecords() / getPayload()创建文本记录NdefRecordcreateTextRecord(language, text)创建 URI 记录NdefRecordcreateUri(uriString)创建 AAR 记录NdefRecordcreateApplicationRecord(packageName)写入标签Ndef / NdefFormatablewriteNdefMessage(message)最终编译安装后在写入页面贴近标签输入内容点击写入在读取页面贴近标签即可看到刚才写入的数据。整个过程只依赖系统 NFC 能力和 NDEF 标准不依赖任何私有 SDK所以能够在绝大多数 Android 手机上复用。6. 常见问题与排查思路实际使用 NFC 标签时大家经常会遇到各种奇怪的现象。下面把高频问题整理成一张排查表。问题现象常见原因解决思路手机碰标签没有反应手机 NFC 未开启或手机壳过厚、金属材质屏蔽信号打开 NFC 开关去掉金属壳或改用品牌原装壳APP 识别到标签但无法读取标签损坏或写入时格式错误用 NFC Tools 查看标签原始页数据确认是否为 NDEF 格式写入失败标签已只读标签被锁定或部分标签出厂预设只读更换空白标签购买时确认支持多次读写碰标签后打开错误的 APPNDEF 中 AAR 记录目标与应用实际包名不一致检查packageName建议通过应用信息页确认包名部分手机碰到标签会弹“无法识别”标签中的 NDEF 内容不符合 NFC Forum 规范删除旧内容使用工具 APP 重新格式化再写入锁屏状态下无法触发系统默认禁止后台读取标签在系统设置中开启 NFC 标签读取或使用前台调度手机壳带磁吸或金属环磁环干扰了 13.56MHz 射频场移除磁吸配件测试标签位置远离磁吸区域如果你的标签写入之后手机完全识别不到原始十六进制数据可以先用 NFC Tools 的“读取标签信息”功能看标签类型、UID、容量是否正常。如果 UID 都读不出来大概率是标签本身损坏或买到劣质芯片而不是代码问题。7. NFC 安全边界与工程建议虽然 NFC 标签方便但在实际工程和日常生活中必须注意安全边界。7.1 不要用普通 NFC 标签存敏感数据普通 NTAG 系列的存储内容是明文可读的任何人拿手机贴近标签都能完整读出 UID、数据区甚至复制整张标签。所以千万不要把 Wi-Fi 密码明文、支付密钥、身份信息等敏感数据直接写进普通 NFC 标签。如果必须使用 NFC 做身份识别或门禁类业务建议采用带安全加密芯片的方案每次认证生成动态签名数据。7.2 标签写保护针对已经写入并验证过的标签可以通过工具软件将标签设置为只读。只读后的标签无法被再次覆盖可以防止数据被恶意篡改。不过要注意设置只读是不可逆的设置前必须完整测试且确认数据正确。7.3 生产环境和设备接入建议如果你在做智能硬件产品比如像米家智能肩颈仪这种带 NFC 一碰连功能的设备有几点工程建议值得关注区分 NFC 标签和 NFC 模块标签成本低但只能读固定数据NFC 模块支持双向通信可以对设备状态做交互确认。需要根据产品交互复杂度选择。初始化流程要兼顾首次使用第一次使用 NFC 配对时手机可能还没安装对应 APP此时建议在 NDEF 数据里同时写入 AAR 记录和下载链接保证手机能自动跳转到应用商店。做好异常回退NFC 触发失败时产品要保留蓝牙按钮、手动扫码等传统连接方式不能把 NFC 作为唯一入口。多环境验证不同手机的 NFC 天线位置不同很多手机 NFC 天线在背面摄像头附近硬件设计时要考虑标签位置和手机持握姿势的匹配。如果你只是个人 DIY也要注意“最小权限”原则比如给访客使用的标签只允许触发某个固定 URL不要给它写入权限。8. 总结与下一步实践方向从米家智能肩颈仪的“NFC 一碰连”这个产品细节出发我们完整梳理了 NFC 的通信原理、NDEF 数据格式、标签 Page 结构、Android 读写方法以及用 NTAG215 做 DIY 自动化场景的全部思路。下一步你可以按照自己的兴趣选择实践方向想入门的读者可以先买几张 NTAG215 标签用 NFC Tools 写几个最简单的 URL体验一下“碰一下打开网页”的效果。想做自动化的读者尝试把标签贴在床头、书桌、玄关配合手机系统和米家 APP 的自动化规则搭建自己的“物理快捷键”体系。想深入开发的读者可以继续学习 Android NFC 前台调度、Host Card EmulationHCE模拟卡片以及 NDEF 自定义 MIME 类型的原理。最后提醒一句NFC 标签本身只是一个低成本的“数字索引”真正让它有价值的是背后的业务链路。无论是厂商设备里的初始化逻辑还是你自己 DIY 的自动化流程搞清楚标签里存什么、手机拿到数据后触发什么动作整个闭环才跑得通。
返回列表