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.tap.common.AndroidAssetReader
|
||||
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.FeedbackManager
|
||||
import com.tangem.tap.common.images.createCoilImageLoader
|
||||
|
|
@ -100,7 +100,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
}
|
||||
|
||||
private fun initAnalytics(application: Application, config: Config) {
|
||||
val globalAnalyticsHandler = AnalyticsEventHandlerBuilder(
|
||||
val globalAnalyticsHandler = GlobalAnalyticsEventHandlerBuilder(
|
||||
application = application,
|
||||
config = config,
|
||||
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.common.card.Card
|
||||
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
|
||||
|
||||
interface GlobalAnalyticsEventHandler : AnalyticsEventHandler,
|
||||
ShopifyOrderEventHandler,
|
||||
ErrorEventHandler,
|
||||
SdkErrorEventHandler
|
||||
SdkErrorEventHandler,
|
||||
ShopifyOrderEventHandler
|
||||
|
||||
class GlobalAnalyticsHandler(
|
||||
private val analyticsHandlers: List<AnalyticsEventHandler>,
|
||||
|
|
@ -28,15 +35,9 @@ class GlobalAnalyticsHandler(
|
|||
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>) {
|
||||
analyticsHandlers.filterIsInstance<ErrorEventHandler>().forEach {
|
||||
it.handleErrorEvent(error, params)
|
||||
analyticsHandlers.filterIsInstance<ErrorEventLogger>().forEach {
|
||||
it.logErrorEvent(error, params)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +62,12 @@ class GlobalAnalyticsHandler(
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -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.tangem.blockchain.common.BlockchainError
|
||||
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.AnalyticsParam
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
|
||||
interface EventHandler {
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface AnalyticsEventHandler {
|
||||
fun handleEvent(
|
||||
event: String,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
)
|
||||
}
|
||||
|
||||
interface AnalyticsEventHandler : EventHandler {
|
||||
fun handleAnalyticsEvent(
|
||||
event: AnalyticsEvent,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
|
|
@ -25,17 +29,11 @@ interface AnalyticsEventHandler : EventHandler {
|
|||
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)
|
||||
): Map<String, String> = mapOf(
|
||||
AnalyticsParam.FIRMWARE.param to card?.firmwareVersion?.stringValue,
|
||||
AnalyticsParam.BATCH_ID.param to card?.batchId,
|
||||
AnalyticsParam.BLOCKCHAIN.param to blockchain,
|
||||
).filterNotNull() + params
|
||||
}
|
||||
|
||||
interface ErrorEventHandler {
|
||||
|
|
@ -63,4 +61,8 @@ interface BlockchainSdkErrorEventHandler {
|
|||
params: Map<AnalyticsParam, String> = mapOf(),
|
||||
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
|
||||
|
||||
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
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsEventHandler
|
||||
|
||||
class AmplitudeAnalyticsHandler(
|
||||
application: Application,
|
||||
key: String,
|
||||
private val client: AmplitudeAnalyticsClient,
|
||||
) : 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))
|
||||
client.logEvent(event, params)
|
||||
}
|
||||
|
||||
override fun handleAnalyticsEvent(
|
||||
|
|
@ -33,11 +20,4 @@ class AmplitudeAnalyticsHandler(
|
|||
) {
|
||||
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
|
||||
|
||||
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
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler
|
||||
|
||||
class AppsFlyerAnalyticsHandler(
|
||||
private val context: Context,
|
||||
key: String,
|
||||
private val client: AppsFlyerAnalyticsClient,
|
||||
) : 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)
|
||||
client.logEvent(event, params)
|
||||
}
|
||||
|
||||
override fun handleAnalyticsEvent(
|
||||
|
|
@ -43,25 +33,26 @@ class AppsFlyerAnalyticsHandler(
|
|||
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"
|
||||
private class OrderToParamsConverter : Converter<Storefront.Order, Map<String, String>> {
|
||||
|
||||
val discountCode =
|
||||
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
||||
override fun convert(value: Storefront.Order): Map<String, String> {
|
||||
val sku = value.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
|
||||
|
||||
val discountParams = if (discountCode != null) {
|
||||
mapOf(AFInAppEventParameterName.COUPON_CODE to discountCode)
|
||||
} else {
|
||||
mapOf()
|
||||
}
|
||||
val discountCode =
|
||||
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
||||
|
||||
return mapOf(
|
||||
AFInAppEventParameterName.CONTENT_ID to sku,
|
||||
AFInAppEventParameterName.REVENUE to value.totalPriceV2.amount,
|
||||
AFInAppEventParameterName.CURRENCY to value.currencyCode.name,
|
||||
) + discountParams
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
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
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.tap.common.analytics.api.ErrorEventHandler
|
||||
import com.tangem.tap.common.analytics.api.SdkErrorEventHandler
|
||||
import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler
|
||||
import com.tangem.tap.common.analytics.converters.BlockchainSdkErrorConverter
|
||||
import com.tangem.tap.common.analytics.converters.CardSdkErrorConverter
|
||||
|
||||
class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler, ErrorEventHandler,
|
||||
SdkErrorEventHandler {
|
||||
|
||||
private val fbAnalytics = Firebase.analytics
|
||||
private val fbCrashlytics = Firebase.crashlytics
|
||||
class FirebaseAnalyticsHandler(
|
||||
private val client: FirebaseAnalyticsClient,
|
||||
) : AnalyticsEventHandler, ErrorEventHandler, SdkErrorEventHandler, ShopifyOrderEventHandler {
|
||||
|
||||
override fun handleEvent(event: String, params: Map<String, String>) {
|
||||
fbAnalytics.logEvent(event, params.toBundle())
|
||||
client.logEvent(event, params)
|
||||
}
|
||||
|
||||
override fun handleAnalyticsEvent(
|
||||
|
|
@ -38,16 +30,11 @@ class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler
|
|||
card: Card?,
|
||||
blockchain: String?,
|
||||
) {
|
||||
handleEvent(event.event, prepareParams(card, blockchain, params))
|
||||
}
|
||||
|
||||
override fun handleShopifyOrderEvent(order: Storefront.Order) {
|
||||
handleEvent(ORDER_EVENT, OrderToParamsConverter().convert(order))
|
||||
handleEvent(event.name, prepareParams(card, blockchain, params))
|
||||
}
|
||||
|
||||
override fun handleErrorEvent(error: Throwable, params: Map<String, String>) {
|
||||
params.forEach { (key, value) -> fbCrashlytics.setCustomKey(key, value) }
|
||||
fbCrashlytics.recordException(error)
|
||||
client.logErrorEvent(error, params)
|
||||
}
|
||||
|
||||
override fun handleCardSdkErrorEvent(
|
||||
|
|
@ -56,18 +43,11 @@ class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler
|
|||
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))
|
||||
val model = CardSdkErrorConverter.Model(error, action, params, prepareParams(card))
|
||||
val converter = CardSdkErrorConverter()
|
||||
converter.convert(model)?.let {
|
||||
handleErrorEvent(it.throwable, it.params)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleBlockchainSdkErrorEvent(
|
||||
|
|
@ -76,52 +56,36 @@ class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler
|
|||
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
|
||||
val model = BlockchainSdkErrorConverter.Model(error, action, params, prepareParams(card))
|
||||
val converter = BlockchainSdkErrorConverter(CardSdkErrorConverter())
|
||||
converter.convert(model)?.let {
|
||||
handleErrorEvent(it.throwable, it.params)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleShopifyOrderEvent(order: Storefront.Order) {
|
||||
handleEvent(FirebaseClient.ORDER_EVENT, OrderToParamsConverter().convert(order))
|
||||
}
|
||||
}
|
||||
|
||||
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 =
|
||||
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
||||
|
||||
val discountParams = if (discountCode != null) {
|
||||
mapOf(FirebaseAnalytics.Param.DISCOUNT to discountCode)
|
||||
} else {
|
||||
mapOf()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
return mapOf(
|
||||
FirebaseAnalytics.Param.ITEM_ID to sku,
|
||||
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