
在2017的WWDC,苹果终于发布了众多开发者期待已久的系统级框架 CoreNFC。可能你对于NFC是什么并不是很了解,简而言之,NFC(近场通信)就是当两台硬件设备相距4cm以内时可以实现互相通信。NFC在商业上的应用是把NFC芯片集成到各类卡片中,极大的加强安全性。目前 CoreNFC 只支持一种格式:NFC Data Exchange Format,简称NDEF(常被用于平板电脑和智能手机中)。
提示:接下来的教程你需要
Xcode9 beta,同时你也需要一部iPhone7或者iPhone 7 Plus运行iOS 11系统来验证本教程中的一些新特性。Xcode9 beta可以同时支持Swift 3.2和Swift 4.0,本教程的代码都将使用Swift 4.0来编写。只是在项目中导入CoreNFC是无法构建或者编译一个App的,必须在物理设备上才可以运行。同时你还需要一个已经付费的开发者账号才可以。
什么是CoreNFC
通过
NFC,你可以阅读到包括NFC数据交换格式(NDEF)数据中的1到5类的近场通讯标签。读取标签,你的App创建了一个NFC数据交换格式的reader session并且提供了一个delegate。正在运行的reader session轮询NFC标签,并在delegate方法中找到包含NDEF消息的标签时传递消息,并将该消息传递给delegate。delegate可以读取消息并处理异常。
NFC谈不上“新”技术。苹果终于向开发者开放了这个 API,以便我们可以利用 NFC 识别信息。
举一个实际的例子
你经营一家商店,希望客户进入后,使用有NFC功能的手机扫描一件商品,就直接完成了所有的流程。没有任何麻烦,没有等待时间。作为一名App开发人员,在不使用NFC的情况下,还可以选择条形码或二维码,但依然比NFC麻烦很多。
说来说去NFC到底是什么?苹果虽然放开了NFC的使用权限,但苹果公司严格限制了我们的访问。这意味着CoreNFC只支持前面提到的NDEF格式。如果您打算使用CoreNFC替换您的`RFID卡,恐怕还有待时间。
准备工作
我们将用一个 demo 来展示如何使用 CoreNFC 。我们的应用程序将读取存储在 NDEF格式 卡上的信息。

为此,我使用 Arduino Uno 与 Adafruit PN532 Shield 配对,将消息编程到 NDEF 格式的样品卡上。如果您没有这些工具,或者根本不想将时间和金钱投入到这样的硬件中,请尝试找到一张带有消息的预格式化卡。在本教程中,我将不会将 NFC 格式化或将消息嵌入到 NDEF 卡中。

我们开始吧
要创建我们的项目,请打开 Xcode 9 并创建一个新的 single-view application 。然后命名您的项目,并确保选择 Swift 作为您的语言。

设计消息视图
为达到目的,我们需要制作用户界面(UI),供用户进行交互。我们先创建一个导航控制器。点击 Main.storyboard 并选择View-Controller。然后,转到status-Bar,然后单击Editor>embed in>Navigation Controller。这会在View-Controller的顶部创建一个导航栏。您可以选择一个合适的标题。我起的标题为 Message in a Bottle。

接下来,拖动UIButton并将其放在 View-Controller 的底部。将按钮的文本更改为扫描,并根据需要进行初始化。添加扫描按钮后,利用UILabel添加背景标题。
现在我们的应用应该是这样的:

设置扫描和消息
现在我们已经做好了基础设置,接下来我们将为按钮和标签通过拖线设置属性,并为按钮设置点击行为。

代码如下:
1 | import UIKit |
设置应用程序权限和隐私
接下来,在我们真正开始研究我们的 NFC 实现之前,我们需要设置我们的应用权限。
注意:您必须非常仔细地关注此部分,否则您的应用配置将无法正常工作。此外,您将需要付费的开发者帐户。
App ID
首先,请转到 developer.apple.com 登录您的帐户,一旦您进入 account 面板,请转到 Certificates , Identifiers & Profiles 标签页。在Identifiers下,单击App IDs。然后点击 (+)注册一个新的App ID。App ID说明应简单(例如NFC)。
填入 Explicit App ID 和 Bundle ID 。 必须与您在 Xcode 项目中使用的Bundle ID 完全一致,就是com.YOURDOMAIN.Message-in-a-Bottle。一旦你把你的Bundle ID放入,向下滚动并检测服务列表。点击下一步,确保您的确认页面与我的相似:

Provisioning Profiles
完成设置后,我们需要为此应用程序创建一个新的配置文件。转到 Provisioning Profiles 选项卡,然后单击 all。然后,单击(+)创建一个新的配置文件。选择iOS Development,继续选择 App ID的名称(我的是NFC),继续选择您使用的证书,添加想要测试此应用程序的任何手机。命名新建的配置文件,我们就生成了一个新的有效的配置文件。

此处解释一下什么是
配置文件?配置文件要验证在所选设备上运行的特定的应用。这样,您可以确认在设备上运行的应用程序可追溯出处并确保安全。
所以我们也需要为我们的App选择特定的配置文件。为此,请返回Xcode>build setting> 禁用Automatically manage signing。对于Debug和Release,选择下拉菜单并选择Download profile。找到对应的相关配置文件,前期准备工作就完成了!
App Entitlements
然而,Xcode 团队尚未启用 CoreNFC 的自动授权。现在,下载此预构建的授权文件,并将文件位置放在 Project> build setting > Code Signing Entitlement 的文本框中。
我们预计苹果将在不久的将来更新此功能,但现在这个步骤不可避免。所以如果发布了一个新的测试版本,可以回到这个教程重新测试。
App Privacy
打开 Info.plist 并右键单击以添加一行。在 Key 列中,打开下拉菜单并选择 Privacy - NFC Scan Usage Description。在 value 中设置自定义的提示信息。我们对 plist 文件的更新允许我们的 App 获取访问 NFC 的必要权限。

实现CoreNFC
接下来让我们来看看有趣的部分!我们将继续向 ViewController.swift 添加几行代码。但在我们写代码之前,需要提一下一个让我调试了几个小时的问题。
目前 CoreNFC 框架尚未编译进 iOS 模拟器。这意味着如果你尝试import CoreNFC 你会得到一个错误,说没有 CoreNFC 模块。简单的修复方法就是主动选择您的 iPhone 或 通用设备。
1 |
|
我们只需要再添加两行代码就可以启动 NFC reader 。更新我们之前创建的 scanPressed 方法来调用NFCNDEFReaderSession初始化器。
1 | func scanPressed(_ sender: Any) { |

如果您的程序在运行时出现 Session is invalidated unexpectedly 错误,请返回并再次检查 设置权限和隐私 部分。
解析消息记录
首先,我们来看看 func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage])
我们可以通过打印messages 的第一个元素来认识它。
1 | ( |
`messages` 是一个 存储`NFCNDEFMessages` 数据格式数组,在 `NFC` 会话无效之前,我们执行的每次扫描都有一个数组,而在我们扫描后,会话会自动失效。我们只需要关注数组中的一个对象。
messages[0] 是一个 NFCNDEFMessage,它包含一个 NFCNDEFPayload。messages[0].records 是一个 NFCNDEFPayload 数组,因为 NDEF卡 可以包含多个 payLoad。
单一 NFCNDEFPayload 包含4项信息:
- identifier
- type
- typeNameFormat
- payload是一个
Data类型的对象
1 | func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { |
此处有几个问题。为什么要前进3?DispatchQueue的内容是什么?
为什么 NFC 标签总是以 enHello 或 enMessage 开头。在对 NDEF 规范和法规进行了一些研究后发现:
所有语言代码必须根据
RFC 3066完成。语言代码不能省略。语言代码长度被编码在状态字节的六个最低有效位中。因此,通过使用值0x3F屏蔽状态字节很容易找到。
第3行将 payload 从 data 类型转换为可读的 string 字符串。”
关于这个问题 DispatchQueue,在readerSession 中 messageLabel 是不可访问的。所以我们要返回主线程,给 messageLabel 赋值,这也是线程间通信的一个最简单的方法。
这是最终的样式:
