Tutorial

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
Using Swift Protocols to Manage App Configuration
iOS
Using Braintree to Accept Credit Card Payment in iOS Apps
iOS
How to Use iOS Charts API to Create Beautiful Charts in Swift
  • Stefan Walkner

    thanks for the great article! But did I get it right that only NFC (NEAR field) is possible and no scanning from some further distance (multiple centimeters or even meters)?


    • Charles Truluck

      You are correct. NFC was built to work over very small distances.


      • Stefan Walkner

        and RFID isn’t possible with the iPhone?


        • Charles Truluck

          I asked an engineer about their plans to implement RFID/iClass support at WWDC, and he said they hadn’t ruled it out. He told me to submit a radar with the feature request (and also mentioned they planned to use RFID on the iPhone at the new Apple campus).


          • Mike

            MikeMike

            Author

            What is a “radar”? How do you submit a feature request?


          • Charles Truluck

            “radar” is what apple calls their bug reporting system. (radar.apple.com) you can. submit a feature request the same way you’d submit a bug report but you choose “suggestion”.


  • Hellen

    HellenHellen

    Author Reply

    I did all like tutorials says (and even try simply to download full project) but in all cases I have two errors:
    – When permission dialog show – there is no permission description text, only empty space.
    – When NFC detect some tag it is always have error

    connection to service named com.apple.nfcd.service.corenfc: Exception caught during decoding of received message, dropping incoming message.

    Exception: Exception while decoding argument 0 (#2 of invocation):

    return value: {v} void

    target: {@} 0x0

    selector: {:} didDetectExternalReader:

    argument 2: {@} 0x0

    Exception: decodeObjectForKey: class “NFTechnologyEvent” not loaded or does not exist

    Help, please!


    • Charles Truluck

      1. As for the permission dialog, make sure you add a line in your Info.plist for “Privacy – NFC Scan Usage Description” and set it to a string with whatever you’d like.
      2. I cannot figure out what your issue is. It looks like it’s an issue with beta 2, try upgrading to beta 4. (ref https://forums.developer.apple.com/thread/79045)

      Let me know if I can help further.


  • TheVirusKA

    TheVirusKATheVirusKA

    Author Reply

    Hello! is it possible to have two iPhones or even an Android communicate with each other from NFC?


    • Charles Truluck

      No, at the moment that is not a possibility as far as I know.


  • Luigi

    LuigiLuigi

    Author Reply

    Hi, thanks for this tutorial… however I tried the app on iphone 7 with iOS11 beta 7… but When I click on “Scan” the app shows the Popup “Ready to San” but no NFC code are recognised… do you have any idea?


  • John Doe

    John DoeJohn Doe

    Author Reply

    Hi Charles, thanks for the very easy and clean Article, till now i got the point that we can read NFC Tag with the help of ReaderClass but can we create NFC Tag using NFCTag class? I have done some research over the SO, but not that lucky so could you help me over this?


    • Charles Truluck

      As of now, you can only read tags. Apple has not opened up the ability to write to tags. It’s kinda sad how constricting CoreNFC is, it has so much potential.


      • SoCal482

        SoCal482SoCal482

        Author Reply

        Agree. I bought a ~ $30USD writer device that attaches via USB to my MacBook. Without write, many use cases won’t be possible. Hopefully next Sept with iOS 12.


  • SoCal482

    SoCal482SoCal482

    Author Reply

    Nice tutorial. Although you might want to update with the release 9.0.x code – some images look slightly different.

    I’m stuck when I try to Build/Run, I get “Unable to install “NFCX”

    “NFCX” requires the “” capability which is not supported by iPhone

    My iPhone is a 7+. I know the RFID works – use Apple Pay successfully.

    PS – is your site all Swift? I’m still using Objective-C. Any thoughts to having both? I think there are plenty of people who haven’t switched yet.


  • Anu

    AnuAnu

    Author Reply

    Hi,
    Is there any way to hide the actionsheet which is displayed on session.begin() call. I want to directly scan the NFC tag without showing the action sheet.
    My requirement is to automatically tap on the nfc tag and detect it without triggering with the scan button.


  • Zaid Mirza

    Zaid MirzaZaid Mirza

    Author Reply

    Great, I want to know, can we remove that fault sheet from bottom when we are scanning ?


  • Harsh

    HarshHarsh

    Author Reply

    Hi Charles Truluck!
    Is it possible for us to override the View Apple shows for Scanning the NFC Tag? I mean can we override the default NFC Screen where it says to “Hold your iPhone near in a Card” and put our customised View?


  • Bang Tran Thanh

    Thanks for detail tutorial. I have just implemented as over. But it’s not working welll.
    I didn’t get anything when a move the card to closest with my phone. And by timeout the popup scan card automatic closed.
    My’s device is iphone 7 plus OS System: 11.3
    Please help me.


  • Peter R

    Peter RPeter R

    Author Reply

    “advancing by 3” may not be a good solution.
    I suspect there is no language code since iOS 12, because this solution just cripples my NDEF content on my device.
    Is there a better way to detect and remove the language code that works when it’s there (iOS11?) and when it’s not (iOS12?)?


Shares