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.
1. Open the iOS Project in Xcode
You can include this in your package.json under the scripts section:
"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
importExpoModulesCoreimportCafSmartAuthprivatestructCafSmartAuthBridgeConstants {staticlet moduleName: String="CafSmartAuthBridgeModule"staticlet startSmartAuth: String="startSmartAuth"staticlet cafSmartAuthSuccessEvent: String="CafSmartAuth_Success"staticlet cafSmartAuthPendingEvent: String="CafSmartAuth_Pending"staticlet cafSmartAuthErrorEvent: String="CafSmartAuth_Error"staticlet cafSmartAuthCancelEvent: String="CafSmartAuth_Cancel"staticlet cafSmartAuthLoadingEvent: String="CafSmartAuth_Loading"staticlet cafSmartAuthLoadedEvent: String="CafSmartAuth_Loaded"staticlet isAuthorized: String="isAuthorized"staticlet attestation: String="attestation"staticlet errorMessage: String="message"staticlet isCancelled: String="isCancelled"staticlet isLoading: String="isLoading"staticlet isLoaded: String="isLoaded"staticlet cafFilterNaturalIndex: Int=0}publicclassCafSmartAuthBridgeModule: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.privatevar smartAuth: CafSmartAuthSdk?publicfuncdefinition() -> 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?) ->Voidin 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()) } } }privatefuncbuild(mfaToken: String,faceAuthToken: String,settings: CafSmartAuthBridgeSettingsModel? ) -> CafSmartAuthSdk {let builder = CafSmartAuthSdk.CafBuilder(mobileToken: mfaToken)iflet stage = settings?.stage, let cafStage =CAFStage(rawValue: stage) {_= builder.setStage(cafStage) }let filter: CafFilterStyle = {iflet faceSettings = settings?.faceAuthenticationSettings, faceSettings.filter == CafSmartAuthBridgeConstants.cafFilterNaturalIndex {return .natural }return .lineDrawing }()_= builder.setLivenessSettings( CafFaceLivenessSettings( faceLivenessToken: faceAuthToken, useLoadingScreen: settings?.faceAuthenticationSettings?.loadingScreen ??false, filter: filter))return builder.build() }privatefuncsetupListener() -> CafVerifyPolicyListener {return { result inswitch result {case .onSuccess(let response): self.sendEvent(CafSmartAuthBridgeConstants.cafSmartAuthSuccessEvent, [ CafSmartAuthBridgeConstants.isAuthorized: response.isAuthorized, CafSmartAuthBridgeConstants.attestation: response.attestation ]) self.smartAuth =nilcase .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.localizedDescription ]) self.smartAuth =nilcase .onCanceled(_): self.sendEvent(CafSmartAuthBridgeConstants.cafSmartAuthCancelEvent, [ CafSmartAuthBridgeConstants.isCancelled:true ]) self.smartAuth =nilcase .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.