Help us understand the problem. What is going on with this article?

iPhone で運転免許証を読み取ってみよう!【ライブラリを使って】

それでは Core NFC を用いた iPhone アプリ開発の例として、運転免許証の読み取りを行います。今回は OSS ライブラリを用いて、Core NFC のコーディングよりも Core NFC を使うときに必要な Xcode プロジェクトでの各設定を中心に説明していきます。


  • 開発
    • Xcode Version 11.2.1 (11B500)
    • Apple Swift version 5.1.2 (swiftlang-1100.0.278 clang-1100.0.33.9)
    • macOS Catalina 10.15.1(19B88)
  • 実機
    • iPhone 11 Pro (A2215、MWCC2J/A)
    • iOS 13.2.3 (17B111)

Xcode プロジェクトの作成

まずは Create a new Xcode project から iOS の Single View App を作成します。


今回は私が開発・公開しているライブラリ、treastrain/TRETJapanNFCReader を使用します。
このライブラリは Swift Package Manager、Carthage、CocoaPods に対応していますが、今回は Carthage を使うことにします。
※運転免許証の読み取りの場合、Swift Package Manager では文字コードの変換を行うことができずに正しく読み取ることができません。

  1. Cartfilegithub "treastrain/TRETJapanNFCReader" と記述して carthage update --platform iOS する。
  2. Project の Target の Build Phases で新しい Run Script Phase を追加し、shell に /usr/local/bin/carthage copy-frameworks を、Input Files に $(SRCROOT)/Carthage/Build/iOS/TRETJapanNFCReader.framework を記述する。スクリーンショット 2019-11-29 21.36.07.png
  3. Project の Target の General で Frameworks, Libraries, and Embbedded Content で Carthage によって追加された TRETJapanNFCReader.framework を追加する。スクリーンショット 2019-11-29 21.53.12.png

Capability と Entitlements の設定

Project の Target から Signing & Capabilities を選択し、「+ Capability」から「Near Field Communication Tag Reading」を追加します。
スクリーンショット 2019-11-29 18.50.17.png
すると、「.entitlements」というファイルが追加されているので、「Near Field Communication Tag Reader Session Formats」に「NFC Data Exchange Format」および「NFC tag-specific data protocol」があることを確認します。
スクリーンショット 2019-11-29 19.01.06.png

Info.plist の設定

Info.plist に「Privacy - NFC Scan Usage Description」と「ISO7816 application identifiers for NFC Tag Reader Session」を追加します。
「Privacy - NFC Scan Usage Description」には NFC を何のために使用するのかについての説明を、「ISO7816 application identifiers for NFC Tag Reader Session」の配下には以下の AID を記述します。

  • A0000002310100000000000000000000
  • A0000002310200000000000000000000
  • A0000002480300000000000000000000

スクリーンショット 2019-11-29 20.39.40.png


ではいよいよコーディングをしていきます。今回はすべて ViewController.swift に記述します。

import UIKit
import TRETJapanNFCReader // ①

class ViewController: UIViewController, DriversLicenseReaderSessionDelegate { // ②

    var reader: DriversLicenseReader! // ③

    override func viewDidLoad() {

        self.reader = DriversLicenseReader(viewController: self) // ④
        self.reader.get(items: DriversLicenseCardItem.allCases, pin1: "1234", pin2: "5678") // ⑤

    func driversLicenseReaderSession(didRead driversLicenseCard: DriversLicenseCard) { // ②・⑥
        let matters = driversLicenseCard.matters!
        let registeredDomicile = driversLicenseCard.registeredDomicile!
        print("呼び名(カナ)", matters.nickname)
        print("生年月日", matters.birthdate)
        print("本籍", registeredDomicile.registeredDomicile)
        print("住所", matters.address)
        print("交付年月日", matters.issuanceDate)
        print("照会番号", matters.referenceNumber)
        print("有効期間の末日", matters.expirationDate)
        print("免許の条件", matters.condition1, matters.condition2, matters.condition3, matters.condition4)
        print("公安委員会名", matters.issuingAuthority)
        print("免許証の番号", matters.number)
        print("普通免許の年月日", matters.ordinaryVehicleLicenceDate)
        print("中型免許の年月日", matters.mediumVehicleLicenceDate)

        // let image = UIImage(data:!.photoData)

    func japanNFCReaderSession(didInvalidateWithError error: Error) { // ②・⑥
  1. ライブラリ TRETJapanNFCReader をインポートします。
  2. ViewControllerDriversLicenseReaderSessionDelegate を適用させます。必要な protocol stubs を追加します。
  3. クラス内に DriversLicenseReader型の変数を用意します。
  4. 3 で用意した変数を初期化します。
  5. reader.get で運転免許証の読み取りに入ります。pin1pin2にはそれぞれ、運転免許証が交付されたときに自分が設定した暗証番号1、暗証番号2を指定します。絶対に間違えないでください(理由は後述)。
  6. 取得した運転免許証のデータを print します。

特に、5 の reader.get は以下のように定義されています。

/// 運転免許証からデータを読み取る
/// - Parameter items: 運転免許証から読み取りたいデータ
/// - Parameter pin1: 暗証番号1
/// - Parameter pin2: 暗証番号2
func get(items: [DriversLicenseCardItem], pin1: String = "", pin2: String = "")

また、ここで指定する DriversLicenseCardItem は以下のように定義されています。

/// 日本の運転免許証から読み取ることができるデータの種別
public enum DriversLicenseCardItem: CaseIterable {
    /// MF/EF01 共通データ要素
    case commonData
    /// MF/EF02 暗証番号(PIN)設定
    case pinSetting
    /// DF1/EF01 記載事項(本籍除く)
    case matters
    /// DF1/EF02 記載事項(本籍)
    case registeredDomicile
    /// DF2/EF01 写真
    case photo

上記に挙げたサンプルでは DriversLicenseCardItem.allCases としてすべて指定していましたが、運転免許証の仕様上、「記載事項(本籍除く)」の読み取りには暗証番号1が、「記載事項(本籍)」、「写真」の読み取りには暗証番号1と暗証番号2の両方が必要です。さらにその暗証番号は3回間違えると免許証がロックされ、警察署等でロック解除をしてもらわなければ運転免許証を読み取ることができなくなってしまいます。読み取る際は慎重に試しましょう……。

例: 2回誤った暗証番号を入力 → 3回目で正しい暗証番号だった → 暗証番号試行回数は残り3回にリセットされる


それではいよいよ実機の iPhone で実行してみましょう。
スクリーンショット 2019-11-29 22.17.37.png


  • Core NFC で運転免許証を読み取ることができる
  • 暗証番号は間違ってはいけない
  • 実際の利用ケースとしては IDセルフィーの置き換え・補助になるかも


スクリーンショット 2019-11-29 22.23.35.png

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away