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

Understanding the Issue

It seems like the FaceTec SDK might not be initializing or functioning correctly within your framework. This could be due to a few reasons:

1. Framework Configuration:

  • Build Settings: Ensure that your framework’s build settings are configured correctly, especially for the FaceTec SDK’s dependencies and linking.
  • Target Membership: Double-check that the FaceTec SDK is included in the target membership of your framework.

2. SDK Initialization ADPRun and Lifecycle:

  • Initialization Timing: Ensure that the SDK is initialized after the view controller has loaded and before any attempts to use its features.
  • View Lifecycle and SDK Interactions: Be mindful of how the SDK interacts with the view controller’s lifecycle, especially when the view controller is presented or dismissed.

3. Framework Structure and Dependency Management:

  • Framework Design: Consider how the FaceTec SDK is integrated into your framework’s structure. Is it a direct dependency or a nested dependency?
  • Dependency Management: Ensure that all necessary dependencies are properly managed and linked to your framework.

Debugging Tips:

  1. Logging: Add detailed logging to track the SDK’s initialization process and any errors that might occur.
  2. Breakpoints: Set breakpoints in your code to step through the execution and inspect variables.
  3. FaceTec SDK Documentation: Refer to the official FaceTec SDK documentation for specific guidance and troubleshooting tips.
  4. Community Forums: Check the FaceTec SDK community forums or contact their support for assistance.
  5. Simplified Setup: Try setting up a minimal example project to isolate the issue and identify potential conflicts.

Best Practices for Integrating Third-Party SDKs:

  • Clear Documentation: Refer to the SDK’s official documentation for specific instructions and guidelines.
  • Dependency Management: Use a dependency manager like CocoaPods or Swift Package Manager to manage dependencies effectively.
  • Modular Design: Keep your framework’s code modular and well-organized.
  • Thorough Testing: Test your framework in different scenarios to ensure it works as expected.
  • Community Support: Engage with the SDK’s community for help and troubleshooting tips.

By following these guidelines and troubleshooting tips, you should be able to successfully integrate the FaceTec SDK into your framework. If you encounter further issues, please provide more specific details about the errors or unexpected behavior you’re observing.

Thank you for share this kind of ifnormation…Marion County Property Appraiser