Updated on 2026-08-14
This commit is contained in:
parent
d17d9e35bf
commit
e97cb41fdb
18 changed files with 468 additions and 228 deletions
|
|
@ -14,7 +14,7 @@ import com.tangem.domain.common.LogConfig
|
||||||
import com.tangem.network.common.MoshiConverter
|
import com.tangem.network.common.MoshiConverter
|
||||||
import com.tangem.tap.common.AndroidAssetReader
|
import com.tangem.tap.common.AndroidAssetReader
|
||||||
import com.tangem.tap.common.AssetReader
|
import com.tangem.tap.common.AssetReader
|
||||||
import com.tangem.tap.common.analytics.AnalyticsEventHandlerBuilder
|
import com.tangem.tap.common.analytics.GlobalAnalyticsEventHandlerBuilder
|
||||||
import com.tangem.tap.common.feedback.AdditionalFeedbackInfo
|
import com.tangem.tap.common.feedback.AdditionalFeedbackInfo
|
||||||
import com.tangem.tap.common.feedback.FeedbackManager
|
import com.tangem.tap.common.feedback.FeedbackManager
|
||||||
import com.tangem.tap.common.images.createCoilImageLoader
|
import com.tangem.tap.common.images.createCoilImageLoader
|
||||||
|
|
@ -100,7 +100,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initAnalytics(application: Application, config: Config) {
|
private fun initAnalytics(application: Application, config: Config) {
|
||||||
val globalAnalyticsHandler = AnalyticsEventHandlerBuilder(
|
val globalAnalyticsHandler = GlobalAnalyticsEventHandlerBuilder(
|
||||||
application = application,
|
application = application,
|
||||||
config = config,
|
config = config,
|
||||||
isDebug = BuildConfig.DEBUG,
|
isDebug = BuildConfig.DEBUG,
|
||||||
|
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
package com.tangem.tap.common.analytics
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import com.tangem.common.json.MoshiJsonConverter
|
|
||||||
import com.tangem.domain.common.AnalyticsHandlersLogConfig
|
|
||||||
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
|
|
||||||
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler
|
|
||||||
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
|
|
||||||
import com.tangem.tap.domain.configurable.config.Config
|
|
||||||
|
|
||||||
/**
|
|
||||||
[REDACTED_AUTHOR]
|
|
||||||
*/
|
|
||||||
class AnalyticsEventHandlerBuilder(
|
|
||||||
private val application: Application,
|
|
||||||
private val config: Config,
|
|
||||||
private val isDebug: Boolean,
|
|
||||||
private val logConfig: AnalyticsHandlersLogConfig,
|
|
||||||
private val jsonConverter: MoshiJsonConverter,
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val analyticHandlers = mutableListOf<AnalyticsEventHandler>()
|
|
||||||
|
|
||||||
fun build(): GlobalAnalyticsEventHandler {
|
|
||||||
return GlobalAnalyticsHandler(analyticHandlers.toList())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun default(): GlobalAnalyticsEventHandler {
|
|
||||||
addFirebaseAnalytics()
|
|
||||||
addAppsFlyer()
|
|
||||||
addAmplitude()
|
|
||||||
|
|
||||||
return GlobalAnalyticsHandler(analyticHandlers.toList())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addFirebaseAnalytics(): AnalyticsEventHandlerBuilder {
|
|
||||||
if (isDebug) {
|
|
||||||
addEventLogger(logConfig.firebase, FirebaseAnalyticsHandler::class.java.simpleName)
|
|
||||||
} else {
|
|
||||||
analyticHandlers.add(FirebaseAnalyticsHandler())
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addAppsFlyer(): AnalyticsEventHandlerBuilder {
|
|
||||||
if (isDebug) {
|
|
||||||
addEventLogger(logConfig.appsFlyer, AppsFlyerAnalyticsHandler::class.java.simpleName)
|
|
||||||
} else {
|
|
||||||
analyticHandlers.add(AppsFlyerAnalyticsHandler(application, config.appsFlyerDevKey))
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addAmplitude(): AnalyticsEventHandlerBuilder {
|
|
||||||
if (isDebug) {
|
|
||||||
addEventLogger(logConfig.amplitude, AmplitudeAnalyticsHandler::class.java.simpleName)
|
|
||||||
} else {
|
|
||||||
analyticHandlers.add(AmplitudeAnalyticsHandler(application, config.amplitudeApiKey))
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addEventLogger(logsEnabled: Boolean, name: String) {
|
|
||||||
// if (logsEnabled) analyticHandlers.add(AnalyticsLogsPrinter(name, jsonConverter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.tangem.tap.common.analytics
|
||||||
|
|
||||||
|
import com.tangem.common.json.MoshiJsonConverter
|
||||||
|
import com.tangem.tap.common.analytics.api.ErrorEventLogger
|
||||||
|
import com.tangem.tap.common.analytics.api.EventLogger
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class AnalyticsEventsLogger(
|
||||||
|
private val name: String,
|
||||||
|
private val jsonConverter: MoshiJsonConverter,
|
||||||
|
) : EventLogger, ErrorEventLogger {
|
||||||
|
|
||||||
|
override fun logEvent(event: String, params: Map<String, String>) {
|
||||||
|
Timber.d(jsonConverter.prettyPrint(PrintEventModel(name, event, params)))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logErrorEvent(error: Throwable, params: Map<String, String>) {
|
||||||
|
Timber.e(error, jsonConverter.prettyPrint(PrintEventModel(name, "error", params)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class PrintEventModel(
|
||||||
|
val client: String,
|
||||||
|
val event: String,
|
||||||
|
val params: Map<String, String>,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
package com.tangem.tap.common.analytics
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
package com.tangem.tap.common.analytics
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import com.tangem.common.json.MoshiJsonConverter
|
||||||
|
import com.tangem.domain.common.AnalyticsHandlersLogConfig
|
||||||
|
import com.tangem.tap.common.analytics.api.AnalyticsEventHandler
|
||||||
|
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
|
||||||
|
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeClient
|
||||||
|
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeLogClient
|
||||||
|
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler
|
||||||
|
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerClient
|
||||||
|
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerLogClient
|
||||||
|
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
|
||||||
|
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseClient
|
||||||
|
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseLogClient
|
||||||
|
import com.tangem.tap.domain.configurable.config.Config
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
class GlobalAnalyticsEventHandlerBuilder(
|
||||||
|
val application: Application,
|
||||||
|
val config: Config,
|
||||||
|
val isDebug: Boolean,
|
||||||
|
val logConfig: AnalyticsHandlersLogConfig,
|
||||||
|
val jsonConverter: MoshiJsonConverter,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val analyticHandlers = mutableListOf<AnalyticsEventHandler>()
|
||||||
|
|
||||||
|
fun build(): GlobalAnalyticsEventHandler {
|
||||||
|
return GlobalAnalyticsHandler(analyticHandlers.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun default(): GlobalAnalyticsEventHandler {
|
||||||
|
addFirebaseAnalytics()
|
||||||
|
addAppsFlyer()
|
||||||
|
addAmplitude()
|
||||||
|
|
||||||
|
return GlobalAnalyticsHandler(analyticHandlers.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addFirebaseAnalytics(): GlobalAnalyticsEventHandlerBuilder {
|
||||||
|
if (isDebug) {
|
||||||
|
if (logConfig.firebase) FirebaseLogClient(createLogger("FirebaseAnalyticsHandler")) else null
|
||||||
|
} else {
|
||||||
|
FirebaseClient()
|
||||||
|
}?.let {
|
||||||
|
analyticHandlers.add(FirebaseAnalyticsHandler(it))
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addAppsFlyer(): GlobalAnalyticsEventHandlerBuilder {
|
||||||
|
if (isDebug) {
|
||||||
|
if (logConfig.appsFlyer) AppsFlyerLogClient(createLogger("AppsFlyerAnalyticsHandler")) else null
|
||||||
|
} else {
|
||||||
|
AppsFlyerClient(application, config.appsFlyerDevKey)
|
||||||
|
}?.let {
|
||||||
|
analyticHandlers.add(AppsFlyerAnalyticsHandler(it))
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addAmplitude(): GlobalAnalyticsEventHandlerBuilder {
|
||||||
|
if (isDebug) {
|
||||||
|
if (logConfig.firebase) AmplitudeLogClient(createLogger("AmplitudeAnalyticsHandler")) else null
|
||||||
|
} else {
|
||||||
|
AmplitudeClient(application, config.amplitudeApiKey)
|
||||||
|
}?.let {
|
||||||
|
analyticHandlers.add(AmplitudeAnalyticsHandler(it))
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createLogger(name: String): AnalyticsEventsLogger {
|
||||||
|
return AnalyticsEventsLogger(name, jsonConverter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,12 +4,19 @@ import com.shopify.buy3.Storefront
|
||||||
import com.tangem.blockchain.common.BlockchainError
|
import com.tangem.blockchain.common.BlockchainError
|
||||||
import com.tangem.common.card.Card
|
import com.tangem.common.card.Card
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
|
import com.tangem.tap.common.analytics.api.AnalyticsEventHandler
|
||||||
|
import com.tangem.tap.common.analytics.api.BlockchainSdkErrorEventHandler
|
||||||
|
import com.tangem.tap.common.analytics.api.CardSdkErrorEventHandler
|
||||||
|
import com.tangem.tap.common.analytics.api.ErrorEventHandler
|
||||||
|
import com.tangem.tap.common.analytics.api.ErrorEventLogger
|
||||||
|
import com.tangem.tap.common.analytics.api.SdkErrorEventHandler
|
||||||
|
import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler
|
||||||
import com.tangem.tap.common.extensions.filterNotNull
|
import com.tangem.tap.common.extensions.filterNotNull
|
||||||
|
|
||||||
interface GlobalAnalyticsEventHandler : AnalyticsEventHandler,
|
interface GlobalAnalyticsEventHandler : AnalyticsEventHandler,
|
||||||
ShopifyOrderEventHandler,
|
|
||||||
ErrorEventHandler,
|
ErrorEventHandler,
|
||||||
SdkErrorEventHandler
|
SdkErrorEventHandler,
|
||||||
|
ShopifyOrderEventHandler
|
||||||
|
|
||||||
class GlobalAnalyticsHandler(
|
class GlobalAnalyticsHandler(
|
||||||
private val analyticsHandlers: List<AnalyticsEventHandler>,
|
private val analyticsHandlers: List<AnalyticsEventHandler>,
|
||||||
|
|
@ -28,15 +35,9 @@ class GlobalAnalyticsHandler(
|
||||||
analyticsHandlers.forEach { it.handleAnalyticsEvent(event, params, card, blockchain) }
|
analyticsHandlers.forEach { it.handleAnalyticsEvent(event, params, card, blockchain) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleShopifyOrderEvent(order: Storefront.Order) {
|
|
||||||
analyticsHandlers.filterIsInstance<ShopifyOrderEventHandler>().forEach {
|
|
||||||
it.handleShopifyOrderEvent(order)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleErrorEvent(error: Throwable, params: Map<String, String>) {
|
override fun handleErrorEvent(error: Throwable, params: Map<String, String>) {
|
||||||
analyticsHandlers.filterIsInstance<ErrorEventHandler>().forEach {
|
analyticsHandlers.filterIsInstance<ErrorEventLogger>().forEach {
|
||||||
it.handleErrorEvent(error, params)
|
it.logErrorEvent(error, params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,6 +62,12 @@ class GlobalAnalyticsHandler(
|
||||||
it.handleBlockchainSdkErrorEvent(error, action, params, card)
|
it.handleBlockchainSdkErrorEvent(error, action, params, card)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun handleShopifyOrderEvent(order: Storefront.Order) {
|
||||||
|
analyticsHandlers.filterIsInstance<ShopifyOrderEventHandler>().forEach {
|
||||||
|
it.handleShopifyOrderEvent(order)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun GlobalAnalyticsEventHandler.logWcEvent(event: Analytics.WcAnalyticsEvent) {
|
fun GlobalAnalyticsEventHandler.logWcEvent(event: Analytics.WcAnalyticsEvent) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.tangem.tap.common.analytics.api
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
interface EventLogger {
|
||||||
|
fun logEvent(
|
||||||
|
event: String,
|
||||||
|
params: Map<String, String> = emptyMap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ErrorEventLogger {
|
||||||
|
fun logErrorEvent(
|
||||||
|
error: Throwable,
|
||||||
|
params: Map<String, String> = emptyMap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
package com.tangem.tap.common.analytics
|
package com.tangem.tap.common.analytics.api
|
||||||
|
|
||||||
import com.shopify.buy3.Storefront
|
import com.shopify.buy3.Storefront
|
||||||
import com.tangem.blockchain.common.BlockchainError
|
import com.tangem.blockchain.common.BlockchainError
|
||||||
import com.tangem.common.card.Card
|
import com.tangem.common.card.Card
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
|
import com.tangem.tap.common.analytics.Analytics
|
||||||
|
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||||
|
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||||
import com.tangem.tap.common.extensions.filterNotNull
|
import com.tangem.tap.common.extensions.filterNotNull
|
||||||
|
|
||||||
interface EventHandler {
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
interface AnalyticsEventHandler {
|
||||||
fun handleEvent(
|
fun handleEvent(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = emptyMap(),
|
params: Map<String, String> = emptyMap(),
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
interface AnalyticsEventHandler : EventHandler {
|
|
||||||
fun handleAnalyticsEvent(
|
fun handleAnalyticsEvent(
|
||||||
event: AnalyticsEvent,
|
event: AnalyticsEvent,
|
||||||
params: Map<String, String> = emptyMap(),
|
params: Map<String, String> = emptyMap(),
|
||||||
|
|
@ -25,17 +29,11 @@ interface AnalyticsEventHandler : EventHandler {
|
||||||
card: Card?,
|
card: Card?,
|
||||||
blockchain: String? = null,
|
blockchain: String? = null,
|
||||||
params: Map<String, String> = emptyMap(),
|
params: Map<String, String> = emptyMap(),
|
||||||
): Map<String, String> {
|
): Map<String, String> = mapOf(
|
||||||
return mapOf(
|
AnalyticsParam.FIRMWARE.param to card?.firmwareVersion?.stringValue,
|
||||||
AnalyticsParam.FIRMWARE.param to card?.firmwareVersion?.stringValue,
|
AnalyticsParam.BATCH_ID.param to card?.batchId,
|
||||||
AnalyticsParam.BATCH_ID.param to card?.batchId,
|
AnalyticsParam.BLOCKCHAIN.param to blockchain,
|
||||||
AnalyticsParam.BLOCKCHAIN.param to blockchain,
|
).filterNotNull() + params
|
||||||
).filterNotNull() + params
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ShopifyOrderEventHandler {
|
|
||||||
fun handleShopifyOrderEvent(order: Storefront.Order)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ErrorEventHandler {
|
interface ErrorEventHandler {
|
||||||
|
|
@ -64,3 +62,7 @@ interface BlockchainSdkErrorEventHandler {
|
||||||
card: Card? = null,
|
card: Card? = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ShopifyOrderEventHandler {
|
||||||
|
fun handleShopifyOrderEvent(order: Storefront.Order)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
package com.tangem.tap.common.analytics.converters
|
||||||
|
|
||||||
|
import com.tangem.blockchain.common.BlockchainError
|
||||||
|
import com.tangem.blockchain.common.BlockchainSdkError
|
||||||
|
import com.tangem.common.Converter
|
||||||
|
import com.tangem.common.core.TangemSdkError
|
||||||
|
import com.tangem.tap.common.analytics.Analytics
|
||||||
|
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||||
|
import com.tangem.tap.common.analytics.TangemSdk
|
||||||
|
import com.tangem.tap.features.demo.DemoTransactionSender
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
internal data class ErrorEvent(
|
||||||
|
val throwable: Throwable,
|
||||||
|
val params: Map<String, String>,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal class CardSdkErrorConverter : Converter<CardSdkErrorConverter.Model, ErrorEvent?> {
|
||||||
|
|
||||||
|
override fun convert(value: Model): ErrorEvent? {
|
||||||
|
if (value.error is TangemSdkError.UserCancelled) return null
|
||||||
|
|
||||||
|
val mutableParams = value.params.convertToParamValue().toMutableMap().apply {
|
||||||
|
putAll(value.cardParams)
|
||||||
|
}
|
||||||
|
mutableParams[AnalyticsParam.ACTION.param] = value.action.key
|
||||||
|
mutableParams[AnalyticsParam.ERROR_CODE.param] = value.error.code.toString()
|
||||||
|
mutableParams[AnalyticsParam.ERROR_DESCRIPTION.param] = value.error.javaClass.simpleName
|
||||||
|
mutableParams[AnalyticsParam.ERROR_KEY.param] = "TangemSdkError"
|
||||||
|
|
||||||
|
return ErrorEvent(TangemSdk.map(value.error), mutableParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal data class Model(
|
||||||
|
val error: TangemSdkError,
|
||||||
|
val action: Analytics.ActionToLog,
|
||||||
|
val params: Map<AnalyticsParam, String>,
|
||||||
|
val cardParams: Map<String, String>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class BlockchainSdkErrorConverter(
|
||||||
|
private val cardSdkErrorConverter: CardSdkErrorConverter,
|
||||||
|
) : Converter<BlockchainSdkErrorConverter.Model, ErrorEvent?> {
|
||||||
|
|
||||||
|
override fun convert(value: Model): ErrorEvent? {
|
||||||
|
val error = (value.error as? BlockchainSdkError) ?: return null
|
||||||
|
|
||||||
|
if (error is BlockchainSdkError.WrappedTangemError) {
|
||||||
|
val tangemSdkError = (error.tangemError as? TangemSdkError) ?: return null
|
||||||
|
|
||||||
|
val cardSdkModel = CardSdkErrorConverter.Model(
|
||||||
|
error = tangemSdkError,
|
||||||
|
action = value.action,
|
||||||
|
params = value.params,
|
||||||
|
cardParams = value.cardParams,
|
||||||
|
)
|
||||||
|
return cardSdkErrorConverter.convert(cardSdkModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.customMessage.contains(DemoTransactionSender.ID)) return null
|
||||||
|
|
||||||
|
val mutableParams = value.params.convertToParamValue().toMutableMap()
|
||||||
|
mutableParams[AnalyticsParam.ACTION.param] = value.action.key
|
||||||
|
mutableParams[AnalyticsParam.ERROR_CODE.param] = error.code.toString()
|
||||||
|
mutableParams[AnalyticsParam.ERROR_DESCRIPTION.param] = "${error.javaClass.simpleName}: ${error.customMessage}"
|
||||||
|
mutableParams[AnalyticsParam.ERROR_KEY.param] = "BlockchainSdkError"
|
||||||
|
|
||||||
|
return ErrorEvent(value.error, mutableParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Model(
|
||||||
|
val error: BlockchainError,
|
||||||
|
val action: Analytics.ActionToLog,
|
||||||
|
val params: Map<AnalyticsParam, String>,
|
||||||
|
val cardParams: Map<String, String>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Map<AnalyticsParam, String>.convertToParamValue(): Map<String, String> {
|
||||||
|
return mutableMapOf<String, String>().also { newMap ->
|
||||||
|
this.forEach {
|
||||||
|
newMap[it.key.param] = it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,28 +1,15 @@
|
||||||
package com.tangem.tap.common.analytics.handlers.amplitude
|
package com.tangem.tap.common.analytics.handlers.amplitude
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import com.amplitude.api.Amplitude
|
|
||||||
import com.amplitude.api.AmplitudeClient
|
|
||||||
import com.tangem.common.Converter
|
|
||||||
import com.tangem.common.card.Card
|
import com.tangem.common.card.Card
|
||||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||||
import com.tangem.tap.common.analytics.AnalyticsEventHandler
|
import com.tangem.tap.common.analytics.api.AnalyticsEventHandler
|
||||||
import org.json.JSONObject
|
|
||||||
|
|
||||||
class AmplitudeAnalyticsHandler(
|
class AmplitudeAnalyticsHandler(
|
||||||
application: Application,
|
private val client: AmplitudeAnalyticsClient,
|
||||||
key: String,
|
|
||||||
) : AnalyticsEventHandler {
|
) : AnalyticsEventHandler {
|
||||||
|
|
||||||
private val client: AmplitudeClient = Amplitude.getInstance()
|
|
||||||
|
|
||||||
init {
|
|
||||||
client.initialize(application, key)
|
|
||||||
client.enableForegroundTracking(application)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleEvent(event: String, params: Map<String, String>) {
|
override fun handleEvent(event: String, params: Map<String, String>) {
|
||||||
client.logEvent(event, ParamsJSONObjectConverter().convert(params))
|
client.logEvent(event, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAnalyticsEvent(
|
override fun handleAnalyticsEvent(
|
||||||
|
|
@ -33,11 +20,4 @@ class AmplitudeAnalyticsHandler(
|
||||||
) {
|
) {
|
||||||
handleEvent(event.event, prepareParams(card, blockchain, params))
|
handleEvent(event.event, prepareParams(card, blockchain, params))
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParamsJSONObjectConverter : Converter<Map<String, String>, JSONObject> {
|
|
||||||
override fun convert(value: Map<String, String>): JSONObject = JSONObject().apply {
|
|
||||||
value.forEach { this.put(it.key, it.value) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.tangem.tap.common.analytics.handlers.amplitude
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import com.amplitude.api.Amplitude
|
||||||
|
import com.amplitude.api.AmplitudeClient
|
||||||
|
import com.tangem.common.Converter
|
||||||
|
import com.tangem.tap.common.analytics.api.EventLogger
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
interface AmplitudeAnalyticsClient : EventLogger
|
||||||
|
|
||||||
|
internal class AmplitudeClient(
|
||||||
|
application: Application,
|
||||||
|
key: String,
|
||||||
|
) : AmplitudeAnalyticsClient {
|
||||||
|
|
||||||
|
private val client: AmplitudeClient = Amplitude.getInstance()
|
||||||
|
|
||||||
|
init {
|
||||||
|
client.initialize(application, key)
|
||||||
|
client.enableForegroundTracking(application)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logEvent(event: String, params: Map<String, String>) {
|
||||||
|
client.logEvent(event, ParamsToJSONObjectConverter().convert(params))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ParamsToJSONObjectConverter : Converter<Map<String, String>, JSONObject> {
|
||||||
|
override fun convert(value: Map<String, String>): JSONObject = JSONObject().apply {
|
||||||
|
value.forEach { this.put(it.key, it.value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.tangem.tap.common.analytics.handlers.amplitude
|
||||||
|
|
||||||
|
import com.tangem.tap.common.analytics.AnalyticsEventsLogger
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
internal class AmplitudeLogClient(
|
||||||
|
private val logger: AnalyticsEventsLogger,
|
||||||
|
) : AmplitudeAnalyticsClient {
|
||||||
|
|
||||||
|
override fun logEvent(event: String, params: Map<String, String>) {
|
||||||
|
logger.logEvent(event, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,30 +1,20 @@
|
||||||
package com.tangem.tap.common.analytics.handlers.appsFlyer
|
package com.tangem.tap.common.analytics.handlers.appsFlyer
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import com.appsflyer.AFInAppEventParameterName
|
import com.appsflyer.AFInAppEventParameterName
|
||||||
import com.appsflyer.AFInAppEventType
|
import com.appsflyer.AFInAppEventType
|
||||||
import com.appsflyer.AppsFlyerLib
|
|
||||||
import com.shopify.buy3.Storefront
|
import com.shopify.buy3.Storefront
|
||||||
import com.tangem.common.Converter
|
import com.tangem.common.Converter
|
||||||
import com.tangem.common.card.Card
|
import com.tangem.common.card.Card
|
||||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||||
import com.tangem.tap.common.analytics.AnalyticsEventHandler
|
import com.tangem.tap.common.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.tap.common.analytics.ShopifyOrderEventHandler
|
import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler
|
||||||
|
|
||||||
class AppsFlyerAnalyticsHandler(
|
class AppsFlyerAnalyticsHandler(
|
||||||
private val context: Context,
|
private val client: AppsFlyerAnalyticsClient,
|
||||||
key: String,
|
|
||||||
) : AnalyticsEventHandler, ShopifyOrderEventHandler {
|
) : AnalyticsEventHandler, ShopifyOrderEventHandler {
|
||||||
|
|
||||||
private val appsFlyerLib: AppsFlyerLib = AppsFlyerLib.getInstance()
|
|
||||||
|
|
||||||
init {
|
|
||||||
appsFlyerLib.init(key, null, context)
|
|
||||||
appsFlyerLib.start(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleEvent(event: String, params: Map<String, String>) {
|
override fun handleEvent(event: String, params: Map<String, String>) {
|
||||||
appsFlyerLib.logEvent(context, event, params)
|
client.logEvent(event, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAnalyticsEvent(
|
override fun handleAnalyticsEvent(
|
||||||
|
|
@ -43,25 +33,26 @@ class AppsFlyerAnalyticsHandler(
|
||||||
companion object {
|
companion object {
|
||||||
const val ORDER_EVENT = AFInAppEventType.PURCHASE
|
const val ORDER_EVENT = AFInAppEventType.PURCHASE
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class OrderToParamsConverter : Converter<Storefront.Order, Map<String, String>> {
|
private class OrderToParamsConverter : Converter<Storefront.Order, Map<String, String>> {
|
||||||
override fun convert(value: Storefront.Order): Map<String, String> {
|
|
||||||
val sku = value.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
|
|
||||||
|
|
||||||
val discountCode =
|
override fun convert(value: Storefront.Order): Map<String, String> {
|
||||||
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
val sku = value.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
|
||||||
|
|
||||||
val discountParams = if (discountCode != null) {
|
val discountCode =
|
||||||
mapOf(AFInAppEventParameterName.COUPON_CODE to discountCode)
|
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
||||||
} else {
|
|
||||||
mapOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapOf(
|
val discountParams = if (discountCode != null) {
|
||||||
AFInAppEventParameterName.CONTENT_ID to sku,
|
mapOf(AFInAppEventParameterName.COUPON_CODE to discountCode)
|
||||||
AFInAppEventParameterName.REVENUE to value.totalPriceV2.amount,
|
} else {
|
||||||
AFInAppEventParameterName.CURRENCY to value.currencyCode.name,
|
mapOf()
|
||||||
) + discountParams
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return mapOf(
|
||||||
|
AFInAppEventParameterName.CONTENT_ID to sku,
|
||||||
|
AFInAppEventParameterName.REVENUE to value.totalPriceV2.amount,
|
||||||
|
AFInAppEventParameterName.CURRENCY to value.currencyCode.name,
|
||||||
|
) + discountParams
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.tangem.tap.common.analytics.handlers.appsFlyer
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.appsflyer.AppsFlyerLib
|
||||||
|
import com.tangem.tap.common.analytics.api.EventLogger
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
interface AppsFlyerAnalyticsClient : EventLogger
|
||||||
|
|
||||||
|
internal class AppsFlyerClient(
|
||||||
|
private val context: Context,
|
||||||
|
key: String,
|
||||||
|
) : AppsFlyerAnalyticsClient {
|
||||||
|
|
||||||
|
private val appsFlyerLib: AppsFlyerLib = AppsFlyerLib.getInstance()
|
||||||
|
|
||||||
|
init {
|
||||||
|
appsFlyerLib.init(key, null, context)
|
||||||
|
appsFlyerLib.start(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logEvent(event: String, params: Map<String, String>) {
|
||||||
|
appsFlyerLib.logEvent(context, event, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.tangem.tap.common.analytics.handlers.appsFlyer
|
||||||
|
|
||||||
|
import com.tangem.tap.common.analytics.AnalyticsEventsLogger
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
internal class AppsFlyerLogClient(
|
||||||
|
private val logger: AnalyticsEventsLogger,
|
||||||
|
) : AppsFlyerAnalyticsClient {
|
||||||
|
|
||||||
|
override fun logEvent(event: String, params: Map<String, String>) {
|
||||||
|
logger.logEvent(event, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,35 +1,27 @@
|
||||||
package com.tangem.tap.common.analytics.handlers.firebase
|
package com.tangem.tap.common.analytics.handlers.firebase
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
import com.google.firebase.analytics.ktx.analytics
|
|
||||||
import com.google.firebase.crashlytics.ktx.crashlytics
|
|
||||||
import com.google.firebase.ktx.Firebase
|
|
||||||
import com.shopify.buy3.Storefront
|
import com.shopify.buy3.Storefront
|
||||||
import com.tangem.blockchain.common.BlockchainError
|
import com.tangem.blockchain.common.BlockchainError
|
||||||
import com.tangem.blockchain.common.BlockchainSdkError
|
|
||||||
import com.tangem.common.Converter
|
import com.tangem.common.Converter
|
||||||
import com.tangem.common.card.Card
|
import com.tangem.common.card.Card
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.tap.common.analytics.Analytics
|
import com.tangem.tap.common.analytics.Analytics
|
||||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||||
import com.tangem.tap.common.analytics.AnalyticsEventHandler
|
|
||||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||||
import com.tangem.tap.common.analytics.ErrorEventHandler
|
import com.tangem.tap.common.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.tap.common.analytics.SdkErrorEventHandler
|
import com.tangem.tap.common.analytics.api.ErrorEventHandler
|
||||||
import com.tangem.tap.common.analytics.ShopifyOrderEventHandler
|
import com.tangem.tap.common.analytics.api.SdkErrorEventHandler
|
||||||
import com.tangem.tap.common.analytics.TangemSdk
|
import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler
|
||||||
import com.tangem.tap.features.demo.DemoTransactionSender
|
import com.tangem.tap.common.analytics.converters.BlockchainSdkErrorConverter
|
||||||
|
import com.tangem.tap.common.analytics.converters.CardSdkErrorConverter
|
||||||
|
|
||||||
class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler, ErrorEventHandler,
|
class FirebaseAnalyticsHandler(
|
||||||
SdkErrorEventHandler {
|
private val client: FirebaseAnalyticsClient,
|
||||||
|
) : AnalyticsEventHandler, ErrorEventHandler, SdkErrorEventHandler, ShopifyOrderEventHandler {
|
||||||
private val fbAnalytics = Firebase.analytics
|
|
||||||
private val fbCrashlytics = Firebase.crashlytics
|
|
||||||
|
|
||||||
override fun handleEvent(event: String, params: Map<String, String>) {
|
override fun handleEvent(event: String, params: Map<String, String>) {
|
||||||
fbAnalytics.logEvent(event, params.toBundle())
|
client.logEvent(event, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAnalyticsEvent(
|
override fun handleAnalyticsEvent(
|
||||||
|
|
@ -38,16 +30,11 @@ class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler
|
||||||
card: Card?,
|
card: Card?,
|
||||||
blockchain: String?,
|
blockchain: String?,
|
||||||
) {
|
) {
|
||||||
handleEvent(event.event, prepareParams(card, blockchain, params))
|
handleEvent(event.name, prepareParams(card, blockchain, params))
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleShopifyOrderEvent(order: Storefront.Order) {
|
|
||||||
handleEvent(ORDER_EVENT, OrderToParamsConverter().convert(order))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleErrorEvent(error: Throwable, params: Map<String, String>) {
|
override fun handleErrorEvent(error: Throwable, params: Map<String, String>) {
|
||||||
params.forEach { (key, value) -> fbCrashlytics.setCustomKey(key, value) }
|
client.logErrorEvent(error, params)
|
||||||
fbCrashlytics.recordException(error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleCardSdkErrorEvent(
|
override fun handleCardSdkErrorEvent(
|
||||||
|
|
@ -56,18 +43,11 @@ class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler
|
||||||
params: Map<AnalyticsParam, String>,
|
params: Map<AnalyticsParam, String>,
|
||||||
card: Card?,
|
card: Card?,
|
||||||
) {
|
) {
|
||||||
if (error is TangemSdkError.UserCancelled) return
|
val model = CardSdkErrorConverter.Model(error, action, params, prepareParams(card))
|
||||||
|
val converter = CardSdkErrorConverter()
|
||||||
val mutableParams = params.toMutableMap()
|
converter.convert(model)?.let {
|
||||||
if (card != null) mutableParams + prepareParams(card)
|
handleErrorEvent(it.throwable, it.params)
|
||||||
|
}
|
||||||
mutableParams[AnalyticsParam.ACTION] = action.key
|
|
||||||
mutableParams[AnalyticsParam.ERROR_CODE] = error.code.toString()
|
|
||||||
mutableParams[AnalyticsParam.ERROR_DESCRIPTION] = error.javaClass.simpleName
|
|
||||||
mutableParams[AnalyticsParam.ERROR_KEY] = "TangemSdkError"
|
|
||||||
|
|
||||||
mutableParams.forEach { fbCrashlytics.setCustomKey(it.key.param, it.value) }
|
|
||||||
fbCrashlytics.recordException(TangemSdk.map(error))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleBlockchainSdkErrorEvent(
|
override fun handleBlockchainSdkErrorEvent(
|
||||||
|
|
@ -76,52 +56,36 @@ class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler
|
||||||
params: Map<AnalyticsParam, String>,
|
params: Map<AnalyticsParam, String>,
|
||||||
card: Card?,
|
card: Card?,
|
||||||
) {
|
) {
|
||||||
val blockchainSdkError = (error as? BlockchainSdkError) ?: return
|
|
||||||
|
|
||||||
if (blockchainSdkError is BlockchainSdkError.WrappedTangemError) {
|
val model = BlockchainSdkErrorConverter.Model(error, action, params, prepareParams(card))
|
||||||
val tangemSdkError = (blockchainSdkError.tangemError as? TangemSdkError) ?: return
|
val converter = BlockchainSdkErrorConverter(CardSdkErrorConverter())
|
||||||
handleCardSdkErrorEvent(tangemSdkError, action, params, card)
|
converter.convert(model)?.let {
|
||||||
return
|
handleErrorEvent(it.throwable, it.params)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockchainSdkError.customMessage.contains(DemoTransactionSender.ID)) return
|
|
||||||
|
|
||||||
val mutableParams = params.toMutableMap()
|
|
||||||
mutableParams[AnalyticsParam.ACTION] = action.key
|
|
||||||
mutableParams[AnalyticsParam.ERROR_CODE] = error.code.toString()
|
|
||||||
mutableParams[AnalyticsParam.ERROR_DESCRIPTION] = "${error.javaClass.simpleName}: ${error.customMessage}"
|
|
||||||
mutableParams[AnalyticsParam.ERROR_KEY] = "BlockchainSdkError"
|
|
||||||
|
|
||||||
mutableParams.forEach { fbCrashlytics.setCustomKey(it.key.param, it.value) }
|
|
||||||
fbCrashlytics.recordException(error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Map<String, String>.toBundle(): Bundle {
|
override fun handleShopifyOrderEvent(order: Storefront.Order) {
|
||||||
return bundleOf(*this.toList().toTypedArray())
|
handleEvent(FirebaseClient.ORDER_EVENT, OrderToParamsConverter().convert(order))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
companion object {
|
|
||||||
const val ORDER_EVENT = FirebaseAnalytics.Event.PURCHASE
|
private class OrderToParamsConverter : Converter<Storefront.Order, Map<String, String>> {
|
||||||
}
|
override fun convert(value: Storefront.Order): Map<String, String> {
|
||||||
|
val sku = value.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
|
||||||
class OrderToParamsConverter : Converter<Storefront.Order, Map<String, String>> {
|
|
||||||
override fun convert(value: Storefront.Order): Map<String, String> {
|
val discountCode =
|
||||||
val sku = value.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
|
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
||||||
|
|
||||||
val discountCode =
|
val discountParams = if (discountCode != null) {
|
||||||
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
mapOf(FirebaseAnalytics.Param.DISCOUNT to discountCode)
|
||||||
|
} else {
|
||||||
val discountParams = if (discountCode != null) {
|
mapOf()
|
||||||
mapOf(FirebaseAnalytics.Param.DISCOUNT to discountCode)
|
}
|
||||||
} else {
|
|
||||||
mapOf()
|
return mapOf(
|
||||||
}
|
FirebaseAnalytics.Param.ITEM_ID to sku,
|
||||||
|
FirebaseAnalytics.Param.VALUE to value.totalPriceV2.amount,
|
||||||
return mapOf(
|
FirebaseAnalytics.Param.CURRENCY to value.currencyCode.name,
|
||||||
FirebaseAnalytics.Param.ITEM_ID to sku,
|
) + discountParams
|
||||||
FirebaseAnalytics.Param.VALUE to value.totalPriceV2.amount,
|
|
||||||
FirebaseAnalytics.Param.CURRENCY to value.currencyCode.name,
|
|
||||||
) + discountParams
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.tangem.tap.common.analytics.handlers.firebase
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
|
import com.google.firebase.analytics.ktx.analytics
|
||||||
|
import com.google.firebase.crashlytics.ktx.crashlytics
|
||||||
|
import com.google.firebase.ktx.Firebase
|
||||||
|
import com.tangem.tap.common.analytics.api.ErrorEventLogger
|
||||||
|
import com.tangem.tap.common.analytics.api.EventLogger
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
interface FirebaseAnalyticsClient : EventLogger, ErrorEventLogger
|
||||||
|
|
||||||
|
internal class FirebaseClient : FirebaseAnalyticsClient {
|
||||||
|
|
||||||
|
private val fbAnalytics = Firebase.analytics
|
||||||
|
private val fbCrashlytics = Firebase.crashlytics
|
||||||
|
|
||||||
|
override fun logEvent(event: String, params: Map<String, String>) {
|
||||||
|
fbAnalytics.logEvent(event, params.toBundle())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logErrorEvent(error: Throwable, params: Map<String, String>) {
|
||||||
|
params.forEach { fbCrashlytics.setCustomKey(it.key, it.value) }
|
||||||
|
fbCrashlytics.recordException(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Map<String, String>.toBundle(): Bundle = bundleOf(*this.toList().toTypedArray())
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ORDER_EVENT = FirebaseAnalytics.Event.PURCHASE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.tangem.tap.common.analytics.handlers.firebase
|
||||||
|
|
||||||
|
import com.tangem.tap.common.analytics.AnalyticsEventsLogger
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
internal class FirebaseLogClient(
|
||||||
|
private val logger: AnalyticsEventsLogger,
|
||||||
|
) : FirebaseAnalyticsClient {
|
||||||
|
|
||||||
|
override fun logEvent(event: String, params: Map<String, String>) {
|
||||||
|
logger.logEvent(event, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logErrorEvent(error: Throwable, params: Map<String, String>) {
|
||||||
|
logger.logErrorEvent(error, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue