feat(analytics): expand DataDog RUM integration and align with iOS parity (#4970)

This commit is contained in:
James Rich 2026-04-01 15:27:28 -05:00 committed by GitHub
parent e249461e3c
commit 0167063497
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 109 additions and 34 deletions

View file

@ -26,6 +26,7 @@ import co.touchlab.kermit.LogWriter
import co.touchlab.kermit.Severity
import com.datadog.android.Datadog
import com.datadog.android.DatadogSite
import com.datadog.android.compose.enableComposeActionTracking
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.log.Logger
import com.datadog.android.log.Logs
@ -33,7 +34,11 @@ import com.datadog.android.log.LogsConfiguration
import com.datadog.android.privacy.TrackingConsent
import com.datadog.android.rum.GlobalRumMonitor
import com.datadog.android.rum.Rum
import com.datadog.android.rum.RumActionType
import com.datadog.android.rum.RumConfiguration
import com.datadog.android.sessionreplay.SessionReplay
import com.datadog.android.sessionreplay.SessionReplayConfiguration
import com.datadog.android.sessionreplay.SessionReplayPrivacy
import com.datadog.android.trace.Trace
import com.datadog.android.trace.TraceConfiguration
import com.datadog.android.trace.opentelemetry.DatadogOpenTelemetry
@ -68,7 +73,7 @@ import co.touchlab.kermit.Logger as KermitLogger
class GooglePlatformAnalytics(private val context: Context, private val analyticsPrefs: AnalyticsPrefs) :
PlatformAnalytics {
private val sampleRate = 100f.takeIf { BuildConfig.DEBUG } ?: 10f // For Datadog remote sample rate
private val sampleRate = 100f // Match Apple: 100% sampling for cross-platform DataDog comparison
private var datadogLogger: Logger? = null
private var isFirebaseInitialized = false
@ -137,7 +142,7 @@ class GooglePlatformAnalytics(private val context: Context, private val analytic
val configuration =
Configuration.Builder(
clientToken = BuildConfig.datadogClientToken,
env = if (BuildConfig.DEBUG) "debug" else "release",
env = if (BuildConfig.DEBUG) "Local" else "Production",
variant = BuildConfig.FLAVOR,
)
.useSite(DatadogSite.US5)
@ -151,10 +156,11 @@ class GooglePlatformAnalytics(private val context: Context, private val analytic
val rumConfiguration =
RumConfiguration.Builder(BuildConfig.datadogApplicationId)
.trackAnonymousUser(true)
.trackBackgroundEvents(false) // Disable background noise
.trackBackgroundEvents(true) // Match Apple: track background events for cross-platform parity
.trackFrustrations(false) // Disable click-tracking based frustration detection
.trackLongTasks()
.trackNonFatalAnrs(true)
.enableComposeActionTracking() // Required: activates runtime consumption of Compose semantics tags
.setSessionSampleRate(sampleRate)
.build()
Rum.enable(rumConfiguration)
@ -162,9 +168,17 @@ class GooglePlatformAnalytics(private val context: Context, private val analytic
val logsConfig = LogsConfiguration.Builder().build()
Logs.enable(logsConfig)
val traceConfig = TraceConfiguration.Builder().setNetworkInfoEnabled(false).build()
val traceConfig = TraceConfiguration.Builder().setNetworkInfoEnabled(true).build()
Trace.enable(traceConfig)
// Session Replay for debug builds only, matching Apple's TestFlight-only gating.
// Masks all text inputs to protect message content.
if (BuildConfig.DEBUG) {
val sessionReplayConfig =
SessionReplayConfiguration.Builder(sampleRate).setPrivacy(SessionReplayPrivacy.MASK_USER_INPUT).build()
SessionReplay.enable(sessionReplayConfig)
}
GlobalOpenTelemetry.set(DatadogOpenTelemetry(serviceName = SERVICE_NAME))
}
@ -233,6 +247,24 @@ class GooglePlatformAnalytics(private val context: Context, private val analytic
GlobalRumMonitor.get().addAttribute("device_hardware", model)
}
override fun trackConnect(
firmwareVersion: String?,
transportType: String?,
hardwareModel: String?,
nodes: Int,
connectionRestored: Boolean,
) {
if (!Datadog.isInitialized() || !GlobalRumMonitor.isRegistered()) return
val attributes = buildMap {
firmwareVersion?.let { put("firmwareVersion", it) }
transportType?.let { put("transportType", it) }
hardwareModel?.let { put("hardwareModel", it) }
put("nodes", nodes)
if (connectionRestored) put("connectionRestored", true)
}
GlobalRumMonitor.get().addAction(RumActionType.CUSTOM, "connect", attributes)
}
private val isGooglePlayAvailable: Boolean
get() =
GoogleApiAvailabilityLight.getInstance().isGooglePlayServicesAvailable(context).let {