In this blog I’ll demonstrate how you can add native code/functionalities to your SAP MDK project. Most requirements can be solved using the NativeScript plugins, like in this tutorial. For our use case however, NativeScript alone, couldn’t provide the solution we needed. To tackle this limitation, you can create a Swift Class in Xcode and call it from an MDK app.

 

Use case

We want to read NFC tags, more specifically the NFC UID. This guaranties us that we read the ID from the tag that is unique in the world and cannot be overwritten. This UID will be saved in the Equipment (PM) master data. (not part of this tutorial)

Why not use the NDEF messages?

We have about 15.000 NFC tags and the end users solely use iPhones. Writing NDEF messages, and locking the NFC tag afterwards using NativeScript alone is not possible (at least with available NPM packages that I could find) on iOS. NativeSctript NFC GitHub

 

Prerequisites (iOS)

If you want to debug your Swift code, you’ll need:

  • A Mac with Xcode installed
  • An Apple Developer Program account (Paid) –  needed for NFC reading
  • Install all SDK dependencies: Tutorial

 

Tutorial/Code

The folder structure with all the needed files for the MDK client build will look like this:

NFCScanning.mdkproject/
┣ App_Resources/
┃ ┣ Android/
┃ ┃ ┗ src/
┃ ┃   ┗ main/
┃ ┗ iOS/
┃   ┣ src/
┃   ┃ ┗ NFCScanningControllerBridge.swift
┃   ┗ app.entitlements
┣ App_Resources_Merge/
┃ ┗ iOS/
┃   ┗ Info.plist
┣ extensions/
┣ BrandedSettings.json
┗ MDKProject.json

Github

 

Create a Swift class (NFCScanningControlBridge.swift) that reads an NFC tag UID and sends it back to the caller using a callback function:

import UIKit
import CoreNFC

@objc(NFCScanningControlBridge)
public class NFCScanningControlBridge: NSObject,  NFCTagReaderSessionDelegate {

    var session: NFCTagReaderSession?

    @objc public var onNFCFoundCallback: ((String) -> Void)? = nil
    
    public override init() {
        super.init()
        CaptureNFC()
    }
    
    @objc public func CaptureNFC() {
        print("CaptureNFC");
        self.session = NFCTagReaderSession(pollingOption: .iso14443, delegate: self)
        self.session?.alertMessage = "Hold Your Phone Near the NFC Tag"
        self.session?.begin()
    }

    public func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
        print("Session Begun!")
    }

    public func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
        print("Error with Launching Session")
    }

    public func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
        if tags.count > 1{
            session.alertMessage = "More Than One Tag Detected, Please try again"
            session.invalidate()
        }
        let tag = tags.first!
        session.connect(to: tag) { (error) in
            if nil != error{
                session.invalidate(errorMessage: "Connection Failed")
            }
            if case let .miFare(sTag) = tag{
                let UID = sTag.identifier.map{ String(format: "%.2hhx", $0)}.joined()
                print("UID:", UID)
                print(sTag.identifier)
                session.invalidate()
                
                // Use main thread
                DispatchQueue.main.async {
                    self.onNFCFoundCallback?(UID);
                }
            }
        }
    }
}

 

Give permission to read NFC Tags, by adding the app.entitlements file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.developer.nfc.readersession.formats</key>
	<array>
		<string>NDEF</string>
		<string>TAG</string>
	</array>
</dict>
</plist>

 

Add the iOS properties file (Info.plist) This file contains critical information about the configuration of an iOS mobile app. We add the NFC reader usage description.

BEWARE: this file is added in the App_Resouces_Merge folder. This is needed because the SAP MDK app will also generate this file, which we don’t want to overwrite. Therefore SAP has foreseen this overriding mechanism: Overriding App Resources – SAP Mobile Services Documentation

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>NFCReaderUsageDescription</key>
	<string>core</string>
</dict>
</plist>

 

Use the Swift class in the MDK app (in this case in the Scan.js rule

/**
 * Describe this function...
 * @param {IClientAPI} clientAPI
 */

export default function Scan(clientAPI) {
  try {   
    // Create instance native iOS nfc scanning class
    var _iOSNFCScanControl = NFCScanningControlBridge.new();

    // Callback function with nfc tag uid
    _iOSNFCScanControl.onNFCFoundCallback = (tagUID) => {
       alert("Tag found: " + tagUID );
    }
  } catch (err) {
    alert("errer" + err)
  };
}

 

Debug on Mac

If you want to debug your Swift code in combination with your MDK app, you will need to create a custom client locally, as described in this tutorial

 

Once your custom client is built, open the /platforms/ios folder with Xcode in the generated MDK project directory.

In Xcode you can now run and debug the generated project. I can connect my own iPhone to test the app and put some breakpoints in the code. If I press the play button, the app will be installed on my iPhone and I can start debugging.

 

 

If I scan a tag, I can see the debugger stops on my breakpoint.

 

And finally…

 

Extra info and sources

SAP Mobile Services documentation for this topic

Example where Swift code is used in combination with MDK using an MDK Extension.

Swift Code for reading NFC UID

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x