iOS 11 Core NFC - any sample code?

Blisterpeanuts picture Blisterpeanuts · Jun 6, 2017 · Viewed 20.3k times · Source

I just installed the first iOS 11 beta to an iPhone 7 and am interested in trying the NFC. There's nothing about it in settings. I am wondering if there's any sample code out there showing how to read a tag. Can anyone show how to use the Core NFC SDK, in a code snippet?

Answer

Boris picture Boris · Jun 6, 2017

In the Apple Developer site, create a new App ID and make sure that NFC Tag Reading is enabled.

Dev portal capabilities

Add the following lines to your .plist file:

<key>NFCReaderUsageDescription</key>
<string>NFC Tag!</string>

and these to the entitlements file:

<key>com.apple.developer.nfc.readersession.formats</key>
    <array>
        <string>NDEF</string>
    </array>

It should look something like this in the corresponding files:

enter image description here

Also Core NFC can be enabled via the Capabilities tab in Xcode.

enter image description here

Objective-c

Import CoreNFC

#import <CoreNFC/CoreNFC.h>

and set the delegate:

@interface YourViewController : UIViewController <NFCNDEFReaderSessionDelegate>

In viewDidLoad:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NFCNDEFReaderSession *session = [[NFCNDEFReaderSession alloc] initWithDelegate:self queue:dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT) invalidateAfterFirstRead:NO];
    [session beginSession];
}

In the delegate callback:

- (void) readerSession:(nonnull NFCNDEFReaderSession *)session didDetectNDEFs:(nonnull NSArray<NFCNDEFMessage *> *)messages {

    for (NFCNDEFMessage *message in messages) {
        for (NFCNDEFPayload *payload in message.records) {
            NSLog(@"Payload data:%@",payload.payload);
        }
    }        
}

You must also add the didInvalidateWithError delegate callback or you'll not conform with protocol:

- (void)readerSession:(nonnull NFCNDEFReaderSession *)session didInvalidateWithError:(nonnull NSError *)error {

}

You can stop the reader with:

[session invalidateSession];

Swift 3/4

Import CoreNFC

import CoreNFC

and set the delegate:

class YourViewController: UIViewController, NFCNDEFReaderSessionDelegate

In viewDidLoad:

override func viewDidLoad() {
        super.viewDidLoad()

        let session = NFCNDEFReaderSession(delegate: self,
                      queue: DispatchQueue(label: "queueName", attributes: .concurrent), invalidateAfterFirstRead: false)  
        session?.begin()
    }

In the delegate callback:

func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
  for message in messages {
    for record in message.records {
      print(record.payload)
    }
  }
}

You can stop the reader with:

session.invalidateSession

Usage

After launching the view you should immediately see the iOS NFC reader dialog like so:

iOS NFC reader dialog

Once this dialog appears you have about a second to place the iPhone near the NFC tag you want to read. Otherwise, the field is deactivated (this seems to be a bug on Apple's end). I often needed to cancel and retry to get consistent readings. More details here.