Reading and Parsing NFC tag on iOS 11

Aijin Yuan (Vince)
5 min readAug 28, 2017

--

Apple finally opens iPhone’s NFC chip. With iOS 11, apps on iPhone 7 and iPhone 7 plus can read NFC tag using Core NFC. (Writing is not allowed!) It adds more possibilities to apps. For example, we can use iPhone to tap a NFC tag to read business car, make phone call, open web page, create an email, open another app, or share Wi-Fi. Apple itself uses NFC to pair up HomeKit devices.

Using Core NFC, you can read Near Field Communication (NFC) tags of types 1 through 5 that contain data in the NFC Data Exchange Format (NDEF). Let’s write some code.

Firstly, import Core NFC library in your iOS project.

import CoreNFC

Secondly, make YourViewController class conform to NFCNDEFReaderSessionDelegate, like this:

class YourViewController: UIViewController, NFCNDEFReaderSessionDelegate {

Thirdly, start a NFCNDEFReaderSession when you tap a button.

@IBAction func didTapScanNFCTagButton(_ sender: Any) {
let session = NFCNDEFReaderSession(delegate: self, queue: DispatchQueue.main, invalidateAfterFirstRead: false)
session.begin()
}

Lastly, get the NFC NDEF message in the callback.

func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
for message in messages {
for payloadRecord in message.records {
// Handle payloadRecord here
}
}
}

Here, payloadRecord’s type is NFCNDEFPayload. But as you can see in the following picture, Apple’s doc does not give us much detail. typeNameFormat could be nfcWellKnown, media or several other types. But identifier, payload and type are all Data which could be anything.

Let’s try to read a simplest NFC tag which contains plain text only. I have empty NFC tags and wrote plain text “hello” into a NFC tag with a free app NFC TagWriter by NXP on an old Android phone Samsung Galaxy Note 3. (Yes, Android phones have NFC for years.). As you can see below, it supports writing many types of data, such as business card, link, email, telephone number, geo location, plain text, etc.

TagWriter and data types it supports

For the plain text tag, typeNameFormat isnfcWellKnown. Let’s assume identifier, payload and type are all UTF-8 string. After we convert Data to string and print them out, we will see identifier is empty, type is “T”, payload is “enhello”. Obviously “T” means Text. But why is there “en” before “hello”?

The actual content of payload is the following in hex:

02 65 6E 68 65 6C 6C 6F    |.enhello|

The structure of plain text payload is more complex than you expected. It consists of 1 status byte, 2 or 5 byte language code, and multiple bytes in UTF-8 or UTF-16. Here is the explaination (from Austin Blackstone’s post. Many thanks!).

|------------------------------|
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0|
|------------------------------|
|UTF| 0 | Length of Lang Code | 1 byte Text Record StatusByte
|------------------------------|
| Lang Code | 2 or 5 byte, multi-byte lang code
|------------------------------|
| Text | Multiple Bytes in UTF-8 or UTF-16
|------------------------------|

For our plain text “hello” payload, the first byte is 02 in hex. It is 00000010 in binary. The No. 7 bit is 0 which means the text is encoded in UTF-8. The 0–5 bits show the length of language code. The length is 2. The following 2 bytes “en” is the language code. The real text is the remaining bytes “hello”.

An NDEF message consists of header and payload. Core NFC parses message header only, but does not parse message payload. You can see even if we only read a plain text NFC tag using Core NFC, it is not so easy as we expected. We can imagine reading NFC tag with other types of payload is much more challenging.

I decided to accept the challenge. I made VYNFCKit, an open source NFC NDEF message payload parsing library. VYNFCKit supports parsing almost all data types TagWriter supports, including Business card, Link, WiFi, Email, Telephone number, Geo location, Plain text and SMS. I did not have time to handle Bluetooth and Launch Application. Launch Application seems for Android only.

VYNFCKit example app

Parsing NFC NDEF message payload with VYNFCKit becomes easy.

func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
for message in messages {
for payload in message.records {
guard let parsedPayload = VYNFCNDEFPayloadParser.parse(payload) else {
continue
}
if let parsedPayload = parsedPayload as? VYNFCNDEFTextPayload {
// parsedPayload.text
} else if let parsedPayload = parsedPayload as? VYNFCNDEFURIPayload {
// parsedPayload.uriString
} else if let parsedPayload = parsedPayload as? VYNFCNDEFTextXVCardPayload {
// parsedPayload.text
} else if let sp = parsedPayload as? VYNFCNDEFSmartPosterPayload {
for textPayload in sp.payloadTexts {
if let textPayload = textPayload as? VYNFCNDEFTextPayload {
//textPayload.text
}
}
// sp.payloadURI.uriString
} else if let wifi = parsedPayload as? VYNFCNDEFWifiSimpleConfigPayload {
// wifi.credential.ssid, wifi.credential.networkKey, wifi.credential.macAddress,
// wifi.credential.authType,
// wifi.credential.encryptType
}
}
}
}

Please refer to VYNFCKit for detailed steps. Example projects in both Objective-C and Swift are provided. Welcome to try VYNFCKit, report bugs, and send me pull requests. Star ⭐️ it if it helps you a little. 🍺

--

--

Aijin Yuan (Vince)

iOS/Android/Web developer. UX engineering lead at Grab. Singapore/Hong Kong/Shanghai