アイリッジ開発者ブログ

アイリッジに所属するエンジニアが技術情報を発信していきます。

iOSのNFCタグ読み取りについて

こんにちは。開発部第1グループの高橋と申します。

今回はiOSのNFCタグ読み取りについて調べたのでまとめを作成しました。

概要

iOSアプリでCore NFCフレームワークを使ってNFCタグの検出、読み取りを行う方法について調べました。

※Core NFCではNFCタグへの書き込みも可能ですが、今回は対象外です🙇

NFCタグの読み取りには、以下2つのクラスを利用できます。

実現したい機能によって使い分けが必要だったので、以下で2つのパターンをご紹介いたします。

パターン1.NFCタグに書き込まれたデータを読み取る

NFCタグに書き込まれたデータを読み取る場合は、NFCNDEFReaderSession を使用します。

ただし、データはNDEF(NFC Data Exchange Format)と呼ばれる形式に準拠している必要があります。

※NDEFについて

NFC Forumが策定したデータ形式で、 詳しいことはHPに載っています。

https://nfc-forum.org/build/specifications

※2024/03/29現在、上記HPでは詳細な仕様書が有料になってしまったようなので、お金をかけずNDEFの構造などを確認したい時は(非公式ではありますが)以下のページが参考になるかと思います。

実装例

1. NFCリーダーを開始する

// NFCリーダーセッションの初期化
let session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false)
// メッセージの設定
session?.alertMessage = "NFCタグをiPhoneに近づけてください。"
// NFCリーダーセッション開始
session?.begin()

上記のようにNFCリーダーセッションを開始するとiPhone端末がNFCタグを検出できる状態になり、スキャン画面が表示されます。

2. NFCタグから読み取ったデータを処理する

NFCNDEFReaderSessionDelegate を実装することにより読み取ったデータの内容を取得することができます。

func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
    // 検出したデータの1つ目を取得
    let records = messages[0].records
    for record in records {
        if let type = String(data: record.type, encoding: .utf8) {
            // データ形式を判定したり、データの内容を使って何かしたり・・・
        }
    }
}

また、その他に NFCNDEFReaderSessionDelegate では以下の処理が可能です。

  • readerSessionDidBecomeActive(_:) ※ iOS13〜
    • NFCリーダーセッション開始時の処理
  • readerSession(_:didDetectNDEFs:)
    • 前述のデータが書き込まれたNFCタグを検出した時の処理
  • readerSession(_:didDetect:) ※ iOS13〜
    • データが書き込まれたNFCタグを検出した時の処理
    • NFCリーダーセッションの読み書き機能を使うことが可能
  • readerSession(_:didInvalidateWithError:)
    • NFCリーダーセッションが無効になった時の処理

NFCタグにデータが書き込まれた状態で読み取りを行う場合、大体はこちらのパターンで実現できるかと思います。

Appleのドキュメントにも詳しい説明とサンプルコードが載っていますので、ご興味があれば是非見てみてください。

Building an NFC Tag-Reader App

パターン2.NFCタグ自体の情報を取得する

こちらは、データが含まれていない空のNFCタグからシリアルナンバーを取得する時に使った方法です。

NFCタグに何も書き込みがされていない場合、パターン1で使った NFCNDEFReaderSession ではタグを検出できません。

そこで NFCTagReaderSession (iOS13〜)を使います。

NFCTagReaderSessionでは、データの有無に関わらず指定した規格のNFCタグを検出し、タグの情報を読み取ることができます。

実装例

1. NFCリーダーを開始する

// pollingOptionを使用するNFCタグの規格に合わせて設定する(複数選択可)
let session = NFCTagReaderSession(pollingOption: [.iso14443, iso15693, .iso18092], delegate: self)
session.alertMessage = "NFCタグをiPhoneに近づけてください。"
session.begin()

NFCTagReaderSessionを初期化する際、使用するNFCタグの種類に合わせて pollingOption を指定します。

指定できる値は以下3つです。 (参考:NFCTagReaderSession.PollingOption

  • iso14443: ISO7816-compatible と MIFARE
  • iso15693: ISO15693
  • iso18092: FeliCa

2. 検出したタグの情報を取得する

パターン1と同様に、NFCTagReaderSessionDelegateを実装することにより読み取ったデータの内容を取得することができます。

func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
    // タグが2つ以上検出された場合は再実行する
    if tags.count > 1 {
        let retryInterval = DispatchTimeInterval.milliseconds(500)
        session.alertMessage = "タグが2つ以上検出されました。もう一度お試しください。"
        DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: {
            session.restartPolling()
        })
        return
    }
    guard let tag = tags.first else {
        return
    }
    switch tag {
    case let .miFare(miFareTag):
        // MIFAREを検出時の処理
    case let .iso7816(iso7816Tag):
        // ISO7816を検出時の処理
    case let .iso15693(iso15693Tag):
        // ISO15693を検出時の処理
    case let .feliCa(feliCaTag):
        //FeliCaを検出時の処理
    }
}

※その他のNFCTagReaderSessionDelegateのメソッド(セッション開始時/終了時の処理)はパターン1とほぼ同じのため割愛します。

まとめ

iOSのNFC関連の機能、意外と悩むところが多かったので、もし同じように悩んでいる方がいたらご参考になれば幸いです!

私ももっと使いこなせるように勉強します!