Introduction

I never had a chance to work with NFC (Near Field Communication), but I have always been curious to find out how it works. In this article, I will focus on scanning NFC tags using CoreNFC with NFCNDEFReaderSession.

Preparation

Before we begin, let’s add the necessary objects:

  • Near Field Communication Tag Reading capability to the project.
  • Privacy - NFC Scan Usage Description key to Info.plist.
  • Near Field Communication Tag Reader Session Formats to the entitlements file.

First Step

The first step before starting scanning is to check if the device supports NFC reading by using the NFCNDEFReaderSession.readingAvailable property.

guard NFCNDEFReaderSession.readingAvailable else {
    let alertController = UIAlertController(
        title: "Scanning Not Supported",
        message: "This device doesn't support tag scanning.",
        preferredStyle: .alert
    )
    alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
    self.present(alertController, animated: true, completion: nil)
    return
}

Second Step

The second step is to create an NFCNDEFReaderSession object by calling the init(delegate:queue:invalidateAfterFirstRead:) initializer method. Set up alertMessage to give users instructions while the phone is scanning NFC tags. Finally, call begin() to start the reader session.

session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false)
session?.alertMessage = "Hold your iPhone near the item to learn more about it."
session?.begin()

Third Step

The third step is to implement NFCNDEFReaderSessionDelegate to be able to receive notifications from the reader session when it reads an NDEF message or becomes invalid due to ending the session or encountering an error.

// MARK: - NFCNDEFReaderSessionDelegate

/// - Tag: processingTagData
func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
    DispatchQueue.main.async {
        // Process detected NFCNDEFMessage objects.
        self.detectedMessages.append(contentsOf: messages)
        self.tableView.reloadData()
    }
}

/// - Tag: endScanning
func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
    // Check the invalidation reason from the returned error.
    if let readerError = error as? NFCReaderError {
        // Show an alert when the invalidation reason is not because of a
        // successful read during a single-tag read session, or because the
        // user canceled a multiple-tag read session from the UI or
        // programmatically using the invalidate method call.
        if (readerError.code != .readerSessionInvalidationErrorFirstNDEFTagRead)
            && (readerError.code != .readerSessionInvalidationErrorUserCanceled) {
            let alertController = UIAlertController(
                title: "Session Invalidated",
                message: error.localizedDescription,
                preferredStyle: .alert
            )
            alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            DispatchQueue.main.async {
                self.present(alertController, animated: true, completion: nil)
            }
        }
    }

    // To read new tags, a new session instance is required.
    self.session = nil
}

Resources

You can find a more detailed article in the Apple Developer Documentation, where each step is explained in depth.

Download Materials

Download

Thank you for reading! 😊