package co.ab180.airbridge.reactnative import android.app.Application import android.content.Context import android.content.Intent import android.util.Log import android.view.View import co.ab180.airbridge.Airbridge import co.ab180.airbridge.AirbridgeOptionBuilder import co.ab180.airbridge.reactnative.common.AirbridgeJSON import co.ab180.airbridge.reactnative.common.AirbridgeLifecycleIntegration import co.ab180.airbridge.reactnative.extension.consume import co.ab180.airbridge.reactnative.extension.isConsumed import co.ab180.airbridge.reactnative.extension.LibraryInfoJSON import co.ab180.airbridge.reactnative.extension.setAirbridgeJSON import co.ab180.airbridge.reactnative.extension.toMap import co.ab180.airbridge.reactnative.module.AttributionInteractor import co.ab180.airbridge.reactnative.module.DeeplinkInteractor import co.ab180.airbridge.reactnative.module.EventInteractor import co.ab180.airbridge.reactnative.module.FetchInteractor import co.ab180.airbridge.reactnative.module.PlacementInteractor import co.ab180.airbridge.reactnative.module.RegisterInteractor import co.ab180.airbridge.reactnative.module.SwitchInteractor import co.ab180.airbridge.reactnative.module.WebInterfaceInteractor import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ReactShadowNode import com.facebook.react.uimanager.ViewManager class AirbridgeReactNative : ReactPackage { companion object { private var airbridgeJSON: Map? = null private var lifecycleIntegration: AirbridgeLifecycleIntegration? = null private var isHandleAirbridgeDeeplinkOnly: Boolean = false private var subWrapperSDKDevelopmentPlatform: String? = null private var subWrapperSDKAttributes: Map? = null /** * Initialize Airbridge SDK. * * You should call this method on MainApplication#onCreate. * @param app Context from MainApplication#onCreate * @param name App Name in English * @param token App Token */ @JvmStatic fun initializeSDK( app: Application, name: String, token: String, ) { airbridgeJSON = AirbridgeJSON.loaderFunc(app)?.toMap() setExtraOptions(airbridgeJSON) Airbridge.initializeSDK( app, AirbridgeOptionBuilder(name, token) .setAirbridgeJSON(airbridgeJSON) .setSDKDevelopmentPlatform(getSDKDevelopmentPlatform()) .setSDKAttributes(getSDKAttributes(app)) .setSDKWrapperOption(getSDKWrapperOption()) .setOnAttributionReceived { AttributionInteractor.onAttributionReceived(it) } .setLifecycleIntegration { lifecycleIntegration?.getDataString(it) } .build() ) Airbridge.handleDeferredDeeplink( onSuccess = { it?.also { DeeplinkInteractor.onDeeplinkReceived(it) } }, onFailure = { Log.d("AirbridgeReactNative", "Failure on Airbridge.handleDeferredDeeplink: error={${it.localizedMessage}}") } ) } /** * Tracks app behavior through deeplink. * * You should call this method on MainActivity#onResume. * @param intent intent from MainActivity#onResume */ @JvmStatic fun trackDeeplink(intent: Intent) { val handled = Airbridge.handleDeeplink( intent = intent, onSuccess = { DeeplinkInteractor.onDeeplinkReceived(it) }, onFailure = { Log.d("AirbridgeReactNative", "Failure on Airbridge.handleDeeplink: error={${it.localizedMessage}}") } ) if (handled || isHandleAirbridgeDeeplinkOnly) { return } if (intent.isConsumed()) { Log.d("AirbridgeReactNative", "intent was already consumed on AirbridgeReactNative.trackDeeplink") return } intent.consume() intent.data?.also { DeeplinkInteractor.onDeeplinkReceived(it) } } /** * Use this method to fetch the correct deep links in exceptional circumstances. * * When your app is opened by tapping a push notification, * third-party libraries (like `Braze`) can provide a customized mechanism to handle deep links. * This mechanism may differ from the default Android OS deeplinking process. * * @param lifecycleIntegration An instance of [AirbridgeLifecycleIntegration] that defines the customized mechanism for handling deeplinks. */ @JvmStatic fun setLifecycleIntegration(lifecycleIntegration: AirbridgeLifecycleIntegration) { AirbridgeReactNative.lifecycleIntegration = lifecycleIntegration } private fun setExtraOptions(airbridgeJSON: Map?) { val json = airbridgeJSON ?: return (json["isHandleAirbridgeDeeplinkOnly"] as? Boolean)?.also { isHandleAirbridgeDeeplinkOnly = it } } private fun getSDKDevelopmentPlatform(): String { return subWrapperSDKDevelopmentPlatform ?: "react_native" } private fun getSDKAttributes(context: Context): Map { return LibraryInfoJSON.load(context).let { if (it == null) { mutableMapOf() } else { mutableMapOf( "wrapperName" to it.getString("name"), "wrapperVersion" to it.getString("version") ) } }.apply { subWrapperSDKAttributes?.let { putAll(it) } } } private fun getSDKWrapperOption(): Map { return mapOf( "isHandleAirbridgeDeeplinkOnly" to isHandleAirbridgeDeeplinkOnly ) } @JvmStatic private fun setSubWrapperSDK( developmentPlatform: String, sdkAttributes: Map ) { subWrapperSDKDevelopmentPlatform = developmentPlatform subWrapperSDKAttributes = sdkAttributes } } override fun createNativeModules( reactContext: ReactApplicationContext ): List = listOf( EventInteractor(reactContext), DeeplinkInteractor(reactContext), RegisterInteractor(reactContext), PlacementInteractor(reactContext), AttributionInteractor(reactContext), FetchInteractor(reactContext), SwitchInteractor(reactContext), WebInterfaceInteractor(reactContext) ) override fun createViewManagers( reactContext: ReactApplicationContext ): List>> = emptyList() }