iOS

Working with CoreNFC in iOS 11


At WWDC 2017, Apple announced a long wanted system framework for developers, CoreNFC. If you are not familiar with NFC, simply put, NFC (short for Near Field Communication) allows two devices to communicate with each other when placed within 4cm of each other. Most businesses put NFC chips in cards, enforcing tighter security of who can enter a building. Apple’s CoreNFC currently supports one single NFC format, NFC Data Exchange Format, or NDEF (commonly used in most tablets and phones on the market today).

Note: You will need Xcode 9 beta to follow tutorial. You will also need an iPhone 7 or iPhone 7 Plus running iOS 11 beta in order to test out some of the features of this tutorial. While Xcode 9 beta supports both Swift 3.2 and 4.0, all the code is written in Swift 4. You cannot build or compile an app which imports the CoreNFC framework unless it is being run on a physical device. A paid developer account is required for this tutorial.

What is CoreNFC?

“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). To read a tag, your app creates an NFC NDEF reader session and provides a delegate. A running reader session polls for NFC tags and calls the delegate when it finds tags that contain NDEF messages, passing the messages to the delegate. The delegate can read the messages and handle conditions that can cause a session to become invalid.”

- Apple’s official documentation on CoreNFC.

NFC is by no means a “new” technology; however, Apple has finally opened up this API to developers so that we can take advantage of the NFC reader.

Here’s a practical use-case: You run a shop and want the customers to just walk in, scan an item using NFC, and walk out. There’s no hassle and no wait time. As an app developer, without access to NFC, the second best thing would probably be bar-codes or QR-codes, but that’s annoying and takes a lot more work to scan.

So, what’s the catch? Though Apple finally opens up the NFC reader, the company strictly limits our access. This means CoreNFC only supports the NDEF format mentioned earlier. If you are planning to use CoreNFC to replace your RFID iClass cards (a commonly used format in business security cards), think again.

CoreNFC Demo

Let’s work on a demo app to see how to use CoreNFC. Our app is going to reveal a secret message stored on a NDEF-formatted card.

working-scanner

To do this, I programmed a message onto a sample NDEF-formatted card using an Arduino Uno paired with a Adafruit PN532 Shield. If you don’t have these tools or simply don’t want to invest the time and money in such hardware, try and find a pre-formatted card with a message on it. I won’t be covering NFC formatting, or embedding messages in a NDEF card in this tutorial.

AdafruitPN532

Getting Started

To create our project, open Xcode 9 and create a new single-view application. Proceed to name your project and make sure to choose Swift as your language.

create-new-proj

Designing the Message View

To being, we need to make a user interface (UI) for the user to interact with. Let’s start by creating a navigation controller. Go to Main.storyboard and select the view controller. Then, go to the status bar and click Editor > Embed In > Navigation Controller. This should create a nav bar at the top of your main view. Feel free to customize the title of this nav bar if you see fit. I went with “Message in a Bottle”.

embed-nav-controller

Next, drag in a UIButton and place it at the bottom of the view. Change the button’s text to ‘scan’, and format it as you like. After you add the scan button, let’s also add a UILabel for the scanned message to go and format it as you please. Now our app should look something like this:

demo-app-ui

Setting up Scan and Message

Now that we’ve setup the necessary components of our app, let’s get our hands dirty in code. We will start off with connecting the label and button. Open the assistant-editor (two circles at the top of Xcode) and control-drag from the UILabel to your code to create an outlet.

ui-connect-outlet

Now, do a similar connection with the scan button. In the connection details pop-up change ‘outlet’ to ‘action’. Name your IBAction function whatever you’d like, I called mine scanPressed Here’s what our ViewController.swift should look like:

Setting up App Entitlements and Privacy

Next, before we can really start working on our NFC implementation, we need to set up our app entitlements.

Note: It is imperative that you follow this section extremely closely otherwise your app configuration will not work as expected. Also, you will require a paid developer account.

To start, head on over to developer.apple.com. Sign into your account, and once you’re in the Account panel, head to Certificates, Identifiers & Profiles tab. Under Identifiers, click App IDs. Then, click the (+) to register a new App ID. The App ID Description should be simple (i.e. nfc). You Explicit App ID and the Bundle ID must match the Bundle Identifier you used in your Xcode project exactly My Bundle Identifier is com.YOURDOMAIN.Message-in-a-Bottle. Once you’ve put your Bundle Identifier in, scroll down and check NFC Tag Reading in the list of services. Click next and make sure your confirmation page looks similar to mine:

app-id-confirm

Once that is all set up, we need to create a new provisioning profile for this app. Go to the Provisioning Profiles tab and click all. Then, click (+) to make a new provisioning profile. Choose iOS Development, continue. Select your App ID’s name (mine is nfc), and continue. Choose the certificate you use, and select any phone you might want to test this app on. Name your profile whatever you feel like, and finish! You should have a new active provisioning profile.

provisioning

What’s a provisioning profile? A provisioning profile authenticates a particular bundle Id (and app) to run on selected devices. This way, you can be sure the apps running on your device are traceable and secure.

We still need to select that specific profile for our app to build with. To do so, navigate back to Xcode > Project settings > then disable Automatically manage signing. For both Debug and Release, select the dropdown menu and choose Download profile. Find your profile (again, mine is nfc and select it. With that, you’re all set! Phew, the hard work is almost done!

Now, here’s where things get a little sketchy. We need to add app entitlements; however, the Xcode team has not enabled automatic entitlements for CoreNFC yet. For now, download this prebuilt entitlements file and put the file location in the text-box at Project > Build Settings > Code Signing Entitlement.

We anticipate Apple will update this feature in the near future, but for now this is the route to go. So if you can’t figure it out, come back to this tutorial once a new beta is released.

There’s only one more privacy policy we need to follow! (Last one I swear) 🙂

Open Info.plist and right click to add a row. In the ‘key’ column, open the dropdown menu and choose Privacy - NFC Scan Usage Description. Set the value to a string of whatever you’d like! This update to our plist file allows our app to access the necessary permissions for NFC.

info-plist

Implementing CoreNFC

Ok, that was a lot. Take a breath, even I’m tired after that! It’s done now though. Let’s get on to the fun part! We’ll go ahead and add a few lines to our ViewController.swift but before we jump into the code, I need to mention an issue that had me tripped up for a couple hours.

Currently, the CoreNFC framework has not been compiled into the iOS simulator yet. This means if you try to import CoreNFC you will get an error saying there is no module named CoreNFC. Simple fix though, select either your iPhone or Generic Device in the active-scheme device selector.

Whoa, Charles, I don’t know what any of that does!

Let me break it down for you.

Line #2– First, we imported CoreNFC.
Line #4 – Then, we adopted and conformed to NFCNDEFReaderSessionDelegate protocol. The two readerSession functions allow us to either figure out what invalidated our NFC session, or receive data from the NFC scan. Having this all set up gives us a basic outline of what we’re doing.

We’re about to be able to see our NFC scanner in action, just two more lines of code need to be added to start the NFC listener.

Let’s update the scanPressed method we created before to invoke the NFCNDEFReaderSession initializer.

These lines are pretty self explanatory, but let’s look into them anyways.

We are initializing the NFC reader, setting the delegate to self (so we call our readerSession functions) and then we invalidate (or stop searching for) the NFC session. It’s always good to understand your code, so I’ll always break down what I’m doing for you.

With that in mind, let’s build and run the app!

working-scanner

If you got an error along the lines of Session is invalidated unexpectedly when running the app, go back and take another look at the “Setting up App Entitlements and Privacy” section — chances are you didn’t do something right there. If it works, congrats!

In concept, that was pretty simple, however Apple has really locked down access to use NFC, and for a good reason too. Getting to this point might have been a bit challenging, but parsing the records is a real blast! Let’s look into that.

Parsing the Message Records

First, let’s take a look at func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {

For those of you who are eager to see what messages[0] contains, let’s take a look — I’m just going to print the contents of the first object in messages and annotate it:

Amazing, right? Apple is actually giving us more than we need! Anyways, if you’ve messed with reading NFC-NDEF tags, you will recognize a lot of these objects. If not, then let’s break it down!

To make this output easier for us to dissect, I’m going to help you visualize this object:

  • messages is an array of NFCNDEFMessages, one for each scan we perform before the NFC session becomes invalidated, though in our app, we invalidate the session automatically after the first scan. We only need to worry about one object in the array.

  • messages[0] is a NFCNDEFMessage, and it contains a NFCNDEFPayload.

  • messages[0].records is an array of NFCNDEFPayloads. This is an array because NDEF cards can contain multiple payloads. For our use, we only will have one payload.

A single NFCNDEFPayload contains 4 items of information:

1.identifier,
2.type, and
3.typeNameFormat. We’re only going to worry about payload.
4.payload is an object of type Data (if we convert the data to a string, we’ll have our message).

Cool! Hopefully that helps a little bit. If it doesn’t, don’t worry too much. It will make more sense as we go.

Let’s just go ahead and start parsing our records:

*”Wait, Charles, I have a few questions. Why are you 1. advancing by 3? What’s the point of that DispatchQueue stuff?” *

First of all, I was a little confused at first with why my NFC tag always started with “enHello” or “enMessage”. After doing some research on NDEF specifications and regulations, I figured this out:

“All language codes MUST be done according to RFC 3066 [RFC3066]. The language code MAY NOT be omitted. The language code length is encoded in the six least significant bits of the status byte. Thus it is easy to find by masking the status byte with the value 0x3F.”

- NFC Data Exchange Format (NDEF) Technical Specification, NFC Forum

For legal reasons, we cannot link to the NDEF regulations PDF, but you may search for it on the internet in your own time to find out more about this restrictions.

In short, section 3.3, “Language Codes”, states that language codes may not be omitted and is a requirement.

In conclusion, line 3 converts the payload from type Data to a human-readable string. I’m skipping the bytes of data which include language codes, so the app does not display, “enMessage in a card!”

On the subject of DispatchQueue, messageLabel is not accessable by readerSession. I’m accessing messageLabel through the main queue, which is the easiest way to exchange the information between threads.

Here’s the final product in action:

CoreNFC Demo

Recap

In this tutorial, we explored the new CoreNFC framework and built a sample app to demonstrate its potential.

In this app we used CoreNFC to tap a physical card against our iPhone, and used the NFC Data Exchange Format to send a message from the card to the iPhone. You can download the complete project here

How will you use CoreNFC in your business? How do you hope to see it used? Leave a comment and let me know!

iOS
Creating a Sidebar Menu Using SWRevealViewController in Swift
iOS
Creating an Immersive User Experience with Haptic Feedback in iOS
iOS
Understanding Key-Value Observing and Coding
Shares