iPhone で運転免許証を読み取ってみよう！【SwiftUI で簡単に】

こんにちは、[aBiteエンジニアのけわし](https://www.abite.tech/home)です！
SwiftUIとOSSライブラリを使って、簡単に運転免許証を読み取ってみましょう。

# Xcode プロジェクト作成
新規プロジェクトを作成し、
<img width="480" alt="Screenshot 2019-12-09 at 19.37.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275966/bb6ff142-d351-cd59-5b43-8579bbaeec73.png">
Single View App を選びます。
<img width="480" alt="Screenshot 2019-12-09 at 19.40.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275966/abdf197c-99d1-bb0b-701b-69064afdc31e.png">

SwiftUI となっていることを確認します。
<img width="480" alt="Screenshot 2019-12-09 at 19.42.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275966/d2729169-66da-193b-f360-8ad954c49f20.png">

# 設定
[ライブラリの導入](https://qiita.com/treastrain/items/9025000acec37f77134a#ライブラリの導入), [Capability と Entitlements の設定](https://qiita.com/treastrain/items/9025000acec37f77134a#capability-と-entitlements-の設定), [Info.plist-の設定](https://qiita.com/treastrain/items/9025000acec37f77134a#infoplist-の設定) の三つを行ってください。

# SwiftUI
コードのプログラミングは、2ステップです。
- UserData.swift: NFCリーダの起動と、読み取り後の変数への代入を行います
- ContentView.swift: 見た目を書きます

## UserData
```swift:UserData.swift
import Foundation
import TRETJapanNFCReader


final class UserData: NSObject, ObservableObject, DriversLicenseReaderSessionDelegate {
    var reader: DriversLicenseReader?
    @Published var registeredDomicileString: String? = nil
    
    func driversLicenseReaderSession(didRead driversLicenseCard: DriversLicenseCard) {
        // スキャン完了時の処理
        self.publishCardInfo(driversLicenseCard)
    }
    
    func publishCardInfo(_ driversLicneceCard: DriversLicenseCard) {
        // DispatchQueue.main.async を使う理由は、UserData と ContentView が別スレッドで走っているため。代入処理をこれで囲む
        DispatchQueue.main.async {
            self.registeredDomicileString = driversLicneceCard.registeredDomicile?.registeredDomicile
            }
        }
        print("data has been published")
    }
    
    func japanNFCReaderSession(didInvalidateWithError error: Error) {
        print("finished")
    }
    
    func startScan(items: [DriversLicenseCardItem], pin1: String = "", pin2: String = "") {
        self.reader?.get(items: items,
                         pin1: pin1, pin2: pin2)
        print("UserData startScan")
    }
    
    override init() {
        super.init()
        self.reader = DriversLicenseReader(delegate: self)
    }
}
```

## ContentView
```swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    @EnvironmentObject var userData: UserData
    @State var pin1: String = ""
    @State var pin2: String = ""
    var body: some View {
        NavigationView {
            List {
                if self.userData.registeredDomicileString != nil {
                    RecordView(key: "本籍", value: self.userData.registeredDomicileString)
                }
                SecureField("暗証番号1", text:$pin1).keyboardType(.numbersAndPunctuation)
                SecureField("暗証番号2", text:$pin2).keyboardType(.numbersAndPunctuation)
                Button(action: {
                    self.userData.startScan(items: [.registeredDomicile], pin1: self.pin1, pin2: self.pin2)
                }) {
                    Text("スキャン").foregroundColor(.blue)
                }.disabled(self.pin1.count != 4)
                    .disabled(self.pin2.count != 4)
            }.navigationBarTitle("記載事項（本籍）")
        }
    }
}

struct RecordView: View {
    var key: String
    var value: String?
    var body: some View {
        HStack {
            Text(key)
            Spacer()
            if (value != nil) {Text(value!).bold()}
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environmentObject(UserData())
    }
}

struct RecordView_Previews: PreviewProvider {
    static var previews: some View {
        RecordView(key: "本籍", value: "東京都千代田区〇〇")
            .previewLayout(.fixed(width: 300, height: 40))
    }
}
```

Swift の良いところは、
- 見た目を表現するコードが見やすい
- **プレビューを見ながら、レイアウトを整えられる**
- **プレビューをクリックして触ると、コードに反映される**
ことですね。

<img width="1392" alt="Screenshot 2019-12-09 at 20.15.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275966/fc9103a9-10ab-e534-720e-7ed461cc3854.png">

## SceneDelegate を修正
23行目くらいの次のコードを

```swift:SceneDelegate.swift
let contentView = ContentView()
```
次のように変更します。

```swift:SceneDelegate.swift
let contentView = ContentView().environmentObject(UserData())
```

#コード例、アプリ
この記事のコードは https://github.com/treastrain/TRETJapanNFCReader/tree/master/Examples/SwiftUIDriversLicenseReader に公開しております（ContentView.swiftはRegisteredDomicile.swiftに対応します）。

また、アプリも便利にお使い頂ければと、無料で公開しております。
https://apps.apple.com/jp/app/id1487791296?ign-mpt=uo%3D4

#参考記事

SwiftUI のチュートリアル：https://developer.apple.com/tutorials/swiftui
免許証読み取りの SwiftUI ではないバージョンは、こちらの記事です。環境設定などは共通しています。
https://qiita.com/treastrain/items/9025000acec37f77134a