ちょっと話題の記事

[iOS 11] 新フレームワークCore NFCを使ってNFCタグのデータを読み取ってみた #WWDC17

2017.06.08

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは。モバイルアプリサービス部の平屋です。

iOS 11で追加されたフレームワークCore NFCを使って、NFCタグのデータを読み取る実装を試してみましたので紹介します。

本記事は Apple からベータ版として公開されているドキュメントを情報源としています。 そのため、正式版と異なる情報になる可能性があります。ご留意の上、お読みください。

検証環境

  • Mac
    • macOS Sierra 10.12.5
    • Xcode Version 9.0 beta (9M136h)
  • iPhone 7
    • iOS 11.0 (15A5278f)

Core NFC

NFCタグを検出し、NDEF(NFC Data Exchange Format)データを含むメッセージを読み取るためのフレームワークです。

NFCタグとCore NFCを組み合わせて使うと、以下のような機能を実現できます。

  • 店舗内の製品に関する情報をユーザーに提供する
  • 博物館の展示物に関する情報をユーザーに提供する

NFCタグ

検証用に、愛三電機でシールタイプのNFCタグを購入しました。サイズは100円玉ぐらいで、型番は「SC3002991」です。

裏はこんな感じになってます。

NDEFデータをNFCタグに書き込む

Core NFCのリファレンスによると、Core NFCはNDEF(NFC Data Exchange Format)というフォーマットのデータを扱うことができます。

今回は、Android端末(Nexus 5)とNFC NDEF Writerを使用して、文字列「https://dev.classmethod.jp」をNFCタグに書き込みました。

実装

NFC Tag Reading を有効にする

以下の操作を行い、アプリで使用するApp IDのNFC Tag Readingを有効にします。

  1. developer.apple.com > Account > Certificates, Identifiers & Profiles > App IDsを開く
  2. アプリで使用するApp IDを選択する
  3. App Services > NFC Tag Reading を有効にする

entitlementsファイルに値を追加する

<ProjectName>.entitlementsファイルにcom.apple.developer.nfc.readersession.formatsキーと値を追加します。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.nfc.readersession.formats</key>
    <array>
        <string>NDEF</string>
    </array>
</dict>
</plist>

プロジェクトにentitlementsファイルがなくて、新規でentitlementsファイルを追加しなければならない場合は、何か適当なCapabilitiesを追加してentitlementsファイルをXcodeに追加させるのが楽もしれません。

Info.plistファイルに値を追加する

Info.plistファイルにNFCReaderUsageDescriptionキーと値(NFCReaderの使用目的)を追加します。

...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

    ...

    <key>NFCReaderUsageDescription</key>
    <string>We are going to use you NFC!</string>
</dict>
</plist>

NFCNDEFReaderSessionを使用した実装を追加する

NFCNDEFReaderSessionを作成してbegin()を呼ぶと、読み取りのセッションが開始します。

import UIKit
import CoreNFC

class ViewController: UIViewController {
    var session: NFCNDEFReaderSession!

    override func viewDidLoad() {
        super.viewDidLoad()

        session = NFCNDEFReaderSession(delegate: self,
                                       queue: nil,
                                       invalidateAfterFirstRead: true)
        session.begin()
    }
}

読み取りが完了すると、NFCNDEFReaderSessionDelegatereaderSession(_:didDetectNDEFs:)メソッドが呼ばます。

タグに書き込まれたデータはmessages引数から取得できます。AndroidアプリNFC NDEF Writeで書き込んだデータは、NFCNDEFPayloadpayloadプロパティに入っていました。

extension ViewController: NFCNDEFReaderSessionDelegate {
    func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
        for message in messages {
            for record in message.records {
                if let type = String.init(data: record.type, encoding: .utf8) {
                    print("type: \(type)")
                }
                if let identifier = String.init(data: record.identifier, encoding: .utf8) {
                    print("identifier: \(identifier)")
                }
                if let payload = String.init(data: record.payload, encoding: .utf8) {
                    print("payload: \(payload)")
                }
            }
        }
    }

    public func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
        print(#function, error)
    }
}

さいごに

本記事では、Core NFCを使って、NFCタグのデータを読み取る実装を紹介しました。

設定や実装はそんなに時間がかかりませんでしたが、読み取りの動作確認に時間がかかってしまいました。(読み取りが上手くいかず、タイムアウトになる)

最終的に、iPhoneの上端をNFCタグに近づけると、読み取りが上手くいきました。

参考資料