本文主要是以「飞书」小程序为准,兼容「微信」小程序,如果没有了解过「飞书」的同学,可以点击此处去官网了解
什么是 NFC
近距离无线通信(英语:Near-field communication,NFC),又简称近距离通信或近场通信,是一套通信协议,让两个电子设备(其中一个通常是移动设备,例如智能手机)在相距几厘米之内进行通信。
近场通信技术由非接触式射频识别(RFID)演变而来,由飞利浦半导体(现恩智浦半导体,缩写 NXP)、诺基亚和索尼共同于2004年研制开发,其基础是RFID及互连技术。近场通信是一种短距高频的无线电技术,在13.56MHz频率运行于20厘米距离内。其传输速度有106 Kbit/秒、212 Kbit/秒或者424 Kbit/秒三种。
NFC 其实在刚诞生的时候我就一直在关注,但是不仅仅应用少,而且搭载的设备也少,甚至小米还出现过前一代搭载 NFC 后一代却不搭载的神奇情况。除此之外,使用起来也是特别复杂,想当初,要用 NFC 去实现刷公交卡,你需要去换一个特殊的 SIM 卡才能够支持(当初不理解,现在想来大概率是因为安全问题)。
在现在,随着安卓厂商的不懈努力,现在不论是应用还是设备的安装率都已经逐渐普及开来。从最初 NFC 也就能在支付宝中扫银行卡快速输入卡号,到现在的公交刷卡、X Pay,甚至传输文件,华为甚至给这个东西换了个名字叫做一碰系统(率感无语)。
除此之外,还能推进智能化的发展。比如以后家庭中加入了一个新设备,那么不再需要繁杂的联网过程,直接扫一下机器身上的 NFC 识别码就可以直接将设备加入到家庭网络中。或者说华为路由器上的一碰连接 Wifi 我觉得就是一个极好的应用。当家里来客人的时候,就不再需要一个人一个人的输入密码了。
NFC 技术一览
运行模式
NFC 现在主要有三种运行模式,分别是卡模拟模式(Card Emulation Mode)、主机模拟模式(Host Emulation Mode)、读卡写卡模式(Reader/Writer Mode)、P2P 模式(P2P Mode)
卡模拟模式
NFC手机可以模拟成为一张非接触卡,通过 POS 机(非接触读卡器)的 RF 来供电,即使 NFC 手机没电也可以工作。
现在很常见的比如 Apple Pay,BYD NFC 钥匙,都是能够实现在断电情况下的刷卡
主机模拟模式
该模式与卡模拟模式很类似,只不过卡模拟无需供电或者说无需 App 的参与就可以完成,但是主机模拟模式是不行的,他是通过将所有的消息转发给应用,由应用去决定该模拟什么内容,也就说该返回什么内容
现阶段很多支付钱包,比如云闪付、京东闪付等等都是通过该模式实现的。
读卡写卡模式
NFC手机可以通过触碰NFC标签(Tag),从中读取非接触标签中的内容,采集数据并发送到对应的应用进行处理。
最常见的应用其实就是华为的一碰系列,除此之外,支付宝支持直接读取信用卡、储蓄卡的卡号。
P2P 模式
两个NFC设备可以近距离内互相连接,直接传递数据,实现点对点数据传输。
例如协助快速建立蓝牙连接、交换手机名片和数据通信等。
最常见的是手机互传、Android Beam。
协议标准类型
因为 NFC 的发展过程的原因,曾经出现过多个协议,甚至每家公司都有不同的协议内容。但现在主要是有一下几个协议标准:
ISO / IEC
主要定义了一下几个协议:
ISO/IEC 18092 / ECMA-340— (NFCIP-1)
Near Field Communication Interface and Protocol-1
ISO/IEC 21481 / ECMA-352— (NFCIP-2)
Near Field Communication Interface and Protocol-2
除此以外,还有一个协议标准很常用,是 ISO-14443 协议,其实这个协议是 RFID 的协议,和上面的唯一区别就是上面的多了一些其他模式的标准,比如点对点模式。
ISO-14443 协议有两个子类,分别是 Type-A 和 Type-B,这两个在 Android 也被称为 NFC-A 和 NFC-B。
但不幸的是,这些协议也不能免费看,要花钱的
NFC Forum
NFC Forum 是一个在 2004 年创建的非盈利行业协会,其成员来自NFC生态系统的各个部分。另外我主要关注了下国内公司,比较知名的有小米、中国移动通讯。
但是你想要从该组织获取任何关于 NFC 相关的技术标准,首先你的公司要成为该组织的成员才行,因为字节根本不在该组织,所以没法从这里获得一手的信息。
不过办法也是有的,该协会的创办者 NXP 公司网站上是有相关的数据资源,后文的参考此资源。
其他
不用管.jpg
沟通协议
以 NFC-A 为例
整个 NFC 卡片其实内部就是一个有限状态机,根据当前不同的状态需要不同的操作。这个图看起来很复杂,其实主要额外包含了两个操作:
密码校验
这个是说 NFC 卡是经过加密的,只有在密码校验通过之后,才能够进行相关的操作。
有一点特殊的是,NFC 的密码长度其实是固定的,即 32 位,4 个字节。
防冲突
之所有有这个设计,是因为在使用过程中,可能会出现同时扫描到多个 NFC 设备的情况,此时就需要通过 READY1/READY2 两个状态来选择正确的 NFC 设备进行操作。
每个卡片都有一个唯一 UID,长度为 7 字节,而每次操作只能选择 4 个字节,所以不得不拆分成两个状态两步去操作。
当没有上面两个操作的时候,可以简单的执行 IDLE -> ACTIVE -> HALT 的状态流程,也就是说连接、操作(也就是读写)、关闭。
存储设计
NFC 在存储上设计了页的概念,一个页表示 4 个字节,以页为最小单位进行操作。所以 NFC 卡片的存储容量其实都是 4 的整数倍。
这里以 NTAG213 180 字节的存储结构为例
这里只需要关注两点:
用户数据存储的空间是从第四页开始
用户可存储空间其实只有 144 字节
只需要记住这两点,在开发 NFC 需求的时候,不要去修改非用户空间的数据,不要存储过长的内容。
设备准备
在有了上面的基础之后,别急你还是不能开始开发 NFC,因为你还缺少至关重要的一个东西,设备
遗憾的是,不是所有的设备都有 NFC 硬件的,也不是说有了 NFC 硬件就能用的
苹果设备只有升级到 iOS 13 以上才能具有开发 NFC 读卡器的能力,不能写入,除此之外,几乎没有其他的 NFC 能力可以使用。机圈也会叫做阉割版 NFC。(暂时没有能力去调研 NFC 的能力一定是需要硬件支持还是说只是软件限制)
安卓设备理论上可以使用几乎所有的 NFC 能力,机圈内叫全功能 NFC,包括读卡、写卡、卡模拟、P2P 等模式。但是不同的手机有着不同的操作系统的限制,所以要选择一个合适的操作系统(原生安卓、类原生安卓是最推荐的)。
所以,请准备好一台安卓手机!
NFC 卡片
在有了设备之后,还要选择正确的 NFC 卡片,因为不是任意一个 NFC 卡片都是可以用的,比如工牌、银行卡等等。这是因为 NFC 卡片是带有加密的,在操作之前必须要通过验证才能操作,所以建议去淘宝买一些可读可写无加密的 NFC 贴纸用于测试。
不过你在淘宝上买的可能是写着 NTAG213 的型号,其实这个是 NXP 出的一款设备,但是支持兼容 ISO NFC-A 协议以及 NFC Forum Type 2 协议,所以大家可以放心使用。
当然了,你也可能看到 NTAG215/NTAG216,这两个都没有任何区别,只是存储空间不同而已。
小程序 API
此时在有了上述的基础知识后,别急,还要了解下小程序的 API 才能更好的开发。
就目前来说,所有与 NFC 相关的操作都被封装到了 NfcAdaptar
类中,通过 tt.getNFCAdaptar()
获取 nfcAfaptar
对象。
具体的 API 参数细节请参考「飞书开放平台」
NFC 整体流程
注册 NFC 发现事件回调
nfcAdaptar.onDiscovered
开启 NFC 扫描
nfcAdaptar.startDiscovered
NFC 卡片贴近设备
触发回调,通过回调可以获得 NFC 支持的协议
- 回调参数内的 techs 字段可以用于判断当前卡片支持的协议
根据协议去读写 NFC 卡片内容
nfcAdaptar.getNfcA()
关闭 NFC 扫描,关闭事件监听
nfcAdaptar.offDiscovered
/nfcAdaptar.stopDiscovered()
可以发现这个流程非常容易理解,也非常容易操作。那么接下来我们看下重头戏
读写 NFC 卡片
这里以 NFC-A 协议为主
通过 nfcAdaptar.getNfcA()
获取操作 NFC-A 卡片的操作类实例 nfca,流程如下
连接卡片
nfca.connect()
读写卡片
nfca.transceive()
读写完成之后关闭连接
nfca.close()
关键点来了,NFC 卡片的读写不和其他的 IO 设备类似,有专门的 read 和 write 函数。对 NFC 来说,通过给 NFC 卡片发送不同的指令来做到完成不用的操作。
这些指令都在 NTAG213 文档中有写,这里简单列一下常用的数据
命令 | 代码 | 功能 | 参数 |
---|---|---|---|
Read | 0x30 | 一次读取四个页的数据 | <Addr:1B> |
Write | 0xA2 | 一次写入一个页的数据 | <Addr:1B> <Data:4B> |
Fast Read | 0x3A | 一次读取多个页的数据 | <StartAddr:1B> <StopAddr:1B> |
比如我要读取第四页的数据,可以写如下代码
1 | nfca.transceive({ |
根据协议,其实还要传 CRC:2B,也就是校验位,不过这个操作已经由 Android 去做掉了,所以就不需要传了,也不需要去了解校验算法
结语
至此,NFC 开发算是入门了,不过这里要注意不同的 NFC 卡片不同的协议会有不同的读写方式,这里要根据你们各自具体的卡片来看。而且有的还有密码保护,还需要额外再走校验的逻辑。