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 Reader
named 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 applicationWillEnterForeground(_ application: UIApplication) {}
func applicationDidBecomeActive(_ application: UIApplication) {}
}
/// 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) {}
}