iOS 11 ——迟来的 NFC

前言

NFC 这个词已经并不陌生了,前一段时间北京地铁支持 NFC 支付一时成为霸占头条的热点。其实在 90 年代末到 2000 年初,二维码和 NFC 就已经相继诞生,由于二维码成本低廉,技术门槛相对较低,因此,二维码迅速抢占了移动支付的市场,但 NFC 的发展并未因此停止。在 Android 端的 NFC 发展已经非常迅猛了,可惜 Apple 迟迟未开放接口,在今年的 WWDC 上,苹果宣布开放其 NFC 接口 CoreNFC, 这为以后 NFC 的应用提供了更多的可能。

正文

如果你对 NFC 这项技术还比较陌生,那么这里科普一下,NFC(Near Field Communication)近场通信,当两个设备相互靠近时能进行信息交流。许多企业讲 NFC 芯片放到卡片里,用带有 NFC 芯片的卡片来授予权限将允许谁有权限,比如说进出入公司。Apple CoreNFC 目前支持的格式有限,NFC 数据交换格式或 NDEF(通常用于当今市场上的大多数平板电脑和手机),比如 Apple Pay 。

CoreNFC Demo

这里我们通过一个简单的实例程序来演示怎么使用 CoreNFC,这个程序可以用来读取存储在卡片上 NDEF 格式的信息。

working-scanner.png

为此,我使用 Arduino Uno 与 Adafruit PN532 Shield 配对,将其发送到样品 NDEF 格式的卡上。 如果你不具备这些东西,或者根本不想在这样的硬件上投入时间和金钱,请尝试找一张带有信息的预格式化卡。 本文中,我不会演示 NFC 格式化以及如何把数据存储到 NDEF 卡 中。

Getting Started

打开 Xcode 9 创建一个简单的 Swift 工程。使用 Storyboard 创建简单的页面:

ViewController 如下:

import UIKit
 
class ViewController: UIViewController {
 
    @IBOutlet weak var messageLabel: UILabel!
 
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
 
    @IBAction func scanPressed(_ sender: Any) {
        // this is our newly created IBAction
    }
 
}

Entitlements & Privacy

我们的 app 要使用 NFC 必须进行应用授权:前提是你得有一个有效 Apple id (交过保护费的). 进行应用程序授权和隐私设置,打开developer.apple.com。 登录你的帐户,创建一个证书 —— 注册一个新的 APP ID。应用说明应该要支持 NFC 点击下一步,确保你的确认页面如下图:

然后再创建 provisioning profile :

这一步完成了,在我们刚创建的项目中导入 证书和描述文件,完成之后呢,我们还需进行 Info.plist 配置 Privacy:

至此,我们的开始工作就完成了。👇我们进入 coding 阶段。

Core NFC

要实现 NFC 功能,我们得接入 Core NFC framework:

import CoreNFC 

目前为止,iOS模拟器尚未支持 CoreNFC。 这意味着如你尝试导入CoreNFC,会收到一条错误,表示没有名为 CoreNFC 的模块。 遇到这种情况,请选择你的 iPhone 或 Generic iOS Device。接下来我们实现 NFCNDEFReaderSessionDelegate 协议:

import UIKit
import CoreNFC 

class ViewController: UIViewController, NFCNDEFReaderSessionDelegate { 

    @IBOutlet weak var messageLabel: UILabel!
    var nfcSession: NFCNDEFReaderSession?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func scanPressed(_ sender: Any) {

    }

    func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
        print("The session was invalidated: \(error.localizedDescription)")
    }

    func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
        // Parse the card's information
    }
}

其中两个 readerSession 函数会分别告诉我们 NFC 会话成功或失败,成功后则返回 NFCNDEFMessage 格式的通信数据,失败后会返回 error 信息。
  当然,我们首先还需要初始化 NFCNDEFReaderSession 并开启 NFC 监听。

@IBAction func scanPressed(_ sender: Any) {
    nfcSession = NFCNDEFReaderSession.init(delegate: self, queue: nil, invalidateAfterFirstRead: true)
    nfcSession?.begin()
}

然后运行程序,看看:

如果提示 Session is invalidated unexpectedly ,那么请仔细核对 证书、描述文件以及 Privacy 设置是否正确。
这个过程并不难,简单几步就能搞定,下面我们来看看怎么解析获取到的 message 。

解析 Message

首先,让我们来看一下这个函数:

func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) 

让我们来看看每一个 message 对象包含了哪些信息:

print(messages[0])

我们可以看到:

( // Payload one (There's only one payload in this card)
    "TNF=1, /* Type Name Format */
    Payload Type=<55>,
    Payload ID=<>,
    Payload=<0048656c 6c6f21>" /* What we're really interested in */
)

根据打印的结果我们可以看出:
. messages 是一个 NFCNDEFMessages 对象的数组。
. NFCNDEFMessage 有一个 NFCNDEFPayload 对象数组 records
然后我们再来看看每一个 payload 又包含了哪些信息:

  1. identifier.
  2. type.
  3. typeNameFormat.
  4. payload.

这里其实我们只关心 payload 。好了,看看如何解析 records 吧。

func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
    var result = ""
    for payload in messages[0].records {
        result += String.init(data: payload.payload.advanced(by: 3), encoding: .utf8)! // 1
    }

    DispatchQueue.main.async {
        self.messageLabel.text = result
    }
}

来看看最终的效果:

nice result

参考

Working with CoreNFC in iOS 11

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容