Support for NFC was first added to iPhone 6 and iPhone 6 Plus along with the debut of Apple Pay in 2014. However, initially there was no API that would allow third-party apps to access the NFC module. Fortunately, three years later, with iOS 11 Apple introduced Core NFC, the framework used for detecting NFC tags and reading data in NFC Data Exchange Format (NDEF) from them on iPhone 7 / iPhone 7 Plus and above. In this post we’ll go through the basic steps of adding NFC reading capability to your app using Core NFC framework.
Project setup
Let’s start by setting up the project. First, you need to enable Near Field Communication Tag Reading capability for your project. To do this, select the project in project navigator, open Capabilities tab and change the switch for Near Field Communication Tag Reading to ON state. This will automatically add required entitlements to your project and, if you are using automatic signing management, will enable NFC Tag Reading service for your app ID. If you are managing app signing manually, make sure to enable NFC Tag Reading service for your app ID and regenerate provisioning profiles on Apple’s developer website.
Next, you need to add NFCReaderUsageDescription key to your project’s Info.plist file with the description of the purpose why your app requires access to NFC module. If you don’t provide this key with your usage description, the app will exit when you attempt to start an NFC tag reading session.
NDEF reader session
With these modifications in place we can jump right into coding. An instance of NFCNDEFReaderSession
is used to detect and read NDEF data from NFC tags. The following example shows how to initialize a reader session and begin scanning.
|
@IBAction func startScanning(_ sender: Any) { if NFCNDEFReaderSession.readingAvailable { readerSession = NFCNDEFReaderSession(delegate: self, queue: DispatchQueue.main, invalidateAfterFirstRead: true) readerSession?.alertMessage = "Hold your iPhone near the NFC tag" readerSession?.begin() } else { let alert = UIAlertController(title: "Ooops!", message: "Seems like your device does not support NFC tag reading.", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil)) present(alert, animated: true, completion: nil) } } |
During initialization you specify the delegate for NFCNDEFReaderSession
, which will handle any data/errors returned from the reader session and a dispatch queue to be used for calling the delegate methods. You tell the session whether it should support multiple tag detection using invalidateAfterFirstRead
parameter of the initializer.
Also, you can provide users with brief instructions by setting the session’s alertMessage
property.
Once you call begin()
method on the reader session, the device will start scanning for NFC tags and the standard scanning UI will be displayed with the message you supplied to alertMessage
property.

You can use readingAvailable
property of NFCNDEFReaderSession
class to check if NFC reading capability is available on current device.
The session’s delegate should conform to NFCNDEFReaderSessionDelegate
protocol. This protocol defines 2 required methods: readerSession(_:didDetectNDEFs:)
is called each time NDEF data is detected and readerSession(_:didInvalidateWithError:)
is called to inform the delegate when the reader session is invalidated with an error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
extension ViewController: NFCNDEFReaderSessionDelegate { func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) { messagesTextView.text = error.localizedDescription } func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { var messagesStr = "Scanned data:\n\n" for message in messages { for record in message.records { if let payloadStr = String(bytes: record.payload, encoding: .utf8) { messagesStr += "Record:\n" messagesStr += payloadStr messagesStr += "\n\n" } } } messagesTextView.text = messagesStr } } |
To stop reader session programmatically use invalidate()
method.
|
func stopScanning() { readerSession?.invalidate() } |
Keep in mind that invalidated sessions cannot be reused, so a new instance of NFCNDEFReaderSession
should be used to begin scanning again.
That’s all you need to add NFC tag reading capability to your app. I’ve uploaded a demo project to github, so feel free to download and play around with it.
Happy coding everyone!