【iOS】NFCタグで始業時間を打刻しFirebaseに送る

今回は、NFCタグを近づけて出勤時刻のデータをFirebaseに送信するコードを紹介します。

以下のコードは「出勤」ボタンを押してからNFCを近づけると、出勤時刻がFirebaseに送られるという仕組みのコードです。

全体コード

import SwiftUI
import CoreNFC
import Firebase
import FirebaseFirestore

//UIKitのUIButtonを利用するためのUIViewRepresentable
struct StartTimeButton: UIViewRepresentable { 
    
    @Binding var userName: String // NFCから読み取った名前
    @Binding var uid: String // その人のID
    @Binding var startTime: Date // 打刻した出勤時刻
    
    func makeUIView(context: Context) -> UIButton {
        let button = UIButton() // UIButtonを利用するためのインスタンスを作成
        button.setTitle("出勤", for: .normal) // ボタンのタイトルを設定
        button.backgroundColor = UIColor.blue // // ボタンの背景色を設定
        // ボタンのタッチしたタイミングでbeginScanメソッド起動させる
        button.addTarget(context.coordinator, action: #selector(context.coordinator.beginScan(_:)), for: .touchUpInside)
        return button
    }
    
    // この関数はUIViewが更新されるときに呼ばれるメソッド。今回は特に何もしない
    func updateUIView(_ uiView: UIButton, context: Context) {
    }
    
    // Coordinatorクラスのインスタンスを作成し返す
    func makeCoordinator() -> StartTimeButton.Coordinator {
        return Coordinator(userName: $userName, uid: $uid, startTime: $startTime)
    }
    
    // UIKitとSwiftUIの間でデータやイベントを橋渡しするクラス
    class Coordinator: NSObject, NFCNDEFReaderSessionDelegate {
        var session: NFCReaderSession?
        @Binding var userName: String
        @Binding var uid: String
        @Binding var startTime: Date
        
     //バインディングされたプロパティを初期化
        init(userName: Binding<String>, uid: Binding<String>,startTime: Binding<Date> ) {
            _userName = userName
            _uid = uid
            _startTime = startTime
        }
        
        // NFCタグをスキャンするメソッド
        @objc func beginScan(_ sender: Any) {
            // NFCリーダーが利用可能かチェック
            guard NFCNDEFReaderSession.readingAvailable else {
                print("このタグは読めません")
                return
            }
            // 新しいNFCリーダーセッションを作成
            session = NFCNDEFReaderSession(delegate: self, queue: .main, invalidateAfterFirstRead: true)
            session?.alertMessage = "スキャンします。NFCタグを近づけてください。"
            // スキャン開始
            session?.begin()
        }
        
        // NFC セッションがエラーによって無効になったときに呼び出されるデリゲートメソッド
        func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
            if let readerError = error as? NFCReaderError,
               readerError.code != .readerSessionInvalidationErrorFirstNDEFTagRead,
               readerError.code != .readerSessionInvalidationErrorUserCanceled {
                print("読み込めませんでした")
            }
            self.session = nil
        }
        
        func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
            guard
                let nfcMess = messages.first,  // メッセージの最初の要素を取得
                let record = nfcMess.records.first,  // レコードの最初の要素を取得
                let payloadString = String(data: record.payload, encoding: .utf8)?.dropFirst(2)
                    .dropLast(2) else {
                return  // 変換できなければ終了
            }
            
            // ペイロードをコンマで分割
            let components = payloadString.components(separatedBy: ",")
            if components.count >= 2 {
                userName = components[0]  // ユーザー名を取得
                uid = components[1]  // ユーザーIDを取得 
                
                // Firestoreにデータを追加
                Firestore.firestore().collection("Start").addDocument(data: [
                    "name": userName, //ユーザー名を保存
                    "userID": uid, //ユーザーIDを保存
                    "startDate": FieldValue.serverTimestamp() // サーバータイムスタンプ(時刻)を保存
                ])
                    } else {
                        print("氏名またはIDが登録されていません")
            }
        }
    }
}

フレームワーク

まずはフレームワーク

import SwiftUI
import CoreNFC // CoreNFCフレームワーク(NFCタグ読み取り用)
import Firebase // Firebaseフレームワーク(Firebase機能全般用)
import FirebaseFirestore // FirebaseFirestoreフレームワーク(Firestore用)