Near-field communication (NFC) is standardized by ISO/IEC 18092. While not a new technology it has become more important with the proliferation of mobile devices. Phone manufacturers have increasingly begun to incorporate NFC hardware in their products. Like NFC credit cards, NFC capable phones can exchange money with an NFC equipped vendor.
Making payments with NFC card emulation is handy, but there are many uses for NFC. NFC reader/writer mode allows data to be pushed or pulled from a tag. NFC tags do not cost much to manufacture; this makes them attractive for tagging large volumes of items.
Using NFC peer-to-peer (P2P) mode, devices can communicate data with each other. The NFC Forum has defined standards for exchanging data. NFC Data Exchange Format (NDEF) messages encapsulate data for transport over Simple NDEF Exchange Protocol (SNEP).
These modes are what consumers and developers use to solve problems. An end user can write to tags to share information or create triggers for their smartphones. Machine to machine (M2M) applications can be built using active and passive P2P. They exchange data and make decisions without user intervention. NFC P2P can transport data just like over BLE or Wi-Fi. Any application can be ported to use NFC as its network transport layer.
Security is another use for NFC. Bluetooth provides a specification for Secure Simple Pairing (SSP) using an Out of Band (OOB) device for authentication. An NFC device can be employed as the OOB source to establish a secure bond between devices.
NFC is a flexible technology. It has a variety of uses, not just for buying coffee or checking out at the pharmacy. My hope is that mobile hardware companies continue to invest in NFC technology. I'm excited to start using CoreNFC on iOS.
WWDC 2017 was filled with announcements. Every year Apple fans always anticipate the event. This year was no different, and Apple did not disappoint; new Macs, updated MacOS and iOS platforms, and many new and exciting APIs. It was a packed event. With so many new things to talk about, it wasn't a surprise that a few things slipped in without an announcement. One of these things was CoreNFC.
During 2014 Apple released the iPhone 6 and 6 plus. These were the first iPhones to contain NFC hardware. The primary purpose was to support Apple Pay. Like other "new" hardware features on the iPhone, Apple did not immediately provide public APIs to access the NFC chip. This limitation didn't stop clever jailbreakers from trying though.
CoreNFC appeared silently in the first beta for iOS 11. It is seemingly buried in the documentation updates for iOS 11. The docs were very limited, the APIs a bit confusing at first, and no sample code as of the first beta release; however, the framework did not go unnoticed. Almost immediately threads began to appear on the developer forums. It was definitely a beta level API.
There are two main components to the API: a session, and a tag data structure. References to NFC NDEF and tag data from vicinity cards (ISO/IEC 15693) appear in the documentation. The documentation also states that:
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).
Many developers had issues getting the code to work at runtime. It didn't seem like there is a single recurring problem. I always expect bugs with Beta 1 for iOS and Apple usually gets them fixed quickly. Subsequent betas fleshed out details for CoreNFC, and things are working much more smoothly now. As of beta 5, we are still sadly missing RFID support.
There are a few parts to how the session works in CoreNFC. First, there is an abstract based class
NFCReaderSession. It is important to note that you do not work directly with instances of this class but with its subclass
NFCNDEFReaderSession. The base class contains only two properties, a
delegate and a
sessionQueue. Finally, it conforms with
sessionQueue is a
DispatchQueue. It delivers messages to the
delegate when the session receives events. As with all asynchronous APIs on iOS, it is always good practice to use a background queue and not the main queue. In addition to blocking your UI and potentially making it drop frames, using the main queue can cause x8badf00d. It is important to remember that you must dispatch any UIKit calls back onto
Next we have 'NFCReaderSessionProtocol' which
NFCReaderSession adopts. This protocol has the primary functions for controlling with the session object.
isReadyis a flag that indicates that the session is both started and available for use.
begin()will instruct the session to start, begin scanning, and deliver notifications to the delegate object.
invalidate()ends the session and stops delivery of notifications to the delegate object.
There are three notifications that the delegate can receive:
begin()is invoked on the session and it is ready to start scanning.
NFCTagdata to the delegate when an NFC device has been scanned.
readerSession](didInvalidateWithError:)notifies that the session became invalid.
NFC Data Exchange Format (NDEF) is a standard that defines a how NFC data should be formatted. The
NFCNDEFReaderSession is currently the only concrete implementation of
NFCReaderSession. This class is the primary means to read NFC devices. It is important to note that only one session can be active at a time. The docs state that the sessions objects are placed into a queue and processed in 'first in first out' order.
NDEF session gives us an initializer which takes an
DispatchQueue to delivery delegate notifications on, and an
invalidateAfterFirstRead flag which makes single reads easier to manage. If we drill down into the headers again, we can find some valuable information that is not available in the docs.
An NDEF reader session will automatically scan and detect NFC Forum tags that contain a valid NDEF message. NFC Forum Tag type 1 to 5 that is NDEF formatted are supported. A modal system UI will present once -beginSession is called to inform the start of the session; the UI sheet is automatically dismissed when the session is invalidated either by the user or by calling -invalidateSession. The reader session has the following properties: - An opened session has a 60 seconds time limit restriction after -beginSession is called; -readerSession:didInvalidateWithError: will return NFCReaderSessionInvalidationErrorSessionTimeout error when the time limit is reached. - Only 1 active reader session is allowed in the system; -readerSession:didInvalidateWithError: will return NFCReaderSessionInvalidationErrorSystemIsBusy when a new reader session is initiated by -beginSession when there is an active reader session. - readerSession:didInvalidateWithError: will return NFCReaderSessionInvalidationErrorUserCanceled when user clicks on the done button on the UI. - readerSession:didInvalidateWithError: will return NFCReaderSessionInvalidationErrorSessionTerminatedUnexpectedly when the client application enters the background state. - readerSession:didInvalidateWithError: will return NFCReaderErrorUnsupportedFeature when 1) reader mode feature is not available on the hardware, 2) client application does not have the required entitlement.
The headers reinforce the fact that only one session can be active. We are given one minute to look for tags, after that the session is immediately invalidated. Backgrounding the app will also cause the session to become invalidated. Finally, the user is prompted with a system UI. They can choose to cancel at any time.
Once we create the session using the
initWithDelegate:queue:invalidateAfterFirstRead: initializer then we are ready to start scanning and get tag data into an
This delegate allows access to events from the
NFCNDEFReaderSession. Earlier we discussed the
NFCReaderSessionDelegate protocol. If we look at the NDEF delegate, we can see that it only conforms to NSObjectProtocol and not
NFCReaderSessionDelegate. The NDEF session delegate gives us a different set of methods:
readerSession:didInvalidateWithError:indicates an error has occurred.
readerSession:didDetectNDEFs:delivers NDEF tag data that was read by the session.
The headers give us some more information about the implementation details for how NFC is detected. When the system reads tag data, it will not try to look for more tags until the NFC tag is out of range. Again don't forget that if you are calling UIKit methods from these events, you must dispatch back to the main queue.
NDEF data is exposed by instances of NFCNDEFMessage. There is a single property
records which contains an array of
NFCNDEFPayload objects. The payload objects include several fields, type name format, type, identifier, and payload. These will be unique to the tag or hardware you are reading.
Wrapping it up
To start writing code, there are a few things to setup in the project file.
First head over to the Apple Developer portal and setup a bundle id for the app. There is a new entitlement that must be activated.
NFC Tag Reading is located close to the end of the 'Application Services'. Check the box and save the changes.
In beta 1 for iOS 11, this option did not appear in Xcode. With beta 5 this option is available in Xcode from the target capabilities screen. Turning this on will activate the entitlement in the developer portal and add an entitlements file to your project.
The second part is important but very difficult to figure out. There is a new info.plist key called
NFCReaderUsageDescription. Similar to other application services, this info-key must contain a description for your app to use the NFC hardware. If this is missing, then you don't get any warnings at compile time, but your session will never become active and fail with an obscure error that does not indicate the problem. The documentation online only mentions this key in one place.
Once these things are setup, you are ready to create a delegate and start scanning for NFC NDEF data.
I'm excited to start using these new APIs. I think there will be some great apps coming this fall that will leverage NFC for both entertainment and security.
Check out our sample app here.