> For the complete documentation index, see [llms.txt](https://docs.caf.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.caf.io/caf-sdk/react-native/standalone-modules/cafsmartauth/expo-modules/native-modules-ios.md).

# Native Module iOS

## 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 [official documentation](https://reactnative.dev/docs/0.73/native-modules-ios).

### 1. Open the iOS Project in Xcode

You can include this in your package.json under the scripts section:

```json
"scripts": {
    "open:ios": "xed ios"
},
```

This script ensures that the Expo module opens correctly in Xcode.

### 2. Create the Native Module

Create a file named `CafSmartAuthBridgeModule.swift` in the directory `modules/caf-smart-auth-react-native/ios/`. This file will contain the class that implements the native module.

#### Key Functions of the `CafSmartAuthBridgeModule` Class

* **`build`**: Creates and configures an instance of the `CafSmartAuthSdk` using the provided parameters.
* **`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

```swift
import ExpoModulesCore
import CafSmartAuth

private struct CafSmartAuthBridgeConstants {
    static let moduleName: String = "CafSmartAuthBridgeModule"
    static let startSmartAuth: String = "startSmartAuth"
    
    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 isCancelled: String = "isCancelled"
    static let isLoading: String = "isLoading"
    static let isLoaded: String = "isLoaded"

    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"
}

public class CafSmartAuthBridgeModule: Module {
    // Each module class must implement the definition function. The definition consists of components
    // that describes the module's functionality and behavior.
    // See https://docs.expo.dev/modules/module-api for more details about available components.
    
    private var smartAuth: CafSmartAuthSdk?
    
    public func definition() -> ModuleDefinition {
        // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
        // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
        // The module will be accessible from `requireNativeModule('CafSmartAuthBridgeModule')` in JavaScript.
        Name(CafSmartAuthBridgeConstants.moduleName)
        
        // Defines event names that the module can send to JavaScript.
        Events(
            CafSmartAuthBridgeConstants.cafSmartAuthSuccessEvent,
            CafSmartAuthBridgeConstants.cafSmartAuthPendingEvent,
            CafSmartAuthBridgeConstants.cafSmartAuthErrorEvent,
            CafSmartAuthBridgeConstants.cafSmartAuthCancelEvent,
            CafSmartAuthBridgeConstants.cafSmartAuthLoadingEvent,
            CafSmartAuthBridgeConstants.cafSmartAuthLoadedEvent
        )
        
        // Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
        Function(CafSmartAuthBridgeConstants.startSmartAuth) { (mfaToken: String, faceAuthToken: String, personId: String, policyId: String, settings: String?) -> Void in
            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())
            }
        }
    }
    
    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 setupListener() -> CafVerifyPolicyListener {
        return { result in
            switch result {
            case .onSuccess(let response):
                self.sendEvent(CafSmartAuthBridgeConstants.cafSmartAuthSuccessEvent, [
                    CafSmartAuthBridgeConstants.isAuthorized: response.isAuthorized,
                    CafSmartAuthBridgeConstants.attestation: response.attestation
                ])
                self.smartAuth = nil
                
            case .onPending(let response):
                self.sendEvent(CafSmartAuthBridgeConstants.cafSmartAuthPendingEvent, [
                    CafSmartAuthBridgeConstants.isAuthorized: response.isAuthorized,
                    CafSmartAuthBridgeConstants.attestation: response.attestation
                ])
                
            case .onError(let error):
                self.sendEvent(CafSmartAuthBridgeConstants.cafSmartAuthErrorEvent, [
                    CafSmartAuthBridgeConstants.errorMessage: error.error.localizedDescription
                ])
                self.smartAuth = nil
                
            case .onCanceled(_):
                self.sendEvent(CafSmartAuthBridgeConstants.cafSmartAuthCancelEvent, [
                    CafSmartAuthBridgeConstants.isCancelled: true
                ])
                self.smartAuth = nil
                
            case .onLoading:
                self.sendEvent(CafSmartAuthBridgeConstants.cafSmartAuthLoadingEvent, [
                    CafSmartAuthBridgeConstants.isLoading: true
                ])
                
            case .onLoaded:
                self.sendEvent(CafSmartAuthBridgeConstants.cafSmartAuthLoadedEvent, [
                    CafSmartAuthBridgeConstants.isLoaded: true
                ])
            }
        }
    }
}
```

### 3. Create the `CafSmartAuthBridgeSettings.swift` File

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

#### Example Implementation:

```swift
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
    }
  }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.caf.io/caf-sdk/react-native/standalone-modules/cafsmartauth/expo-modules/native-modules-ios.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
