> 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/caf-sdk-pt-br/react-native/standalone-modules/cafsmartauth/native-modules/native-module-android.md).

# Módulo nativo Android

## Como criar um Módulo Nativo no Android

Este guia detalhado explica como criar um módulo nativo para a plataforma Android dentro de um aplicativo React Native. O processo segue as instruções passo a passo de [documentação oficial](https://reactnative.dev/docs/0.73/native-modules-android).

### 1. Abra o projeto Android no Android Studio

Primeiro, abra o projeto Android do seu aplicativo React Native no Android Studio. Você pode encontrar o projeto Android na pasta: `YourApp/android`.

Usar o Android Studio ajuda a identificar rapidamente problemas, como erros de sintaxe, e oferece ferramentas poderosas para o desenvolvimento Android.

### 2. Crie o módulo nativo

Crie um arquivo chamado `CafSmartAuthBridgeModule.kt` no diretório `android/app/src/main/java/com/your-app-name/`. Este arquivo conterá a classe que implementa o módulo nativo.

#### Principais funções da `CafSmartAuthBridgeModule` Classe

* **`getName`**: Esta função retorna o nome do módulo nativo, que será usado para acessá-lo em JavaScript dentro do React Native. O nome deve ser exclusivo para evitar conflitos com outros módulos.
* **`build`**: A `build` função é responsável por configurar e instanciar o `CafSmartAuth` objeto usando os parâmetros fornecidos. Essa função aplica várias configurações, como definir etapas e autenticação facial, para preparar o SDK para uso.
* **`emitEvent`**: Permite enviar eventos do lado nativo para o JavaScript. Os eventos podem incluir sucesso, erros ou outros status relevantes.
* **`setupListener`**: Configura um listener para monitorar o status das operações de verificação, como sucesso, pendente, erro, cancelamento e outros.
* **`requestPermission`**: Solicita as permissões necessárias, como permissões de localização, para o funcionamento adequado do SDK.
* **`startSmartAuth`**: Exposta ao JavaScript, esta função inicia o processo de autenticação inteligente usando os parâmetros recebidos.
* **`requestLocationPermissions`**: Exposta ao JavaScript, permite que o aplicativo solicite ao usuário permissões de localização.

#### Exemplo de implementação do `CafSmartAuthBridgeModule.kt` Arquivo

```kotlin
class CafSmartAuthBridgeModule(private val reactContext: ReactApplicationContext) :
    ReactContextBaseJavaModule(reactContext) {

    @Nonnull
    override fun getName(): String {
        return CAF_SMART_AUTH_BRIDGE_MODULE
    }

    private fun build(mfaToken: String, faceAuthToken: String, settings: String): CafSmartAuth {
        val smartAuthSettings = CafSmartAuthBridgeSettings(settings = settings)

        return CafSmartAuth.CafBuilder(mfaToken, reactContext).apply {
            setSdkPlatform(CafSdkPlatform.REACT_NATIVE)
            smartAuthSettings.cafStage?.let { setStage(it) }
            smartAuthSettings.emailUrl?.let { setEmailUrl(it) }
            smartAuthSettings.phoneUrl?.let { setPhoneUrl(it) }
            setFaceAuthenticatorSettings(
                CafFaceAuthenticatorSettings(
                    faceAuthToken,
                    smartAuthSettings.faceAuthenticatorSettings?.loadingScreen,
                    smartAuthSettings.faceAuthenticatorSettings?.enableScreenCapture,
                    smartAuthSettings.faceAuthenticatorSettings?.filter
                )
            )
            setThemeConfigurator(
                CafThemeConfigurator(
                    lightTheme = smartAuthSettings.theme?.lightTheme ?: CafTheme(),
                    darkTheme = smartAuthSettings.theme?.darkTheme ?: CafTheme()
                )
            )
        }.build()
    }

    private fun emitEvent(eventName: String, params: Any) {
        reactApplicationContext
            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
            .emit(eventName, params)
    }

    private fun setupListener() = object : CafVerifyPolicyListener {
        override fun onSuccess(
            isAuthorized: Boolean,
            attemptId: String?,
            attestation: String?
        ) {
            emitEvent(eventName = CAF_SMART_AUTH_SUCCESS_EVENT, params = WritableNativeMap().apply {
                putBoolean(CAF_WRITABLE_MAP_IS_AUTHORIZED, isAuthorized)
                putString(CAF_WRITABLE_MAP_ATTEMPT_ID, attemptId)
                putString(CAF_WRITABLE_MAP_ATTESTATION, attestation)
            })
        }

        override fun onPending(isAuthorized: Boolean, attestation: String) {
            emitEvent(eventName = CAF_SMART_AUTH_PENDING_EVENT, params = WritableNativeMap().apply {
                putBoolean(CAF_WRITABLE_MAP_IS_AUTHORIZED, isAuthorized)
                putString(CAF_WRITABLE_MAP_ATTESTATION, attestation)
            })
        }

        override fun onError(failure: CafFailure, message: String?) {
            emitEvent(eventName = CAF_SMART_AUTH_ERROR_EVENT, params = WritableNativeMap().apply {
                putString(CAF_WRITABLE_MAP_ERROR_MESSAGE, failure.message)
            })
        }

        override fun onCancel() {
            emitEvent(eventName = CAF_SMART_AUTH_CANCEL_EVENT, params = true)
        }

        override fun onLoading() {
            emitEvent(eventName = CAF_SMART_AUTH_LOADING_EVENT, params = true)
        }

        override fun onLoaded() {
            emitEvent(eventName = CAF_SMART_AUTH_LOADED_EVENT, params = true)
        }
    }

    private fun requestPermission(permission: String, activity: Activity) {
        if (ContextCompat.checkSelfPermission(
                reactContext,
                permission
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(activity, arrayOf(permission), REQUEST_CODE)
        }
    }

    @ReactMethod
    fun startSmartAuth(
        mfaToken: String,
        faceAuthToken: String,
        personId: String,
        policyId: String,
        jsonString: String
    ) {
        Handler(Looper.getMainLooper()).post {
            val smartAuth =
                build(mfaToken = mfaToken, faceAuthToken = faceAuthToken, settings = jsonString)
            smartAuth.verifyPolicy(personId, policyId, setupListener())
        }
    }

    @ReactMethod
    fun requestLocationPermissions(promise: Promise) {
        val activity = currentActivity ?: return

        Handler(Looper.getMainLooper()).post {
            try {
                requestPermission(
                    permission = Manifest.permission.ACCESS_FINE_LOCATION,
                    activity = activity
                )
                requestPermission(
                    permission = Manifest.permission.ACCESS_COARSE_LOCATION,
                    activity = activity
                )
                promise.resolve(true)
            } catch (e: Exception) {
                promise.reject(
                    PERMISSION_ERROR,
                    "$PERMISSION_ERROR_DESCRIPTION ${e.message}"
                )
            }
        }
    }

    companion object {
        private const val REQUEST_CODE = 1234

        private const val CAF_SMART_AUTH_BRIDGE_MODULE = "CafSmartAuthBridgeModule"

        private const val CAF_SMART_AUTH_SUCCESS_EVENT = "CafSmartAuth_Success"
        private const val CAF_SMART_AUTH_PENDING_EVENT = "CafSmartAuth_Pending"
        private const val CAF_SMART_AUTH_ERROR_EVENT = "CafSmartAuth_Error"
        private const val CAF_SMART_AUTH_CANCEL_EVENT = "CafSmartAuth_Cancel"
        private const val CAF_SMART_AUTH_LOADING_EVENT = "CafSmartAuth_Loading"
        private const val CAF_SMART_AUTH_LOADED_EVENT = "CafSmartAuth_Loaded"

        private const val CAF_WRITABLE_MAP_IS_AUTHORIZED = "isAuthorized"
        private const val CAF_WRITABLE_MAP_ATTEMPT_ID = "attemptId"
        private const val CAF_WRITABLE_MAP_ATTESTATION = "attestation"

        private const val CAF_WRITABLE_MAP_ERROR_MESSAGE = "message"

        private const val PERMISSION_ERROR = "PERMISSION_ERROR"
        private const val PERMISSION_ERROR_DESCRIPTION = "Erro ao verificar as permissões de localização:"
    }
}
```

### 3. Crie o `CafSmartAuthBridgeSettings.kt` Arquivo

Este arquivo lidará com a interpretação dos dados enviados do React Native para o módulo nativo.

#### Exemplo de implementação:

```kotlin
internal data class CafFaceAuthenticationSettingsModel(
    val loadingScreen: Boolean?,
    val enableScreenCapture: Boolean?,
    val filter: CafFilterStyle?
)

internal data class CafSmartAuthBridgeTheme(
    val lightTheme: CafTheme,
    val darkTheme: CafTheme
)

internal class CafSmartAuthBridgeSettings(settings: String) : Serializable {
    val cafStage: CafStage?
    val emailUrl: String?
    val phoneUrl: String?
    val faceAuthenticatorSettings: CafFaceAuthenticationSettingsModel?
    val theme: CafSmartAuthBridgeTheme?

    init {
        val jsonObject = JSONObject(settings)

        cafStage = jsonObject.takeIf {
            it.has(STAGE)
        }?.let {
            CafStage.entries[it.getInt(STAGE)]
        }

        emailUrl = jsonObject.takeIf {
            it.has(EMAIL)
        }?.getString(EMAIL)

        phoneUrl = jsonObject.takeIf {
            it.has(PHONE)
        }?.getString(PHONE)

        faceAuthenticatorSettings = jsonObject.takeIf {
            it.has(FACE_AUTHENTICATION_SETTINGS)
        }?.let {
            val faceAuthenticatorSettings = it.getJSONObject(FACE_AUTHENTICATION_SETTINGS)

            val filterStyle = faceAuthenticatorSettings.takeIf { settings ->
                settings.has(FILTER)
            }?.let {
                CafFilterStyle.entries[faceAuthenticatorSettings.getInt(FILTER)]
            }

            CafFaceAuthenticationSettingsModel(
                faceAuthenticatorSettings.optBoolean(LOADING_SCREEN),
                faceAuthenticatorSettings.optBoolean(ENABLE_SCREEN_CAPTURE),
                filterStyle ?: CafFilterStyle.LINE_DRAWING
            )
        }

        theme = jsonObject.takeIf {
            it.has(THEME)
        }?.let {
            val theme = it.getJSONObject(THEME)

            val lightTheme = theme.optJSONObject(LIGHT_THEME)
            val darkTheme = theme.optJSONObject(DARK_THEME)

            CafSmartAuthBridgeTheme(
                lightTheme = parseTheme(lightTheme),
                darkTheme = parseTheme(darkTheme)
            )
        }
    }

    private fun parseTheme(json: JSONObject?): CafTheme {
        return json?.let {
            CafTheme(
                backgroundColor = json.optString(BACKGROUND_COLOR).takeIf { it.isNotEmpty() }
                    ?: BACKGROUND_COLOR_HEX,
                textColor = json.optString(TEXT_COLOR).takeIf { it.isNotEmpty() }
                    ?: TEXT_COLOR_HEX,
                progressColor = json.optString(PROGRESS_COLOR).takeIf { it.isNotEmpty() }
                    ?: PRIMARY_COLOR_HEX,
                linkColor = json.optString(LINK_COLOR).takeIf { it.isNotEmpty() }
                    ?: PRIMARY_COLOR_HEX,
                boxBackgroundColor = json.optString(BOX_BACKGROUND_COLOR).takeIf { it.isNotEmpty() }
                    ?: BOX_BACKGROUND_COLOR_HEX,
                boxBorderColor = json.optString(BOX_BORDER_COLOR).takeIf { it.isNotEmpty() }
                    ?: PRIMARY_COLOR_HEX,
                boxTextColor = json.optString(BOX_TEXT_COLOR).takeIf { it.isNotEmpty() }
                    ?: PRIMARY_COLOR_HEX
            )
        } ?: CafTheme(
            backgroundColor = BACKGROUND_COLOR_HEX,
            textColor = TEXT_COLOR_HEX,
            progressColor = PRIMARY_COLOR_HEX,
            linkColor = PRIMARY_COLOR_HEX,
            boxBackgroundColor = BOX_BACKGROUND_COLOR_HEX,
            boxBorderColor = PRIMARY_COLOR_HEX,
            boxTextColor = PRIMARY_COLOR_HEX
        )
    }

    private companion object {
        const val STAGE = "stage"
        const val EMAIL = "emailUrl"
        const val PHONE = "phoneUrl"
        const val FACE_AUTHENTICATION_SETTINGS = "faceAuthenticationSettings"
        const val LOADING_SCREEN = "loadingScreen"
        const val ENABLE_SCREEN_CAPTURE = "enableScreenCapture"
        const val FILTER = "filter"
        const val THEME = "theme"
        const val LIGHT_THEME = "lightTheme"
        const val DARK_THEME = "darkTheme"
        const val BACKGROUND_COLOR = "backgroundColor"
        const val TEXT_COLOR = "textColor"
        const val PROGRESS_COLOR = "progressColor"
        const val LINK_COLOR = "linkColor"
        const val BOX_BACKGROUND_COLOR = "boxBackgroundColor"
        const val BOX_BORDER_COLOR = "boxBorderColor"
        const val BOX_TEXT_COLOR = "boxTextColor"

        const val BACKGROUND_COLOR_HEX = "#FFFFFF"
        const val TEXT_COLOR_HEX = "#FF000000"
        const val PRIMARY_COLOR_HEX = "#004AF7"
        const val BOX_BACKGROUND_COLOR_HEX = "#0A004AF7"
    }
}
```

### 4. Registre o Módulo Nativo

Para tornar o módulo nativo reconhecível pelo React Native, crie um arquivo chamado `CafPackage.kt` no mesmo diretório:

#### Exemplo de implementação:

```kotlin
class CafPackage : ReactPackage {
    override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
        return listOf(CafSmartAuthBridgeModule(reactContext))
    }

    override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
        return emptyList()
    }
}
```

No `MainApplication.kt` arquivo, adicione o `CafPackage` módulo dentro do `getPackages` método:

#### Exemplo de implementação:

```kotlin
override fun getPackages(): List<ReactPackage> =
    PackageList(this).packages.apply {
        add(CafPackage())
    }
```

Com isso, seu módulo nativo está configurado e pronto para ser usado no React Native.


---

# 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/caf-sdk-pt-br/react-native/standalone-modules/cafsmartauth/native-modules/native-module-android.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.
