こんにちは。開発部第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関連の機能、意外と悩むところが多かったので、もし同じように悩んでいる方がいたらご参考になれば幸いです!
私ももっと使いこなせるように勉強します!