【SwiftUI】交通系ICカードの残高を読み取ってみた

ライブラリTRET JapanNFCReaderを使って交通系ICカードの残高を読み取ってみました。

https://github.com/treastrain/TRETJapanNFCReader

iOS16,Xode14です。

XcodeのFile、Add Packagesでパッケージを追加します。

右上の検索ボックスに上記のGithubのURLを入れると検索できます。

ダウンロードできるパッケージは選択できますが、大事なものが欠けているとエラーが出ますので、必要そうなものは多めに選択してダウンロードしておきます。

type-BのMIFARE以下のパッケージは、運転免許証やマイナンバー用のようです。

次にCapabilitiesでNFCを有効にします。

Signing & Capabilities

次にinfo.plistを以下のようにします。

item0の「0003」はFelicaを読み取る際のパラメータです。

以上で準備ができました。

コードを書いていきます。

import Foundation
import TRETJapanNFCReader
import TRETJapanNFCReader_FeliCa
import TRETJapanNFCReader_FeliCa_TransitIC

final class ViewModel: NSObject, ObservableObject, FeliCaReaderSessionDelegate {
    
    @Published var balance: Int? = nil
    @Published var transactions:[Data]? = nil
    var reader: TransitICReader!
        
    //読み取りを開始する
    func readingStart(){
        self.reader = TransitICReader(delegate: self)
        self.reader.get(itemTypes: [.balance])
    }
    
    func japanNFCReaderSession(didInvalidateWithError error: Error) {
        print(error)
    }
    
    //Felicaの読み取りが終わった後に、残高を格納する
    func feliCaReaderSession(didRead feliCaCardData: TRETJapanNFCReader_FeliCa.FeliCaCardData, pollingErrors: [TRETJapanNFCReader_FeliCa.FeliCaSystemCode : Error?]?, readErrors: [TRETJapanNFCReader_FeliCa.FeliCaSystemCode : [TRETJapanNFCReader_FeliCa.FeliCaServiceCode : Error]]?) {
        
        let transitICCardData = feliCaCardData as! TransitICCardData
        DispatchQueue.main.async {
            self.balance = transitICCardData.balance
        }
    }
    
    func feliCaReaderSession(didInvalidateWithError pollingErrors: [TRETJapanNFCReader_FeliCa.FeliCaSystemCode : Error?]?, readErrors: [TRETJapanNFCReader_FeliCa.FeliCaSystemCode : [TRETJapanNFCReader_FeliCa.FeliCaServiceCode : Error]]?) {
    }
}

Felicaの読み取りが完了するとdidReadが呼ばれるので、カードデータから残高を代入しています。

UIは以下の通り。

struct ContentView: View {
    
    @ObservedObject var vm: ViewModel
    
    var body: some View {
        
        VStack {
            Text("交通系ICカードの残高")
                .font(.title)
            if (self.vm.balance != nil) {
                Text("¥\(String(self.vm.balance!))")
                    .font(.largeTitle)
                    .fontWeight(.bold)
            }
            Button {
                vm.readingStart()
            } label: {
                Text("ICカードの読み取りを開始する")
                    .font(.title)
            }

        }
        
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let vm = ViewModel()
        vm.balance = 2000
        return ContentView(vm: vm)
    }
}

テキストとボタンのみのUIです。

アップルウォッチのモバイルSuicaに対して読み取りができました。

残高の他に入退出履歴も表示させる場合には、Data型をゴリゴリ解析する必要がありそうです。

ABOUTこの記事をかいた人

個人アプリ開発者。Python、Swift、Unityのことを発信します。月間2.5万PVブログ運営。 Twitter:@yamagablog