Updated on 2026-08-14

This commit is contained in:
Tangem 2022-09-23 02:11:50 +03:00
parent 53f9b9d572
commit d17d9e35bf
28 changed files with 514 additions and 455 deletions

View file

@ -1,56 +0,0 @@
package com.tangem.tap.common.analytics
import com.amplitude.api.Amplitude
import com.amplitude.api.AmplitudeClient
import com.shopify.buy3.Storefront
import com.tangem.common.card.Card
import com.tangem.common.core.TangemSdkError
import org.json.JSONObject
class AmplitudeAnalyticsHandler : AnalyticsHandler() {
private val client: AmplitudeClient = Amplitude.getInstance()
override fun triggerEvent(
event: AnalyticsEvent,
card: Card?,
blockchain: String?,
params: Map<String, String>
) {
client.logEvent(event.event, prepareParams(card, blockchain, params).toJson())
}
override fun triggerEvent(event: String, params: Map<String, String>) {
client.logEvent(event, params.toJson())
}
override fun logCardSdkError(
error: TangemSdkError,
actionToLog: Analytics.ActionToLog,
parameters: Map<AnalyticsParam, String>?,
card: Card?
) {
//TODO
}
override fun logError(error: Throwable, params: Map<String, String>) {
//TODO
}
override fun getOrderEvent(): String {
//TODO
return ""
}
override fun getOrderParams(order: Storefront.Order): Map<String, String> {
//TODO
return emptyMap()
}
private fun Map<String, String>.toJson(): JSONObject {
val json = JSONObject()
this.map { json.put(it.key, it.value) }
return json
}
}

View file

@ -0,0 +1,66 @@
package com.tangem.tap.common.analytics
import com.shopify.buy3.Storefront
import com.tangem.blockchain.common.BlockchainError
import com.tangem.common.card.Card
import com.tangem.common.core.TangemSdkError
import com.tangem.tap.common.extensions.filterNotNull
interface EventHandler {
fun handleEvent(
event: String,
params: Map<String, String> = emptyMap(),
)
}
interface AnalyticsEventHandler : EventHandler {
fun handleAnalyticsEvent(
event: AnalyticsEvent,
params: Map<String, String> = emptyMap(),
card: Card? = null,
blockchain: String? = null,
)
fun prepareParams(
card: Card?,
blockchain: String? = null,
params: Map<String, String> = emptyMap(),
): Map<String, String> {
return mapOf(
AnalyticsParam.FIRMWARE.param to card?.firmwareVersion?.stringValue,
AnalyticsParam.BATCH_ID.param to card?.batchId,
AnalyticsParam.BLOCKCHAIN.param to blockchain,
).filterNotNull() + params
}
}
interface ShopifyOrderEventHandler {
fun handleShopifyOrderEvent(order: Storefront.Order)
}
interface ErrorEventHandler {
fun handleErrorEvent(
error: Throwable,
params: Map<String, String> = emptyMap(),
)
}
interface SdkErrorEventHandler : CardSdkErrorEventHandler, BlockchainSdkErrorEventHandler
interface CardSdkErrorEventHandler {
fun handleCardSdkErrorEvent(
error: TangemSdkError,
action: Analytics.ActionToLog,
params: Map<AnalyticsParam, String> = emptyMap(),
card: Card? = null,
)
}
interface BlockchainSdkErrorEventHandler {
fun handleBlockchainSdkErrorEvent(
error: BlockchainError,
action: Analytics.ActionToLog,
params: Map<AnalyticsParam, String> = mapOf(),
card: Card? = null,
)
}

View file

@ -0,0 +1,66 @@
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))
}
}

View file

@ -1,93 +0,0 @@
package com.tangem.tap.common.analytics
import com.shopify.buy3.Storefront
import com.tangem.common.card.Card
import com.tangem.common.core.TangemSdkError
import com.tangem.tap.common.extensions.filterNotNull
abstract class AnalyticsHandler {
abstract fun triggerEvent(
event: AnalyticsEvent,
card: Card? = null,
blockchain: String? = null,
params: Map<String, String> = emptyMap()
)
abstract fun triggerEvent(
event: String,
params: Map<String, String>
)
abstract fun logCardSdkError(
error: TangemSdkError,
actionToLog: Analytics.ActionToLog,
parameters: Map<AnalyticsParam, String>? = null,
card: Card? = null
)
abstract fun logError(
error: Throwable,
params: Map<String, String> = emptyMap()
)
protected fun prepareParams(
card: Card?,
blockchain: String? = null,
params: Map<String, String> = emptyMap()
): Map<String, String> {
return mapOf(
AnalyticsParam.FIRMWARE.param to card?.firmwareVersion?.stringValue,
AnalyticsParam.BATCH_ID.param to card?.batchId,
AnalyticsParam.BLOCKCHAIN.param to blockchain,
).filterNotNull() + params
}
fun logWcEvent(event: Analytics.WcAnalyticsEvent) {
when (event) {
is Analytics.WcAnalyticsEvent.Action -> {
triggerEvent(
event = AnalyticsEvent.WC_SUCCESS_RESPONSE,
params = mapOf(
AnalyticsParam.WALLET_CONNECT_ACTION.param to event.action.name
)
)
}
is Analytics.WcAnalyticsEvent.Error -> {
val params = mapOf(
AnalyticsParam.WALLET_CONNECT_ACTION.param to event.action?.name,
AnalyticsParam.ERROR_DESCRIPTION.param to event.error.message
)
.filterNotNull()
logError(event.error, params)
}
is Analytics.WcAnalyticsEvent.InvalidRequest ->
triggerEvent(
event = AnalyticsEvent.WC_INVALID_REQUEST,
params = mapOf(
AnalyticsParam.WALLET_CONNECT_REQUEST.param to event.json
).filterNotNull()
)
is Analytics.WcAnalyticsEvent.Session -> {
val analyticsEvent = when (event.event) {
Analytics.WcSessionEvent.Disconnect -> AnalyticsEvent.WC_SESSION_DISCONNECTED
Analytics.WcSessionEvent.Connect -> AnalyticsEvent.WC_NEW_SESSION
}
triggerEvent(
event = analyticsEvent,
params = mapOf(
AnalyticsParam.WALLET_CONNECT_DAPP_URL.param to event.url
).filterNotNull()
)
}
}
}
fun logShopifyOrder(order: Storefront.Order) {
triggerEvent(getOrderEvent(), getOrderParams(order))
}
protected abstract fun getOrderEvent(): String
protected abstract fun getOrderParams(order: Storefront.Order): Map<String, String>
}

View file

@ -1,65 +0,0 @@
package com.tangem.tap.common.analytics
import android.content.Context
import com.appsflyer.AFInAppEventParameterName
import com.appsflyer.AFInAppEventType
import com.appsflyer.AppsFlyerLib
import com.shopify.buy3.Storefront
import com.tangem.common.card.Card
import com.tangem.common.core.TangemSdkError
class AppsFlyerAnalyticsHandler(val context: Context): AnalyticsHandler() {
override fun triggerEvent(
event: AnalyticsEvent,
card: Card?,
blockchain: String?,
params: Map<String, String>
) {
AppsFlyerLib.getInstance().logEvent(
context,
event.event,
prepareParams(card, blockchain, params)
)
}
override fun logCardSdkError(
error: TangemSdkError,
actionToLog: Analytics.ActionToLog,
parameters: Map<AnalyticsParam, String>?,
card: Card?
) {
//TODO
}
override fun logError(error: Throwable, params: Map<String, String>) {
//TODO
}
override fun getOrderEvent(): String = AFInAppEventType.PURCHASE
override fun getOrderParams(order: Storefront.Order): Map<String, String> {
val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
val discountCode =
(order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
val discountParams = if (discountCode != null ){
mapOf(AFInAppEventParameterName.COUPON_CODE to discountCode)
} else {
mapOf()
}
return mapOf(
AFInAppEventParameterName.CONTENT_ID to sku,
AFInAppEventParameterName.REVENUE to order.totalPriceV2.amount,
AFInAppEventParameterName.CURRENCY to order.currencyCode.name
) + discountParams
}
override fun triggerEvent(event: String, params: Map<String, String>) {
AppsFlyerLib.getInstance().logEvent(context, event, params)
}
}

View file

@ -1,88 +0,0 @@
package com.tangem.tap.common.analytics
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.FirebaseCrashlytics
import com.google.firebase.ktx.Firebase
import com.shopify.buy3.Storefront
import com.tangem.common.card.Card
import com.tangem.common.core.TangemSdkError
object FirebaseAnalyticsHandler : AnalyticsHandler() {
override fun triggerEvent(
event: AnalyticsEvent,
card: Card?,
blockchain: String?,
params: Map<String, String>
) {
val fullParams = prepareParams(card, blockchain, params)
Firebase.analytics.logEvent(event.event, fullParams.toBundle())
}
fun logException(name: String, throwable: Throwable) {
Firebase.analytics.logEvent(name, bundleOf(
"message" to (throwable.message ?: "none"),
"cause_message" to (throwable.cause?.message ?: "none"),
"stack_trace" to throwable.stackTraceToString()
))
}
private fun Map<String, String>.toBundle(): Bundle {
return bundleOf(*this.toList().toTypedArray())
}
override fun logCardSdkError(
error: TangemSdkError,
actionToLog: Analytics.ActionToLog,
parameters: Map<AnalyticsParam, String>?,
card: Card?,
) {
if (error is TangemSdkError.UserCancelled) return
val params = parameters?.toMutableMap() ?: mutableMapOf()
if (card != null) params + prepareParams(card)
params[AnalyticsParam.ACTION] = actionToLog.key
params[AnalyticsParam.ERROR_CODE] = error.code.toString()
params[AnalyticsParam.ERROR_DESCRIPTION] = error.javaClass.simpleName
params[AnalyticsParam.ERROR_KEY] = "TangemSdkError"
params.forEach {
FirebaseCrashlytics.getInstance().setCustomKey(it.key.param, it.value)
}
val cardError = TangemSdk.map(error)
FirebaseCrashlytics.getInstance().recordException(cardError)
}
override fun logError(error: Throwable, params: Map<String, String>) {
params.forEach { (key, value) -> FirebaseCrashlytics.getInstance().setCustomKey(key, value) }
FirebaseCrashlytics.getInstance().recordException(error)
}
override fun getOrderEvent(): String = FirebaseAnalytics.Event.PURCHASE
override fun getOrderParams(order: Storefront.Order): Map<String, String> {
val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
val discountCode =
(order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
val discountParams = if (discountCode != null ){
mapOf(FirebaseAnalytics.Param.DISCOUNT to discountCode)
} else {
mapOf()
}
return mapOf(
FirebaseAnalytics.Param.ITEM_ID to sku,
FirebaseAnalytics.Param.VALUE to order.totalPriceV2.amount,
FirebaseAnalytics.Param.CURRENCY to order.currencyCode.name
) + discountParams
}
override fun triggerEvent(event: String, params: Map<String, String>) {
Firebase.analytics.logEvent(event, params.toBundle())
}
}

View file

@ -1,77 +1,103 @@
package com.tangem.tap.common.analytics
import android.content.Context
import com.amplitude.api.Amplitude
import com.appsflyer.AppsFlyerLib
import com.shopify.buy3.Storefront
import com.tangem.blockchain.common.BlockchainError
import com.tangem.common.card.Card
import com.tangem.common.core.TangemSdkError
import com.tangem.tap.store
import com.tangem.tap.common.extensions.filterNotNull
class GlobalAnalyticsHandler(val analyticsHandlers: List<AnalyticsHandler>) :
AnalyticsHandler() {
override fun triggerEvent(
interface GlobalAnalyticsEventHandler : AnalyticsEventHandler,
ShopifyOrderEventHandler,
ErrorEventHandler,
SdkErrorEventHandler
class GlobalAnalyticsHandler(
private val analyticsHandlers: List<AnalyticsEventHandler>,
) : GlobalAnalyticsEventHandler {
override fun handleEvent(event: String, params: Map<String, String>) {
analyticsHandlers.forEach { it.handleEvent(event, params) }
}
override fun handleAnalyticsEvent(
event: AnalyticsEvent,
params: Map<String, String>,
card: Card?,
blockchain: String?,
params: Map<String, String>
) {
analyticsHandlers.forEach { it.triggerEvent(event, card, blockchain, params) }
analyticsHandlers.forEach { it.handleAnalyticsEvent(event, params, card, blockchain) }
}
override fun triggerEvent(event: String, params: Map<String, String>) {
analyticsHandlers.forEach { it.triggerEvent(event, params) }
override fun handleShopifyOrderEvent(order: Storefront.Order) {
analyticsHandlers.filterIsInstance<ShopifyOrderEventHandler>().forEach {
it.handleShopifyOrderEvent(order)
}
}
override fun logCardSdkError(
override fun handleErrorEvent(error: Throwable, params: Map<String, String>) {
analyticsHandlers.filterIsInstance<ErrorEventHandler>().forEach {
it.handleErrorEvent(error, params)
}
}
override fun handleCardSdkErrorEvent(
error: TangemSdkError,
actionToLog: Analytics.ActionToLog,
parameters: Map<AnalyticsParam, String>?,
card: Card?
action: Analytics.ActionToLog,
params: Map<AnalyticsParam, String>,
card: Card?,
) {
analyticsHandlers.forEach { it.logCardSdkError(error, actionToLog, parameters, card) }
analyticsHandlers.filterIsInstance<CardSdkErrorEventHandler>().forEach {
it.handleCardSdkErrorEvent(error, action, params, card)
}
}
override fun logError(error: Throwable, params: Map<String, String>) {
analyticsHandlers.forEach { it.logError(error, params) }
override fun handleBlockchainSdkErrorEvent(
error: BlockchainError,
action: Analytics.ActionToLog,
params: Map<AnalyticsParam, String>,
card: Card?,
) {
analyticsHandlers.filterIsInstance<BlockchainSdkErrorEventHandler>().forEach {
it.handleBlockchainSdkErrorEvent(error, action, params, card)
}
}
}
override fun getOrderEvent(): String {
return ""
}
override fun getOrderParams(order: Storefront.Order): Map<String, String> {
return emptyMap()
}
companion object {
fun createDefaultAnalyticHandlers(context: Context): GlobalAnalyticsHandler {
return GlobalAnalyticsHandler(
listOf(
FirebaseAnalyticsHandler,
AppsFlyerAnalyticsHandler(context),
AmplitudeAnalyticsHandler()
)
fun GlobalAnalyticsEventHandler.logWcEvent(event: Analytics.WcAnalyticsEvent) {
when (event) {
is Analytics.WcAnalyticsEvent.Action -> {
handleAnalyticsEvent(
event = AnalyticsEvent.WC_SUCCESS_RESPONSE,
params = mapOf(
AnalyticsParam.WALLET_CONNECT_ACTION.param to event.action.name,
),
)
}
private fun initAnalytics(context: Context) {
initAppsFlyer(context)
initAmplitude(context)
is Analytics.WcAnalyticsEvent.Error -> {
val params = mapOf(
AnalyticsParam.WALLET_CONNECT_ACTION.param to event.action?.name,
AnalyticsParam.ERROR_DESCRIPTION.param to event.error.message,
).filterNotNull()
handleErrorEvent(event.error, params)
}
private fun initAppsFlyer(context: Context) {
val devKey = store.state.globalState.configManager?.config?.appsFlyerDevKey ?: return
AppsFlyerLib.getInstance().init(devKey, null, context)
AppsFlyerLib.getInstance().start(context)
}
private fun initAmplitude(context: Context) {
val apiKey = store.state.globalState.configManager?.config?.amplitudeApiKey ?: return
Amplitude.getInstance()
.initialize(context.applicationContext, apiKey)
.enableForegroundTracking(context)
is Analytics.WcAnalyticsEvent.InvalidRequest ->
handleAnalyticsEvent(
event = AnalyticsEvent.WC_INVALID_REQUEST,
params = mapOf(
AnalyticsParam.WALLET_CONNECT_REQUEST.param to event.json,
).filterNotNull(),
)
is Analytics.WcAnalyticsEvent.Session -> {
val analyticsEvent = when (event.event) {
Analytics.WcSessionEvent.Disconnect -> AnalyticsEvent.WC_SESSION_DISCONNECTED
Analytics.WcSessionEvent.Connect -> AnalyticsEvent.WC_NEW_SESSION
}
handleAnalyticsEvent(
event = analyticsEvent,
params = mapOf(
AnalyticsParam.WALLET_CONNECT_DAPP_URL.param to event.url,
).filterNotNull(),
)
}
}
}

View file

@ -0,0 +1,43 @@
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.tap.common.analytics.AnalyticsEvent
import com.tangem.tap.common.analytics.AnalyticsEventHandler
import org.json.JSONObject
class AmplitudeAnalyticsHandler(
application: Application,
key: String,
) : AnalyticsEventHandler {
private val client: AmplitudeClient = Amplitude.getInstance()
init {
client.initialize(application, key)
client.enableForegroundTracking(application)
}
override fun handleEvent(event: String, params: Map<String, String>) {
client.logEvent(event, ParamsJSONObjectConverter().convert(params))
}
override fun handleAnalyticsEvent(
event: AnalyticsEvent,
params: Map<String, String>,
card: Card?,
blockchain: String?,
) {
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) }
}
}
}

View file

@ -0,0 +1,67 @@
package com.tangem.tap.common.analytics.handlers.appsFlyer
import android.content.Context
import com.appsflyer.AFInAppEventParameterName
import com.appsflyer.AFInAppEventType
import com.appsflyer.AppsFlyerLib
import com.shopify.buy3.Storefront
import com.tangem.common.Converter
import com.tangem.common.card.Card
import com.tangem.tap.common.analytics.AnalyticsEvent
import com.tangem.tap.common.analytics.AnalyticsEventHandler
import com.tangem.tap.common.analytics.ShopifyOrderEventHandler
class AppsFlyerAnalyticsHandler(
private val context: Context,
key: String,
) : 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>) {
appsFlyerLib.logEvent(context, event, params)
}
override fun handleAnalyticsEvent(
event: AnalyticsEvent,
params: Map<String, String>,
card: Card?,
blockchain: String?,
) {
handleEvent(event.event, prepareParams(card, blockchain, params))
}
override fun handleShopifyOrderEvent(order: Storefront.Order) {
handleEvent(ORDER_EVENT, OrderToParamsConverter().convert(order))
}
companion object {
const val ORDER_EVENT = AFInAppEventType.PURCHASE
}
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 =
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
val discountParams = if (discountCode != null) {
mapOf(AFInAppEventParameterName.COUPON_CODE to discountCode)
} else {
mapOf()
}
return mapOf(
AFInAppEventParameterName.CONTENT_ID to sku,
AFInAppEventParameterName.REVENUE to value.totalPriceV2.amount,
AFInAppEventParameterName.CURRENCY to value.currencyCode.name,
) + discountParams
}
}
}

View file

@ -0,0 +1,127 @@
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.shopify.buy3.Storefront
import com.tangem.blockchain.common.BlockchainError
import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.common.Converter
import com.tangem.common.card.Card
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.AnalyticsEventHandler
import com.tangem.tap.common.analytics.AnalyticsParam
import com.tangem.tap.common.analytics.ErrorEventHandler
import com.tangem.tap.common.analytics.SdkErrorEventHandler
import com.tangem.tap.common.analytics.ShopifyOrderEventHandler
import com.tangem.tap.common.analytics.TangemSdk
import com.tangem.tap.features.demo.DemoTransactionSender
class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler, ErrorEventHandler,
SdkErrorEventHandler {
private val fbAnalytics = Firebase.analytics
private val fbCrashlytics = Firebase.crashlytics
override fun handleEvent(event: String, params: Map<String, String>) {
fbAnalytics.logEvent(event, params.toBundle())
}
override fun handleAnalyticsEvent(
event: AnalyticsEvent,
params: Map<String, String>,
card: Card?,
blockchain: String?,
) {
handleEvent(event.event, 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>) {
params.forEach { (key, value) -> fbCrashlytics.setCustomKey(key, value) }
fbCrashlytics.recordException(error)
}
override fun handleCardSdkErrorEvent(
error: TangemSdkError,
action: Analytics.ActionToLog,
params: Map<AnalyticsParam, String>,
card: Card?,
) {
if (error is TangemSdkError.UserCancelled) return
val mutableParams = params.toMutableMap()
if (card != null) mutableParams + prepareParams(card)
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(
error: BlockchainError,
action: Analytics.ActionToLog,
params: Map<AnalyticsParam, String>,
card: Card?,
) {
val blockchainSdkError = (error as? BlockchainSdkError) ?: return
if (blockchainSdkError is BlockchainSdkError.WrappedTangemError) {
val tangemSdkError = (blockchainSdkError.tangemError as? TangemSdkError) ?: return
handleCardSdkErrorEvent(tangemSdkError, action, params, card)
return
}
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 {
return bundleOf(*this.toList().toTypedArray())
}
companion object {
const val ORDER_EVENT = FirebaseAnalytics.Event.PURCHASE
}
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 =
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
val discountParams = if (discountCode != null) {
mapOf(FirebaseAnalytics.Param.DISCOUNT to discountCode)
} else {
mapOf()
}
return mapOf(
FirebaseAnalytics.Param.ITEM_ID to sku,
FirebaseAnalytics.Param.VALUE to value.totalPriceV2.amount,
FirebaseAnalytics.Param.CURRENCY to value.currencyCode.name,
) + discountParams
}
}
}