2019年12月5日 追記
Core NFC Advent Calendar 2019 にて、こちらの記事の内容を最新にしたものを公開しました。ぜひそちらをご覧ください!
WWDC19 にて発表された iOS 13 の Core NFC にて、これまでの NDEF タグの読み書きの他に FeliCa を含む NFC の読み書きができるようになりました。
そこで私は日本の NFC、FeliCa カードの読み取りを行うためのライブラリとして、treastrain/TRETJapanNFCReader を開発しています。
開発途中のため、まだまだできることは少ないですが、少しでも iOS 13 における NFC の利用方法について知ってもらいたいと思い、この記事では運転免許証を読み取るサンプルを紹介させていただきたいと思います。
なお、記事中で紹介するコードは treastrain/TRETJapanNFCReader 0.0.5 の Examples にある DriversLicenseReader にすべて含まれています。
TRETJapanNFCReader
treastrain/TRETJapanNFCReader: 日本の NFC、FeliCa カード向けリーダーライブラリ(iOS 13.0 以降) - GitHub
- Suica、PASMOなどの交通系ICカード、運転免許証の読み取り
- 日本語・英語に対応
iOS 13.0 以降で使える、日本のNFCカード向けリーダーライブラリを 開発途中ではありますが GitHub に上げました。https://t.co/ARV6y0aWYe
— treastrain / とれいん (@treastrain) 2019年6月28日
いまは運転免許証をスキャンするところまで公開しております。
今日中には運転免許証の公開情報の読み込みまでをアップする予定です。
様々な方から いいね、Star をいただいており、とてもうれしく思っています!
環境
- Xcode 11 beta 3
- NFC の読み取りが可能な iOS 13.0 端末(iOS 13.0 beta 3 の iPhone X で動作確認しています)
- 運転免許証(いわゆる ICカード免許証、NFC-B (Type-B))
- treastrain/TRETJapanNFCReader 0.0.5
残念ながら SwiftUI ではありません……。
GitHub からダウンロード
まずは GitHub からコード一式を持ってきてください。
Releases から Tag 0.0.5 をダウンロードすることをおすすめします。
GitHub の Examples にあるサンプルは Capabilities や Info.plist の設定が既に済んでいます。README をご確認ください。
ライブラリのインポート
以降、DriversLicenseReaderディレクトリ内を操作します。
すでにサンプルのための ViewController が作成されていますが、ここでは新しく ViewController.swift を作成するものとして記事を進めます。
まずはライブラリのインポートから。
import UIKit
import CoreNFC
import TRETJapanNFCReader
初期化とデリゲートの継承
運転免許証の読み取りを司る DriversLicenseReader を初期化します。
DriversLicenseReader は初期化の際に DriversLicenseReaderSessionDelegate か DriversLicenseReaderSessionDelegate を継承した UIViewController、DriversLicenseReaderViewController を要求します。
public typealias DriversLicenseReaderViewController = UIViewController & DriversLicenseReaderSessionDelegate
DriversLicenseReader(viewController: ) で初期化すると、エラーが発生した場合にライブラリ内で UIAlertController を作って viewController.present します。エラーのときの処理をすべて自前で行う場合は DriversLicenseReader(delegate: ) で初期化してください。
import UIKit
import CoreNFC
import TRETJapanNFCReader
class ViewController: UIViewController, DriversLicenseReaderSessionDelegate {
    
    var reader: DriversLicenseReader!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.reader = DriversLicenseReader(viewController: self)
    }
}
DriversLicenseReader.get(items: ) を呼ぶ
DriversLicenseReader の初期化が済んだら、あとは DriversLicenseReader.get(items: ) を呼ぶだけです。引数の items は [DriversLicenseCardItem] を要求します。DriversLicenseCardItem は、記事執筆時点で以下のとおりです。
/// 日本の運転免許証から読み取ることができるデータの種別
public enum DriversLicenseCardItem: CaseIterable {
    /// MF/EF01 共通データ要素
    case commonData
    /// MF/EF02 暗証番号(PIN)設定
    case pinSetting
    /// DF1/EF01 記載事項(本籍除く)
    case matters
}
ここで気をつけなければいけないのは、ICカード免許証の仕様で 共通データ要素 と 暗証番号(PIN)設定 以外のデータの読み取りには、ICカード免許証の発行時に各自で設定した暗証番号が必要となることです。
ICカード運転免許証には暗証番号1と暗証番号2の2つがあり、本籍 を含むデータを読み取る場合は暗証番号1と暗証番号2の両方、それ以外のデータの場合は暗証番号1が必要となっています。
また、この暗証番号は3回間違えるとロックされ、以降は警察署などでロックを解除してもらわなければ、読み取りの際に暗証番号が必要なデータを読み取ることができなくなってしまいます。
よって、items で commonData と pinSetting を指定した場合は問題ありませんが、matters が含まれている場合(DriversLicenseCardItem.allCasesとした場合なども同様)は暗証番号1も渡す必要があります。
self.reader.get(items: [.commonData, .pinSetting])
self.reader.get(items: [.matters], pin1: "暗証番号1")
一度 self.reader.get(items: [.pinSetting]) で ICカード免許証を読み取り、暗証番号が設定されているかどうかを確認することもできます。
読み取った結果を確認する
DriversLicenseReader.get(items: ) を呼んだ後は iOS 端末が NFC の読み取りモードに入ります。iPhone の上部(受話部)を ICカード免許証の下半分を隠すように置いて、読み取ります。
読み取りが正しく成功すると、DriversLicenseReaderSessionDelegate により driversLicenseReaderSession(didRead driversLicenseCard: DriversLicenseCard) が呼ばれます。
    func driversLicenseReaderSession(didRead driversLicenseCard: DriversLicenseCard) {
        // driversLicenseCard に読み取った運転免許証の情報が格納されている
    }
}
driversLicenseCard に読み取った情報が入っているので、確認してみましょう。DriversLicenseCard は TRETJapanNFCReader/DriversLicense/DriversLicenseCard.swift で定義されています。
終わりに
以上の手順で簡単に運転免許証のデータを読み取ることができたかと思います。
例えば、いわゆる IDセルフィー と運転免許証の NFC 読み取りを組み合わせれば本人確認の手段として有効に活用できるのではないかなと思います。
もしよろしければ GitHub のほうに Star していただけるとありがたいです!また、指摘や意見等もお待ちしています。
