Issues Integrating FaceTec SDK into a Custom iOS Framework:

0

I am working on a custom iOS framework that integrates FaceTec SDK for biometric authentication, but I am facing issues with properly running the SDK within my framework. Below is the context and specific issues I need help with:

Context: I have created a framework that includes a UIViewController called FinishViewController. This controller is responsible for managing the FaceTec SDK session. Below is a simplified snippet of the code used to initialize and handle FaceTec SDK:

import UIKit
import FaceTecSDK
import LocalAuthentication

class FinishViewController: UIViewController, URLSessionDelegate{
    
    var utils: SampleAppUtilities!
    var latestProcessor: Processor!
    var latestExternalDatabaseRefID: String = ""
    var latestSessionResult: FaceTecSessionResult!
    var latestIDScanResult: FaceTecIDScanResult!
    

    
    @IBOutlet weak var elTelon: UIView!
    
    var isRealPerson = false
    var isNotSuccessful = false
    var isCancelled = false
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        utils = SampleAppUtilities(vc: self)
        // Initialize FaceTec SDK
        Config.initializeFaceTecSDKFromAutogeneratedConfig(completion: { initializationSuccessful in
            if(initializationSuccessful) {
                self.onFaceTecSDKInitializationSuccess()
            }
            else {
                self.onFaceTecSDKInitializationFailure()
            }
        })
        
        
        
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [self] in
            
            getSessionToken() { sessionToken in
                
                _ = LivenessCheckProcessor(sessionToken: sessionToken, fromViewController: self)
                .lvResponseDelegate = self
                //self.latestProcessor = AuthenticateProcessor(sessionToken: sessionToken, fromViewController: self)
            }
            
        }
        // Do any additional setup after loading the view.
    }
    
    func onFaceTecSDKInitializationFailure() {
        // Displays the FaceTec SDK Status to text field if init failed
        self.utils.displayStatus(statusString: "\(FaceTec.sdk.description(for: FaceTec.sdk.getStatus()))")
    }
    
    func onFaceTecSDKInitializationSuccess() {
        //        self.utils.enableButtons(shouldEnable: true)
        
        // Set your FaceTec Device SDK Customizations.
        ThemeHelpers.setAppTheme(theme: utils.currentTheme)
        
        // Set the sound files that are to be used for Vocal Guidance.
        
        
        
        // Set the strings to be used for group names, field names, and placeholder texts for the FaceTec ID Scan User OCR Confirmation Screen.
        SampleAppUtilities.setOCRLocalization()
        let currentTheme = Config.wasSDKConfiguredWithConfigWizard ? "Config Wizard Theme" : "FaceTec Theme"
        utils.handleThemeSelection(theme: currentTheme)
        self.utils.displayStatus(statusString: "Initialized Successfully.")
        
    }
    func onComplete() {
        
        if !self.latestProcessor.isSuccess() {
            // Reset the enrollment identifier.
            self.latestExternalDatabaseRefID = "";
        }
    }
    
    func getSessionToken(sessionTokenCallback: @escaping (String) -> ()) {
        
        let endpoint = Config.BaseURL + "/session-token"
        let request = NSMutableURLRequest(url: NSURL(string: endpoint)! as URL)
        request.httpMethod = "GET"
        // Required parameters to interact with the FaceTec Managed Testing API.
        request.addValue(Config.DeviceKeyIdentifier, forHTTPHeaderField: "X-Device-Key")
        request.addValue(FaceTec.sdk.createFaceTecAPIUserAgentString(""), forHTTPHeaderField: "User-Agent")
        request.addValue(FaceTec.sdk.createFaceTecAPIUserAgentString(""), forHTTPHeaderField: "X-User-Agent")
        
        let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue.main)
        let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
            // Ensure the data object is not nil otherwise callback with empty dictionary.
            guard let data = data else {
                print("Exception raised while attempting HTTPS call.")
                return
            }
            if let responseJSONObj = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! [String: AnyObject] {
                if((responseJSONObj["sessionToken"] as? String) != nil)
                {
                    
                    sessionTokenCallback(responseJSONObj["sessionToken"] as! String)
                    
                    return
                }
                else {
                    print("Exception raised while attempting HTTPS call.")
                }
            }
        })
        task.resume()
    }
    
    func getLatestExternalDatabaseRefID() -> String {
        return latestExternalDatabaseRefID;
    }
    
    func setLatestSessionResult(sessionResult: FaceTecSessionResult) {
        latestSessionResult = sessionResult
        
        print("The latestSessionResult is: ", latestSessionResult!)
    }
    @IBAction func finish(_ sender: Any) {
        AppConfig.shared.intentosCaptura = 1
        self.performSegue(withIdentifier: "unwindToRoot", sender: self)
    }
}

I am working on a custom iOS framework that integrates FaceTec SDK for biometric authentication, but I am facing issues with properly running the SDK within my framework. Below is the context and specific issues I need help with:

Context: I have created a framework that includes a UIViewController called FinishViewController. This controller is responsible for managing the FaceTec SDK session. Below is a simplified snippet of the code used to initialize and handle FaceTec SDK:

import UIKit
import FaceTecSDK
import LocalAuthentication

class FinishViewController: UIViewController, URLSessionDelegate{
    
    var utils: SampleAppUtilities!
    var latestProcessor: Processor!
    var latestExternalDatabaseRefID: String = ""
    var latestSessionResult: FaceTecSessionResult!
    var latestIDScanResult: FaceTecIDScanResult!
    

    
    @IBOutlet weak var elTelon: UIView!
    
    var isRealPerson = false
    var isNotSuccessful = false
    var isCancelled = false
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        utils = SampleAppUtilities(vc: self)
        // Initialize FaceTec SDK
        Config.initializeFaceTecSDKFromAutogeneratedConfig(completion: { initializationSuccessful in
            if(initializationSuccessful) {
                self.onFaceTecSDKInitializationSuccess()
            }
            else {
                self.onFaceTecSDKInitializationFailure()
            }
        })
        
        
        
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [self] in
            
            getSessionToken() { sessionToken in
                
                _ = LivenessCheckProcessor(sessionToken: sessionToken, fromViewController: self)
                .lvResponseDelegate = self
                //self.latestProcessor = AuthenticateProcessor(sessionToken: sessionToken, fromViewController: self)
            }
            
        }
        // Do any additional setup after loading the view.
    }
    
    func onFaceTecSDKInitializationFailure() {
        // Displays the FaceTec SDK Status to text field if init failed
        self.utils.displayStatus(statusString: "\(FaceTec.sdk.description(for: FaceTec.sdk.getStatus()))")
    }
    
    func onFaceTecSDKInitializationSuccess() {
        //        self.utils.enableButtons(shouldEnable: true)
        
        // Set your FaceTec Device SDK Customizations.
        ThemeHelpers.setAppTheme(theme: utils.currentTheme)
        
        // Set the sound files that are to be used for Vocal Guidance.
        
        
        
        // Set the strings to be used for group names, field names, and placeholder texts for the FaceTec ID Scan User OCR Confirmation Screen.
        SampleAppUtilities.setOCRLocalization()
        let currentTheme = Config.wasSDKConfiguredWithConfigWizard ? "Config Wizard Theme" : "FaceTec Theme"
        utils.handleThemeSelection(theme: currentTheme)
        self.utils.displayStatus(statusString: "Initialized Successfully.")
        
    }
    func onComplete() {
        
        if !self.latestProcessor.isSuccess() {
            // Reset the enrollment identifier.
            self.latestExternalDatabaseRefID = "";
        }
    }
    
    func getSessionToken(sessionTokenCallback: @escaping (String) -> ()) {
        
        let endpoint = Config.BaseURL + "/session-token"
        let request = NSMutableURLRequest(url: NSURL(string: endpoint)! as URL)
        request.httpMethod = "GET"
        // Required parameters to interact with the FaceTec Managed Testing API.
        request.addValue(Config.DeviceKeyIdentifier, forHTTPHeaderField: "X-Device-Key")
        request.addValue(FaceTec.sdk.createFaceTecAPIUserAgentString(""), forHTTPHeaderField: "User-Agent")
        request.addValue(FaceTec.sdk.createFaceTecAPIUserAgentString(""), forHTTPHeaderField: "X-User-Agent")
        
        let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue.main)
        let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
            // Ensure the data object is not nil otherwise callback with empty dictionary.
            guard let data = data else {
                print("Exception raised while attempting HTTPS call.")
                return
            }
            if let responseJSONObj = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! [String: AnyObject] {
                if((responseJSONObj["sessionToken"] as? String) != nil)
                {
                    
                    sessionTokenCallback(responseJSONObj["sessionToken"] as! String)
                    
                    return
                }
                else {
                    print("Exception raised while attempting HTTPS call.")
                }
            }
        })
        task.resume()
    }
    
    func getLatestExternalDatabaseRefID() -> String {
        return latestExternalDatabaseRefID;
    }
    
    func setLatestSessionResult(sessionResult: FaceTecSessionResult) {
        latestSessionResult = sessionResult
        
        print("The latestSessionResult is: ", latestSessionResult!)
    }
    @IBAction func finish(_ sender: Any) {
        AppConfig.shared.intentosCaptura = 1
        self.performSegue(withIdentifier: "unwindToRoot", sender: self)
    }
}

When I try to run the SDK, no initial compilation or runtime errors occur, but the SDK does not start as expected and there are no clear indications or errors in the console to help me diagnose the problem. I have checked the wiring of all the IBOutlet and IBAction, and everything seems to be in order.

Are there any special considerations I should be aware of when integrating FaceTec SDK into a framework rather than an application directly?

Are there any best practices for managing SDK initialization or view lifecycles within an iOS framework?

Has anyone faced similar issues when integrating third-party SDKs into custom frameworks and how did they resolve them?

Hello, @rockyto

Here’s a streamlined and comprehensive solution for integrating the FaceTec SDK into your custom iOS framework:

override func viewDidLoad() {
super.viewDidLoad()

utils = SampleAppUtilities(vc: self)
Config.initializeFaceTecSDKFromAutogeneratedConfig { initializationSuccessful in
    if initializationSuccessful {
        self.onFaceTecSDKInitializationSuccess()
    } else {
        self.onFaceTecSDKInitializationFailure()
    }
}

}

func onFaceTecSDKInitializationFailure() {
let status = FaceTec.sdk.description(for: FaceTec.sdk.getStatus())
self.utils.displayStatus(statusString: “Initialization Failed: (status)”)
// Add more detailed logs and error handling here
}

func onFaceTecSDKInitializationSuccess() {
ThemeHelpers.setAppTheme(theme: utils.currentTheme)
SampleAppUtilities.setOCRLocalization()
let currentTheme = Config.wasSDKConfiguredWithConfigWizard ? “Config Wizard Theme” : “FaceTec Theme”
utils.handleThemeSelection(theme: currentTheme)
self.utils.displayStatus(statusString: “Initialized Successfully.”)
}

Session Token Handling:

Fetch the session token properly and implement error handling to capture any issues during the HTTP call.

func getSessionToken(sessionTokenCallback: escaping (String) → ()) {
let endpoint = “(Config.BaseURL)/session-token”
var request = URLRequest(url: URL(string: endpoint)!)
request.httpMethod = “GET”
request.addValue(Config.DeviceKeyIdentifier, forHTTPHeaderField: “X-Device-Key”)
request.addValue(FaceTec.sdk.createFaceTecAPIUserAgentString(“”), forHTTPHeaderField: “User-Agent”)

let session = URLSession(configuration: .default, delegate: self, delegateQueue: .main)
let task = session.dataTask(with: request) { data, response, error in
    guard let data = data else {
        print("HTTPS call failed with error: \(String(describing: error))")
        return
    }
    if let responseJSON = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: AnyObject],
       let sessionToken = responseJSON["sessionToken"] as? String {
        sessionTokenCallback(sessionToken)
    } else {
        print("Failed to parse session token from response: \(String(describing: responseJSON))")
    }
}
task.resume()

}
Processor and Delegates:

Ensure all necessary delegate methods are implemented and correctly set. Handle any responses and errors appropriately.

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.getSessionToken { sessionToken in
let processor = LivenessCheckProcessor(sessionToken: sessionToken, fromViewController: self)
processor.lvResponseDelegate = self
self.latestProcessor = processor // Ensure latestProcessor is correctly assigned
}
}

UI Updates and Session Handling:

  • Update UI elements and handle sessions, ensuring proper feedback to the user and error handling.
    func setLatestSessionResult(sessionResult: FaceTecSessionResult) {
    latestSessionResult = sessionResult
    print(“The latestSessionResult is: (latestSessionResult!)”)
    }

IBAction func finish(_ sender: Any) {
AppConfig.shared.intentosCaptura = 1
self.performSegue(withIdentifier: “unwindToRoot”, sender: self)
}

func onComplete() {
if !self.latestProcessor.isSuccess() {
self.latestExternalDatabaseRefID = “”
}
}

By implementing these best practices and ensuring thorough error handling and logging, you should be able to integrate the FaceTec SDK smoothly within your custom iOS framework.

I hope this info is helpful to you.

Best Regard,
Melody Amundson