SCMEnvironment is the main class for the Smart Card Middleware API. It provides the initial entry points from connecting to the iOS API, obtaining the readers and listening to events.

The first function to call is: SCMEnvironment.createEnvironment(bluetoothSupport:completionHandler:). If the creation of the environment was successful, your app can get the list of all smart card readers by calling SCMEnvironment.getReaders().

Note that the if the phone supports NFC Tag Reader Session (iOS 13.0 or above, iPhone X or above), a NFC Readernamed NFC Interface will be added to the list of the reader.

To start listening to smart card events, your app needs to implement the ReaderEvents protocol and call SCMEnvironment.addReaderListener(listener:).

To start scanning for NFC tags, your app needs to call SCMEnvironment.initTagReaderSession(message:completionHandler:). After calling this function, iOS will display an alert action sheet waiting to detect tags. When a tag is detected, your app will receive an ReaderEvents.onReaderStateChanged(reader:) event, from which your app can start its own sequence of operation to perform with the card.

/// AppDelegate.swift

import UIKit
import ScmApi

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var env:SCMEnvironment?
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {}

    func applicationDidEnterBackground(_ application: UIApplication) {
        SCMEnvironment.notifyApplicationDidEnterBackground()
    }

    func applicationWillEnterForeground(_ application: UIApplication) {}

    func applicationDidBecomeActive(_ application: UIApplication) {}

    func applicationWillTerminate(_ application: UIApplication) {
        env?.notifyApplicationWillTerminate()
    }
}
/// ViewController.swift

import UIKit
import ScmApi

class ViewController: UIViewController, ReaderEvents {
    // assuming viewDidAppear is called before any other function that uses the environment
    override func viewDidAppear(_ animated: Bool) {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        if (appDelegate.env == nil) {
            SCMEnvironment.createEnvironment { (env, error) in
                if (error == nil) {
                    appDelegate.env = env

                    // register a reader event listener to start listening to smart card events
                    appDelegate.env!.addReaderListener(listener: self)
                }
                else {
                    // environment creation failed
                }
            }
        }
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let appDelegate = UIApplication.shared.delegate as! AppDelegate

        // remove the reader event listener.
        if (appDelegate.env != nil) {
            appDelegate.env?.removeReaderEventListener(listener: self)
        }
    }

    @IBAction func scan(_ sender: Any) {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate

        // start scanning for NFC tags
        appDelegate.env?.initTagReaderSession(message: "Scanning...", completionHandler: { (error) in
            // session is ended, possibly with an error
        })
    }


    // ##########################################################################
    // Reader event listener functions

    func onReaderAdded(reader: Reader) {}

    func onReaderStateChanged(reader: Reader) {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        if (reader.getName() == "NFC Interface") {
            if (reader.isCardPresent()) {
                // connecting to the card
                appDelegate.env!.updateTagReaderSession(message: "Connecting...");
                reader.connect { (token, error) in
                    if (error == nil) {
                        // retrieve all objects found in the token. The private objects may not be returned if the associated PIN has not been verified previously.
                        appDelegate.env!.updateTagReaderSession(message: "Reading smart card objects...");
                        token?.getObjects(completionHandler: { (objects, error) in
                            if (error == nil) {
                                // let's assume that the user choose the first certificate found in the card.
                                var cert: Certificate?
                                let pin: Pin?
                                for i in 0..<objects!.count {
                                    if (objects![i].getType() == "certificate") {
                                        cert = objects![i] as? Certificate
                                        break
                                    }
                                }
                                pin = cert?.getParent().pins()[(cert?.getPinNumber())!];
                                // login
                                pin?.login(value: "1234", completionHandler: { (error) in
                                    if (error == nil) {
                                        // after verifying PIN, the private objects can be retrieved
                                        token?.getObjects(completionHandler: { (objects, error) in
                                            if (error == nil) {
                                                var prkey: PrivateKey?
                                                // looking for the private key associated to the certificate chosen by the user
                                                for i in 0..<objects!.count {
                                                    if (objects![i].getType() == "privateKey" && objects![i].getCkId() == cert?.getCkId()) {
                                                        prkey = objects![i] as? PrivateKey
                                                        break
                                                    }
                                                }
                                                if (prkey != nil) {
                                                    if ((pin?.isValidated())!) {
                                                        appDelegate.env?.updateTagReaderSession(message: "Signing...");
                                                        prkey!.hashAndSign(data: dataFromHexString("12345678"), algorithm: "sha256", completionHandler: { (data, error) in
                                                            if (error == nil) {
                                                                appDelegate.env?.updateTagReaderSession(message: "Ok")
                                                                appDelegate.env?.endTagReaderSession(errorMessage: nil)
                                                            }
                                                            else {
                                                                // display error to user
                                                                appDelegate.env?.endTagReaderSession(errorMessage: error?.localizedDescription)
                                                            }
                                                        })
                                                    }
                                                }
                                                else {
                                                    // display error to user
                                                    appDelegate.env?.endTagReaderSession(errorMessage: "The private key associated to the certificate chosen not found")
                                                }

                                            }
                                            else {
                                                // display error to user
                                                appDelegate.env?.endTagReaderSession(errorMessage: error?.localizedDescription)
                                            }
                                        })
                                    }
                                    else {
                                        // display error to user
                                        appDelegate.env?.endTagReaderSession(errorMessage: error?.localizedDescription)
                                    }
                                })
                            }
                            else {
                                // display error to user
                                appDelegate.env?.endTagReaderSession(errorMessage: error?.localizedDescription);
                            }
                        })
                    }
                    else {
                        // display error to user
                        appDelegate.env?.endTagReaderSession(errorMessage: error?.localizedDescription);
                    }
                }
            }
        }
    }

    func onReaderRemoved(reader: Reader) {}
}