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つまたは複数のレコードを含みます。
このrecode
のpayload
プロパティ値を読み取ればOKです。
#実際にやってみた。
Androidアプリ「NFC Tools」から自分のブログのURLであるblog.personal-factory.comのデータを書き込みます。
iOSでアプリをビルドしてタグを近づけるとUIがチェックマークに変わり、タグのデータが出力されました
出力文字列
blog.personal-factory.com
成功ですね。
ハマったこと
物品管理として使おうかと思ったので、社内のテスト端末であるiPhone5cにNFCタグを貼り付けたのです。
紹介したNFCタグはシールとなっていて、どこでも貼り付けられるようになっています。
ところが、一行に認識せず、タイムアウトエラーが出てしまっていました。
1時間悩んで、他のタグでやると今度は認識しました。
どうやら金属に貼り付けると認識できないことがあるようです。
試しにどこにも貼り付けないで近づけると認識しました。
このNFCタグの特徴なのか、iPhoneXの精度の問題なのかはまだ確認していないです。
ビジネスとして物品管理などを行う場合は、他のメーカーのNFCタグも試して、精度を確認した方がいいかと思いました。