LogoLogo
Useful links
  • Home
  • Product guides
  • API
  • SDKs
  • Overview
  • First steps
  • ANDROID
    • Getting Started with the SDK
    • Standalone Modules
      • Document Detector
        • Release Notes
        • Current Version
        • Requirements
        • Gradle Dependencies
        • Gradle Source Code
        • Setting up the SDK
          • Setting properties
          • Capture Stages
          • Messages Settings
          • Customization
          • Security Settings
          • Detection Steps
          • Upload Mode
          • Advanced Settings
            • Proxy configuration
            • Preview configuration
        • Start Document Detection
        • Source Code
        • Google security form
        • Reduce SDKs size
        • SDKs response
        • References
        • FAQ
      • Face Liveness
        • Release Notes
        • Current Version
        • Requirements
        • Gradle Dependencies
        • Gradle Source Code
        • SDK Lifecycle
        • Building the SDK
        • Start Liveness Verification
        • Source Code
        • References
        • Advanced Features
        • FAQ
      • Face Authenticator
        • Release Notes
      • Smart Auth
        • Release Notes
        • Current Version
        • Requirements
        • Gradle Dependencies
        • Gradle Source Code
        • Permissions
        • SDK Lifecycle
        • Building the SDK
        • Start Smart Authentication
        • Source Code
        • References
        • FAQ
      • Face Liveness (deprecated)
        • Release Notes
  • iOS
    • Getting Started with the SDK
    • Standalone Modules
      • Document Detector
        • Release Notes
        • Current Version
        • Requirements
        • Installing the SDK
        • Setting up the SDK
          • Setting properties
          • Messages Settings
          • Customization
          • Detection Steps
          • Upload Mode
          • Advanced Settings
            • Proxy configuration
            • Preview configuration
        • Start Document Detection
        • References
        • FAQ
      • Face Liveness
        • Release Notes
        • Installation
        • Current Version
        • Requirements
        • SDK Lifecycle
        • Building the SDK
        • Start Liveness Verification
        • Source Code
        • References
        • FAQ
      • Face Authenticator
        • Release Notes
        • Installation
        • Current Version
        • Requirements
        • Building the SDK
        • Start the SDK
        • References
        • FAQ
      • Smart Auth
        • Release Notes
        • Installation
        • Current Version
        • Requirements
        • SDK Lifecycle
        • Building the SDK
        • Start Smart Authentication
        • Source Code
        • References
        • FAQ
      • Face Liveness (deprecated)
        • Release Notes
  • REACT NATIVE
    • Standalone Modules
      • Document Detector
        • Release Notes
        • Current Version
        • Requirements
        • Installation
        • Hooks
        • Start Document Verification
        • Source Code
        • TypeScript References
        • Customizing Style
        • FAQ
      • Face Liveness
        • Release Notes
        • Current Version
        • Requirements
        • Installation
        • Hooks
        • Start Liveness Verification
        • Source Code
        • TypeScript References
        • FAQ
      • Face Authenticator
        • Release Notes
        • Current Version
        • Requirements
        • Installation
        • Hooks
        • Start Authentication Verification
        • Source Code
        • TypeScript References
        • FAQ
      • Smart Auth
        • Getting started
        • Release notes
        • Using Native Modules
          • Requirements
          • Gradle Source Code
          • Podfile Source Code
          • Native Module Android
          • Native Module iOS
          • Import Native Modules
          • Source Code
          • TypeScript References
          • FAQ
        • Using Expo Modules
          • Requirements
          • Create Local Expo Module
          • Gradle Source Code
          • Podspec Source Code
          • Native Module Android
          • Native Module iOS
          • Import Expo Modules
          • Source Code
          • TypeScript References
          • FAQ
  • WEB (JAVASCRIPT)
    • Standalone Modules
      • Document Detector
        • Getting started
        • SDK builder options
          • Analytics
          • Appearance
          • Messages
        • SDK methods
        • Event listeners
        • Customization
        • Release notes
      • Face Liveness
        • Customization
        • Release notes
      • Face Authenticator
        • Customization
        • Release notes
      • Smart Auth
        • SDK errors
        • Customization
        • Release notes
LogoLogo

2025 © Caf. - All rights reserved

On this page
  • How to Create a Native Module in iOS
  • 1. Open the iOS Project in Xcode
  • 2. Create the Native Module
  • 3. Create the CafSmartAuthBridgeSettings.swift File
  • 4. Register the Native Module
  • 5. Create the Bridging Header for Swift and Objective-C
  1. REACT NATIVE
  2. Standalone Modules
  3. Smart Auth
  4. Using Native Modules

Native Module iOS

Last updated 11 days ago

How to Create a Native Module in iOS

This detailed guide explains how to create a native module for the iOS platform within a React Native application. The process follows the step-by-step instructions from the .

1. Open the iOS Project in Xcode

First, open the iOS project of your React Native application in Xcode. You can find the iOS project in the folder: YourApp/ios/your-app-name.xcworkspace.

Using Xcode helps in quickly identifying issues, such as syntax errors, and provides powerful tools for iOS development.

2. Create the Native Module

Create a file named CafSmartAuthBridgeModule.swift in the directory ios/. This file will contain the class that implements the native module.

Key Functions of the CafSmartAuthBridgeModule Class

  • requiresMainQueueSetup: Indicates whether the module needs to be set up on the main queue. Returns true.

  • supportedEvents: Returns the list of events that the module can emit to React Native.

  • build: Creates and configures an instance of the CafSmartAuthSdk using the provided parameters.

  • emitEvent: Emits events from the native side to React Native.

  • setupListener: Sets up a listener to monitor the status of authentication operations.

  • startSmartAuth: A method exposed to React Native to initiate smart authentication.

Example Implementation of the CafSmartAuthBridgeModule.swift File

import Foundation
import React
import CafSmartAuth

private struct CafSmartAuthBridgeConstants { 
    static let cafSmartAuthSuccessEvent: String = "CafSmartAuth_Success"
    static let cafSmartAuthPendingEvent: String = "CafSmartAuth_Pending"
    static let cafSmartAuthErrorEvent: String = "CafSmartAuth_Error"
    static let cafSmartAuthCancelEvent: String = "CafSmartAuth_Cancel"
    static let cafSmartAuthLoadingEvent: String = "CafSmartAuth_Loading"
    static let cafSmartAuthLoadedEvent: String = "CafSmartAuth_Loaded"
    
    static let isAuthorized: String = "isAuthorized"
    static let attestation: String = "attestation"
    static let errorMessage: String = "message"

    static let cafFilterNaturalIndex: Int = 0

    static let backgroundColorHex: String = "#FFFFFF"
    static let textColorHex: String = "#FF000000"
    static let primaryColorHex: String = "#004AF7"
    static let boxBackgroundColorHex: String = "#0A004AF7"
}

@objc(CafSmartAuthBridgeModule)
class CafSmartAuthBridgeModule: RCTEventEmitter {
  private var smartAuth: CafSmartAuthSdk?
  
  @objc
  override static func requiresMainQueueSetup() -> Bool {
    return true
  }
  
  override func supportedEvents() -> [String]! {
    return [
      CafSmartAuthBridgeConstants.cafSmartAuthSuccessEvent,
      CafSmartAuthBridgeConstants.cafSmartAuthPendingEvent,
      CafSmartAuthBridgeConstants.cafSmartAuthErrorEvent,
      CafSmartAuthBridgeConstants.cafSmartAuthCancelEvent,
      CafSmartAuthBridgeConstants.cafSmartAuthLoadingEvent,
      CafSmartAuthBridgeConstants.cafSmartAuthLoadedEvent
    ]
  }
  
  private func build(
    mfaToken: String,
    faceAuthToken: String,
    settings: CafSmartAuthBridgeSettingsModel?
  ) -> CafSmartAuthSdk {
    let builder = CafSmartAuthSdk.CafBuilder(mobileToken: mfaToken)
    
    if let stage = settings?.stage, let cafStage = CAFStage(rawValue: stage) {
      _ = builder.setStage(cafStage)
    }

    if let emailUrl = settings?.emailUrl {
      _ = builder.setEmailURL(URL(string: emailUrl))
    }
    
    if let phoneUrl = settings?.phoneUrl {
      _ = builder.setPhoneURL(URL(string: phoneUrl))
    }
    
    let filter: CafFilterStyle = {
      if let faceSettings = settings?.faceAuthenticationSettings, faceSettings.filter == CafSmartAuthBridgeConstants.cafFilterNaturalIndex {
        return .natural
      }
      return .lineDrawing
    }()
    
    _ = builder.setLivenessSettings(
      CafFaceLivenessSettings(
        faceLivenessToken: faceAuthToken,
        useLoadingScreen: settings?.faceAuthenticationSettings?.loadingScreen ?? false,
        filter: filter
      )
    )

    let lightTheme = settings?.theme?.lightTheme
    let darkTheme = settings?.theme?.darkTheme
    
    _ = builder.setThemeConfigurator(
      CafThemeConfigurator(
        lightTheme: parseTheme(theme: lightTheme),
        darkTheme: parseTheme(theme: darkTheme)
      )
    )
    
    return builder.build()
  }

  private func parseTheme(theme: CafSmartAuthBridgeTheme?) -> CafTheme {
    if theme != nil {
      return CafTheme(
        backgroundColor: theme?.backgroundColor ?? CafSmartAuthBridgeConstants.backgroundColorHex,
        textColor: theme?.textColor ?? CafSmartAuthBridgeConstants.textColorHex,
        linkColor: theme?.linkColor ?? CafSmartAuthBridgeConstants.primaryColorHex,
        boxBorderColor: theme?.boxBorderColor ?? CafSmartAuthBridgeConstants.primaryColorHex,
        boxFilledBorderColor: theme?.boxFilledBorderColor ?? CafSmartAuthBridgeConstants.primaryColorHex,
        boxBackgroundColor: theme?.boxBackgroundColor ?? CafSmartAuthBridgeConstants.boxBackgroundColorHex,
        boxFilledBackgroundColor: theme?.boxFilledBackgroundColor ?? CafSmartAuthBridgeConstants.boxBackgroundColorHex,
        boxTextColor: theme?.boxTextColor ?? CafSmartAuthBridgeConstants.primaryColorHex,
        progressColor:  theme?.progressColor ?? CafSmartAuthBridgeConstants.primaryColorHex
      )
    } else {
      return CafTheme(
        backgroundColor: CafSmartAuthBridgeConstants.backgroundColorHex,
        textColor: CafSmartAuthBridgeConstants.textColorHex,
        linkColor: CafSmartAuthBridgeConstants.primaryColorHex,
        boxBorderColor: CafSmartAuthBridgeConstants.primaryColorHex,
        boxFilledBorderColor: CafSmartAuthBridgeConstants.primaryColorHex,
        boxBackgroundColor: CafSmartAuthBridgeConstants.boxBackgroundColorHex,
        boxFilledBackgroundColor: CafSmartAuthBridgeConstants.boxBackgroundColorHex,
        boxTextColor: CafSmartAuthBridgeConstants.primaryColorHex,
        progressColor: CafSmartAuthBridgeConstants.primaryColorHex
      )
    }
  }
  
  private func emitEvent(name: String, data: Any) {
    self.sendEvent(withName: name, body: data)
  }
  
  private func setupListener() -> CafVerifyPolicyListener {
    return { result in
      switch result {
      case .onSuccess(let response):
        self.emitEvent(
          name: CafSmartAuthBridgeConstants.cafSmartAuthSuccessEvent,
          data: [
            CafSmartAuthBridgeConstants.isAuthorized: response.isAuthorized,
            CafSmartAuthBridgeConstants.attestation: response.attestation
          ]
        )
        self.smartAuth = nil
        
      case .onPending(let response):
        self.emitEvent(
          name: CafSmartAuthBridgeConstants.cafSmartAuthPendingEvent,
          data: [
            CafSmartAuthBridgeConstants.isAuthorized: response.isAuthorized,
            CafSmartAuthBridgeConstants.attestation: response.attestation
          ]
        )
        
      case .onError(let error):
        self.emitEvent(
          name: CafSmartAuthBridgeConstants.cafSmartAuthErrorEvent,
          data: [CafSmartAuthBridgeConstants.errorMessage: error.error.localizedDescription]
        )
        self.smartAuth = nil
        
      case .onCanceled(_):
        self.emitEvent(
          name: CafSmartAuthBridgeConstants.cafSmartAuthCancelEvent,
          data: true
        )
        self.smartAuth = nil
        
      case .onLoading:
        self.emitEvent(name: CafSmartAuthBridgeConstants.cafSmartAuthLoadingEvent, data: true)
        
      case .onLoaded:
        self.emitEvent(name: CafSmartAuthBridgeConstants.cafSmartAuthLoadedEvent, data: true)
      }
    }
  }
  
  
  @objc(startSmartAuth:livenessToken:personId:policyId:settings:)
  func startSmartAuth(mfaToken: String, faceAuthToken: String, personId: String, policyId: String, settings: String?) {
    DispatchQueue.main.async {
      self.smartAuth = self.build(
        mfaToken: mfaToken, faceAuthToken: faceAuthToken, settings: CafSmartAuthBridgeSettings().parseJson(settings: settings)
      )
      
      self.smartAuth?.verifyPolicy(personID: personId, policyId: policyId, listener: self.setupListener())
    }
  }
}

3. Create the CafSmartAuthBridgeSettings.swift File

This file will handle the interpretation of data sent from React Native to the native module.

Example Implementation:

import Foundation
import CafSmartAuth

internal struct CafFaceAuthenticationSettingsModel: Decodable {
  let loadingScreen: Bool?
  let filter: Int?
}

internal struct CafSmartAuthBridgeTheme: Decodable {
  let backgroundColor: String?
  let textColor: String?
  let progressColor: String?
  let linkColor: String?
  let boxBackgroundColor: String?
  let boxFilledBackgroundColor: String?
  let boxBorderColor: String?
  let boxFilledBorderColor: String?
  let boxTextColor: String?
}

internal struct CafSmartAuthBridgeThemeConfigurator: Decodable {
  let lightTheme: CafSmartAuthBridgeTheme?
  let darkTheme: CafSmartAuthBridgeTheme?
}


internal struct CafSmartAuthBridgeSettingsModel: Decodable {
  let stage: Int?
  let faceAuthenticationSettings: CafFaceAuthenticationSettingsModel?
  let emailUrl: String?
  let phoneUrl: String?
  let theme: CafSmartAuthBridgeThemeConfigurator?
}

internal class CafSmartAuthBridgeSettings {
  internal func parseJson(settings: String?) -> CafSmartAuthBridgeSettingsModel? {
    guard let data = settings?.data(using: .utf8) else {
      return nil
    }
    
    do {
      let decoder = JSONDecoder()
      let parsedSettings = try decoder.decode(CafSmartAuthBridgeSettingsModel.self, from: data)
      
      return parsedSettings
    } catch {
      return nil
    }
  }
}

4. Register the Native Module

Create the main header and implementation files for the custom native module. Create a new file named CafSmartAuthBridge.h.

Example Implementation:

#import <React/RCTBridgeModule.h>

@interface CafSmartAuthBridgeModule : NSObject <RCTBridgeModule>

@end

To make the native module recognizable by React Native, create the file CafSmartAuthBridge.mm in the same directory:

Example Implementation:

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

@interface RCT_EXTERN_MODULE(CafSmartAuthBridgeModule, RCTEventEmitter)
RCT_EXTERN_METHOD(startSmartAuth:(NSString *)mfaToken livenessToken:(NSString *)livenessToken personId:(NSString *)personId policyId:(NSString *)policyId settings:(NSString *)settings)
@end

5. Create the Bridging Header for Swift and Objective-C

Whenever you mix Swift and Objective-C in an iOS project, a bridging header file is required. This file allows Swift to access functionalities implemented in Objective-C, including React Native APIs.

In the same directory as the Swift file, create the file CafSmartAuthBridge-Bridging-Header.h.

Example Implementation of the Bridging Header File

#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

Configuration Steps

  1. Ensure the CafSmartAuthBridge-Bridging-Header.h file is included in the Objective-C Bridging Header field in Build Settings (Build Settings > Swift Compiler - General > Objective-C Bridging Header).

  2. Provide the relative path to the file, e.g.,

    YourApp/ios/YourApp/CafSmartAuthBridge-Bridging-Header.h
official documentation