Search code examples
iosswiftnfccore-nfc

CoreNFC - NFCNDEFReaderSession session couldn't start after invalidation on iPhone 8


The issue is reproduced only on old NFC devices like iPhone 8 which don't have a background NFC reading, but everything good on iPhone 12, 11, X. After clicking cancel (invalidate session) - it is impossible to start the NFC session again. Only after force close app it can be started again. Here is the code of openning session (button scan)

session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true)
session?.alertMessage = "Hold your iPhone near the item to scan tag."
session?.begin()

Code of delegate methods NFCNDEFReaderSessionDelegate

func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
      guard let ndefMessage = messages.first,
            let record = ndefMessage.records.first,
            record.typeNameFormat == .absoluteURI || record.typeNameFormat == .nfcWellKnown,
            let payloadText = String(data: record.payload, encoding: .utf8) else {
                return
        }
        print("scanned NFC info: \(payloadText)")
        self.session = nil
    }
    
    
    func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
        if let readerError = error as? NFCReaderError {
            if (readerError.code != .readerSessionInvalidationErrorFirstNDEFTagRead)
                && (readerError.code != .readerSessionInvalidationErrorUserCanceled) {
                let alertController = UIAlertController(
                    title: "Session is expired.",
                    message: "Please, try again.",//error.localizedDescription,
                    preferredStyle: .alert
                )
                alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                DispatchQueue.main.async {
                    self.present(alertController, animated: true, completion: nil)
                }
            }
        }
        self.session = nil
    }

Solution

  • You will have to re-start the session again.

     @IBAction func beingScanning(){
             guard !session?.isReady else {
               return
             }
    // invalidateAfterFirstRead = false
             session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false)
             session?.alertMessage = "Hold your iPhone near the item to scan tag."
             session?.begin()
        }
    

    Also use invalidateAfterFirstRead false instead of true. Once you are done with successful reading, you can invalidate it.