iOS11 Core NFCを使ってみた

iOS11になって、Core NFCというフレームワークが追加されました。
これはNFC(近距離無線通信)を利用したタグとの通信が出来るフレームワークです。

現状では読み取り専用で、しかも専用のアプリを起動しなければいけないそうです。
Androidアプリでは「NFCタグを端末に近づけるとアプリを起動する」といったことができますが、iPhoneではまだそのようなバックグラウンドからNFCの検知イベントでアプリを立ち上げるなどはできません。

ですが、長年さまざまな人が待望した機能ではあります。
実験する価値はあると思っています。

今回はCore NFCを使ったサンプルのアプリの紹介です。
コード量はすくないですが、ハマリポイントもあったので皆さんのお役に立てればと思います。

動作環境

  • Xcode9.2
  • iPhoneX iOS 11.1.2

NFCタグをゲットする

Core NFCを利用したいなら兎にも角にも最初はNFCタグをどこからか入手しなければ行けません。
幸いAmazonで10枚入りのモノが売っていたのでそちらを購入します。

サンワサプライ NFCタグ(10枚入り) 白 MM-NFCT

2017/12/17現在、870円ととても安くなっています。

AndroidでNFCタグにデータを書き込む

残念なことに、現在Core NFCはNFCタグのデータを読み込むことはできても書き込むことはできません。
「サンワサプライ NFCタグ」はデータがない状態で販売されているので何かしらの方法でデータを書き込むことが必要です。

一番簡単なのがAndroidのアプリを使うことです。
私はNFC Toolsというアプリを使って書き込みをしてみました。

Writeタブの「Add a record」から書き込むデータを指定して「Write / 30 Bytes」セルをタップ、書き込みたいNFCタグを近づけるとデータを書き込めます。

iOS側の実装

NFCタグを使うには次の段階を踏む必要があります。

  • Info.plistにNFCReaderUsageDescriptionキーを追加
  • ケイパビリティをONにする
  • NFC読み取りの実装をする

Info.plistにNFCReaderUsageDescriptionキーを追加

NFCの利用は位置情報やカメラの利用と同じようにユーザーに許可を求める必要があります。
Info.plistに次のKeyと説明文言を追加します。

<key>NFCReaderUsageDescription</key>
<string>[ユーザーへアプリがNFCを利用する説明を記述]</string>

Xcodeのプロパティリスト表示ではPrivacy - NFC Scan Usage Descriptionというキーを追加すればOKです。

ケイパビリティをONにする

続いてケイパビリティNear Field Communication Tag ReadingをONにします。

エンタイトルメントファイルが追加されます。

これで認証系の事前準備は終了です。
次からコードを書いていきます。

NFC読み取りの実装をする

いよいよ実装していきます。
ViewControllerに実装していきたいと思います。

CoreNFCフレームワークをインポートして、NFCNDEFReaderSessionDelegateプロトコルを適応させます。

import UIKit
import CoreNFC

class ViewController: UIViewController, NFCNDEFReaderSessionDelegate {
    var session: NFCNDEFReaderSession?

読み取り開始

    //読み取りボタンを押した
    @IBAction func readNFC(_ sender: UIButton) {
        if NFCNDEFReaderSession.readingAvailable {
            session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false)
            session?.alertMessage = "NFCタグをiPhoneに近づけてください"
            session?.begin()
        } else {
            print("NFCが使えません")
        }
    }

NFCが使える端末かどうかはNFCNDEFReaderSession.readingAvailableで判定ができます。trueなら利用できfalseなら利用できません。
現在iPhone7/7Plus、iPhone8/8Plus、iPhoneXで利用ができます。

NFCNDEFReaderSessionのイニシャライズでNFC読み取りのセッションを作成します。
第三引数のinvalidateAfterFirstReadは連続でNFCタグを読み取るかどうかのフラグです。trueなら最初に読み取った時点でセッションを終了します。falseならタイムアウトするまで連続で読み取ります。

session?.alertMessageでシステムが表示した読み取りUIの説明文言を指定できます。

session?.begin()で読み取り開始です。

システムが用意する読み取りUIが表示されます。

赤く丸をつけたところがsession?.alertMessageで指定した文字列です。

デリゲートを受け取る

NFCNDEFReaderSessionDelegateは2つのメソッドを実装しなければいけません

readerSession(_:didInvalidateWithError:)readerSession(_:didDetectNDEFs:)です。

readerSession(_:didInvalidateWithError:)はエラーが発生した場合に呼ばれます。
ユーザーがシステムの読み取りUIの「キャンセル」を押すか読み取りがタイムアウト(現状60秒)しても呼ばれます。

    /// 読み取りエラーが起こった時呼ばれる。ユーザーがキャンセルボタンを押すか、タイムアウトしたときに呼ばれる。
    func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
        print("error:\(error.localizedDescription)")
    }

NFCが無事に読み取れるとreaderSession(_:didDetectNDEFs:)が呼ばれます。

/// 読み取りに成功したら呼ばれる。
func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {

    for message in messages {
        for record in message.records {
            print(String(data: record.payload, encoding: .utf8)!)
        }
    }
}

NFCの情報はmessage引数からNFCNDEFMessageの配列として受け取れます。通常は1つのタグにメッセージは1つだそうです。

NFCNDEFMessageインスタンスはvar records:[NFCNDEFPayload]を持っています。
NFCタグには1つまたは複数のレコードを含みます。

このrecodepayloadプロパティ値を読み取ればOKです。

実際にやってみた。

Androidアプリ「NFC Tools」から自分のブログのURLであるblog.personal-factory.comのデータを書き込みます。

iOSでアプリをビルドしてタグを近づけるとUIがチェックマークに変わり、タグのデータが出力されました

出力文字列

blog.personal-factory.com

成功ですね。

ハマったこと

物品管理として使おうかと思ったので、社内のテスト端末であるiPhone5cにNFCタグを貼り付けたのです。
紹介したNFCタグはシールとなっていて、どこでも貼り付けられるようになっています。
ところが、一行に認識せず、タイムアウトエラーが出てしまっていました。

1時間悩んで、他のタグでやると今度は認識しました。
どうやら金属に貼り付けると認識できないことがあるようです。
試しにどこにも貼り付けないで近づけると認識しました。

NFCタグと金属は相性が悪いそうで、実際物品管理などに導入するさいは考慮する必要がありそうです。

参考&宣伝

この記事は「iOS 11 Programming」を参考にしました。
Core NFC以外にもiOS 11の機能を網羅的にまとめられていてすごく参考になります。
ぜひチェックしてみてください。

iOS 11 Programming

  • 著者:堤 修一,吉田 悠一,池田 翔,坂田 晃一,加藤 尋樹,川邉 雄介,岸川 克己,所 友太,永野 哲久,加藤 寛人,
  • 製本版,電子版
  • PEAKSで購入する