SDK

Scannables

This functionality will allow your app to present content after they have scanned a NFC Tag or QR Code (we use QR Codes whenever the device does not support NFC). This could be extremely useful if you looking to extend physical objects with engaging content pretty much the same way you do when sending a notification.

Before you can start using this functionality you will need to create one or more tags in our dashboard. This is covered in our guides located here.

For this functionality you'll need to add the following to your app's .plist file:

ios nfc camera privacy entries

You must provide a text describing why your need to use NFC capabilities and why you need to use the camera in your app. Please note that only iPhone 7 and 7 Plus, iPhone 8 and 8 Plus and iPhone X support NFC scanning. When NFC is not supported or disabled, our library will fallback to QR codes scanning.

Scanning physical object is only available after our library has been initialized and is ready to use, so make sure you only start scanning after the onReady delegate has been triggered:

...more code

- (void)notificarePushLib:(NotificarePushLib *)library onReady:(nonnull NotificareApplication *)application {

    ...more code

    [self startScannableSession];

    ...more code
}

...more code
...more code

func notificarePushLib(_ library: NotificarePushLib, onReady application: NotificareApplication) {

    ...more code

    startScannableSession()

    ...more code
}

...more code

In most cases you will never want to start a scanning session from the onReady delegate, instead you will want to hook this method to a button in your UI. Just make sure that button is only enable when the onReady method has been triggered.

Because Apple will request information about your Core NFC functionality while reviewing your app, we decided not to include the NFCNDEFReaderSession methods inside our library for those users which that will not make use of these features. We do still ship a built-in view to scan QR Codes but the Core NFC methods you need to implement yourself using the examples below.

First start by importing the CoreNFC framework and let your class implement the NFCNDEFReaderSessionDelegate. Here we do it in the AppDelegate.m or AppDelegate.swift but you can do this from any other class:

#import <CoreNFC/CoreNFC.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, NotificarePushLibDelegate, NFCNDEFReaderSessionDelegate>
import CoreNFC

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, NotificarePushLibDelegate, NFCNDEFReaderSessionDelegate {

}

Then you should implement a method that will do two things. If the device support CoreNFC it will start a NFCNDEFReaderSession otherwise it will fallback to our built-in QR Code scanner as shown below:

-(void)startScannableSession{
    if (@available(iOS 11.0, *)) {
        if ([NFCNDEFReaderSession readingAvailable]) {
            NFCNDEFReaderSession * session = [[NFCNDEFReaderSession alloc] initWithDelegate:self queue:nil invalidateAfterFirstRead:YES];
            [session beginSession];
        } else {
            // Fallback for devices with no hardware support with QRCode
            UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
            [[NotificarePushLib shared] startScannableSessionWithQRCode:navController asModal:YES];
        }
    } else {
        // Fallback on earlier versions with QRCode
        UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
        [[NotificarePushLib shared] startScannableSessionWithQRCode:navController asModal:YES];
    }
}
func startScannableSession() {
    if #available(iOS 11.0, *) {
        if NFCNDEFReaderSession.readingAvailable {
            let session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true)
            session.begin()
        }
        else {
            // Fallback for devices with no hardware support with QRCode
            var navController = window.rootViewController as? UINavigationController
            NotificarePushLib.shared().startScannableSession(withQRCode: navController, asModal: true)
        }
    }
    else {
        // Fallback on earlier versions with QRCode
        var navController = window.rootViewController as? UINavigationController
        NotificarePushLib.shared().startScannableSession(withQRCode: navController, asModal: true)
    }
}

If a device supports CoreNFC you should implement the following to handle the result if successful:

-(void)readerSession:(NFCNDEFReaderSession *)session didDetectNDEFs:(NSArray<NFCNDEFMessage *> *)messages NS_AVAILABLE_IOS(11.0){
    if (@available(iOS 11.0, *)) {
        NSString * scannable = @"";
        for (NFCNDEFMessage *tagMessage in messages) {
            for (NFCNDEFPayload *tagPayload in [tagMessage records]) {
                NSString * typeString = [[NSString alloc] initWithData:tagPayload.type encoding:NSUTF8StringEncoding];
                if (tagPayload.typeNameFormat == NFCTypeNameFormatNFCWellKnown) {
                    if ([typeString isEqualToString:@"U"]) {
                        scannable = [[NotificarePushLib shared] parseURIPayload:tagPayload.payload];
                        if (scannable && scannable.length > 0) {
                            [[NotificarePushLib shared] fetchScannable:scannable];
                        } else {
                            //Handle Error
                        }
                    } else {
                        //Handle Error
                    }
                } else {
                    //Handle Error
                }
            }
        }
    }
}
func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
    if #available(iOS 11.0, *) {
        var scannable = ""
        for tagMessage: NFCNDEFMessage in messages {
            for tagPayload: NFCNDEFPayload in tagMessage.records {
                let typeString = String(data: tagPayload.type, encoding: .utf8)
                if tagPayload.typeNameFormat == .nfcWellKnown {
                    if (typeString == "U") {
                        scannable = NotificarePushLib.shared().parseURIPayload(tagPayload.payload)
                        if scannable && (scannable.count ?? 0) > 0 {
                            NotificarePushLib.shared().fetchScannable(scannable)
                        }
                        else {
                            //Handle Error
                        }
                    } else {
                        //Handle Error
                    }
                } else {
                    //Handle Error
                }
            }
        }
    }
}

If you get an error while scanning you can implement the following delegate to catch that error. As you can see in the example below you can still fallback ro the QR Code scanning:

-(void)readerSession:(NFCNDEFReaderSession *)session didInvalidateWithError:(nonnull NSError *)error NS_AVAILABLE_IOS(11.0) {
    UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
    switch ([error code]) {
        case NFCReaderErrorUnsupportedFeature:
            // Fallback for devices with no hardware support with QRCode
            [[NotificarePushLib shared] startScannableSessionWithQRCode];
            break;
        default:
            break;
    }
}
func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
    var navController = window.rootViewController as? UINavigationController
    switch (error as NSError?)?.code {
        case .readerErrorUnsupportedFeature:
            // Fallback for devices with no hardware support with QRCode
            NotificarePushLib.shared().startScannableSession(withQRCode: navController, asModal: true)
        default:
            break
    }
}

Once the scanning from both a NFC tag or QR Code is finished and a scannable has been found it will trigger the following delegate:

-(void)notificarePushLib:(NotificarePushLib *)library didDetectScannable:(nonnull NotificareScannable *)scannable{
    //Handle Scannable
}
func notificarePushLib(_ library: NotificarePushLib, didDetect scannable: NotificareScannable) {
    //Handle Scannable
}

If instead no valid tag could be found, it will trigger the following delegate:

-(void)notificarePushLib:(NotificarePushLib *)library didInvalidateScannableSessionWithError:(nonnull NSError *)error{
    //Handle error
}
func notificarePushLib(_ library: NotificarePushLib, didInvalidateScannableSessionWithError error: Error) {
    //Handle error
}

If you've included content in a tag, when successfully scanned you can open that content by invoking the following method:

[[NotificarePushLib shared] openScannable:scannable completionHandler:^(id  _Nullable response, NSError * _Nullable error) {
    if (!error) {
        UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
        [[NotificarePushLib shared] presentScannable:scannable inNavigationController:navController withController:response];
    }
}];
NotificarePushLib.shared().openScannable(scannable, completionHandler: {(_ response: Any?, _ error: Error?) -> Void in
    if error == nil {
        var navController = self.window.rootViewController as? UINavigationController
        NotificarePushLib.shared().presentScannable(scannable, in: navController, withController: response)
    }
})

This will make sure that as soon as a valid NFC tag or QR code is scanned your app will be able to handle results and present the content accordingly.