【问题标题】:NFC alert not always dismissed after reading dataNFC 警报在读取数据后并不总是消失
【发布时间】:2022-06-21 15:26:40
【问题描述】:

上下文
我正在开发一个数字棋盘游戏(带有移动应用程序)。玩家可以通过扫描他们的徽章(包含 UUID)与应用程序交互。

我的问题
我创建了一个 NFCReader 服务来从 NFC 徽章读取数据。当我从该服务调用 scan() 方法时,NFC 弹出窗口也会显示,并且当我将 NFC bagde 放在手机上时它会按预期消失。但是,当我在触发 NFC 检测之前使用 NFC 徽章已经在我的手机上发现重复此操作时,NFC 弹出窗口会按预期显示,但 有时,读取数据后不会关闭.

预期情况

Bug 情况(在调用扫描方法之前,我的徽章已经在我的手机上被发现:

NFCReader 服务

class NFCReader: NSObject, NFCNDEFReaderSessionDelegate, ObservableObject {

    static var instance = NFCReader()
    var session: NFCNDEFReaderSession?
    
    var onRecordCallBack: ((_ badgeId: String) -> Void)?

    func scan(message: String, onRecord: @escaping (_ badgeId: String) -> Void) {
        guard NFCReaderSession.readingAvailable else {
            return
        }
        
        self.onRecordCallBack = onRecord

        self.session = NFCNDEFReaderSession(delegate: self, queue: .main, invalidateAfterFirstRead: false)
        self.session?.alertMessage = message
        self.session?.begin()
    }
    
    func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
        if let readerError = error as? NFCReaderError {
            print("Error NFC reader : \(readerError.localizedDescription)")
        }
        self.session = nil
    }

    func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
        
        guard
            let message = messages.first,
            let record = message.records.first,
            let badgeId = String(data: record.payload, encoding: .utf8) else {
            return
        }

        if let onRecordCallBack = self.onRecordCallBack {
            onRecordCallBack(badgeId)
        }
        
        self.session?.invalidate()
    }
}

ViewModel 使用 NFCReader 时

struct InGameTravelView: View {
    @StateObject var viewModel = InGameTravelViewModel()
    
    var body: some View {
        VStack {
            if viewModel.isScanning {
                Text("Scan your badge")
                    .onAppear() {
                        self.viewModel.scan()
                    }.onTapGesture {
                        self.viewModel.scan()
                    }
                ForEach(viewModel.pilots) { pilot in
                    Text("\(pilot.player.name) \(pilot.player.role.name)")
                        .onTapGesture {
                            viewModel.currentPilot = pilot
                            viewModel.isScanning = false
                        }
                }
            } else {
                switch viewModel.currentPilot.player.role.slug {
                case .GOOD :
                    GoodPilotActionView(pilot: $viewModel.currentPilot) { selectedMatePilot in
                        viewModel.onActionFinished(selectedMatePilot)
                    }
                case .BAD :
                    BadPilotActionView(pilot: $viewModel.currentPilot) {
                        //
                    }
                }
            }
        }.onAppear() {
            viewModel.fetchData()
        }
    }
}

extension InGameTravelView {
    class InGameTravelViewModel: ObservableObject {
        @Published var pilots: [Pilot] = []
        @Published var pilotsAlreadyPlayed: [Pilot] = []
        @Published var isScanning = true
        @Published var currentPilot = Pilot.fake()
        
        func fetchData() {
            /* Retrieve current round */
            let round = GameManager.instance.state.currentRound
            /* Retrieve pilots */
            self.pilots = round.pilots
            
            if let pilot = self.pilots.first {
                self.currentPilot = pilot
            }
        }
        
        func scan() {
            NFCReader.instance.scan(message: "Scan your badge") { badgeId in
                print("badgeId : \(badgeId)")
                let round = GameManager.instance.state.currentRound
                guard let pilot = round.getPilotByBadgeId(badgeId: badgeId) else {
                    return
                }
                self.currentPilot = pilot
                self.isScanning = false
            }
        }
    }

如您所见,我手动使 NFC 会话 (self.session?.invalidate()) 无效,以尽快隐藏弹出窗口(以避免玩家自己动手)。

我想强调这个错误是随机发生的。有时,即使徽章在触发扫描之前被弄脏,它也会按预期工作 (GIF 1)。

【问题讨论】:

    标签: swift swiftui nfc


    【解决方案1】:

    我认为您应该检查是否发生了一些错误响应,但它们没有被捕获。那么在终端中是否可以找到一些相关的日志。

    【讨论】:

      猜你喜欢
      • 2019-04-21
      • 1970-01-01
      • 1970-01-01
      • 2014-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多