iOS 11 ——遲來的 NFC

前言

NFC 這個詞已經並不陌生了,前一段時間北京地鐵支持 NFC 支付一時成爲霸佔頭條的熱點。其實在 90 年代末到 2000 年初,二維碼和 NFC 就已經相繼誕生,因爲二維碼成本低廉,技術門檻相對較低,所以,二維碼迅速搶佔了移動支付的市場,但 NFC 的發展並未所以中止。在 Android 端的 NFC 發展已經很是迅猛了,惋惜 Apple 遲遲未開放接口,在今年的 WWDC 上,蘋果宣佈開放其 NFC 接口 CoreNFC, 這爲之後 NFC 的應用提供了更多的可能。json

正文

若是你對 NFC 這項技術還比較陌生,那麼這裏科普一下,NFC(Near Field Communication)近場通訊,當兩個設備相互靠近時能進行信息交流。許多企業講 NFC 芯片放到卡片裏,用帶有 NFC 芯片的卡片來授予權限將容許誰有權限,好比說進出入公司。Apple CoreNFC 目前支持的格式有限,NFC 數據交換格式或 NDEF(一般用於當今市場上的大多數平板電腦和手機),好比 Apple Pay 。swift

CoreNFC Demo

這裏咱們經過一個簡單的實例程序來演示怎麼使用 CoreNFC,這個程序能夠用來讀取存儲在卡片上 NDEF 格式的信息。數組

working-scanner.png

爲此,我使用 Arduino Uno 與 Adafruit PN532 Shield 配對,將其發送到樣品 NDEF 格式的卡上。 若是你不具有這些東西,或者根本不想在這樣的硬件上投入時間和金錢,請嘗試找一張帶有信息的預格式化卡。 本文中,我不會演示 NFC 格式化以及如何把數據存儲到 NDEF 卡 中。bash

Getting Started

打開 Xcode 9 建立一個簡單的 Swift 工程。使用 Storyboard 建立簡單的頁面:session

ViewController 以下:app

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 點擊下一步,確保你的確認頁面以下圖:async

而後再建立 provisioning profile :ide

這一步完成了,在咱們剛建立的項目中導入 證書和描述文件,完成以後呢,咱們還需進行 Info.plist 配置 Privacy:函數

至此,咱們的開始工做就完成了。👇咱們進入 coding 階段。ui

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

相關文章
相關標籤/搜索