diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ac8cc43b4b..c9fbcdf40f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -167,7 +167,7 @@ opusencoder = "io.element.android:opusencoder:1.1.0" kotlinpoet = "com.squareup:kotlinpoet:1.15.3" # Analytics -posthog = "com.posthog.android:posthog:2.0.3" +posthog = "com.posthog:posthog-android:3.0.0-RC.1" sentry = "io.sentry:sentry-android:7.0.0" matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:aa14cbcdf81af2746d20a71779ec751f971e1d7f" diff --git a/services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PostHogFactory.kt b/services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PostHogFactory.kt index 40c72142c6..6c02b8b788 100644 --- a/services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PostHogFactory.kt +++ b/services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PostHogFactory.kt @@ -17,7 +17,9 @@ package io.element.android.services.analyticsproviders.posthog import android.content.Context -import com.posthog.android.PostHog +import com.posthog.PostHogInterface +import com.posthog.android.PostHogAndroid +import com.posthog.android.PostHogAndroidConfig import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.di.ApplicationContext import javax.inject.Inject @@ -27,31 +29,20 @@ class PostHogFactory @Inject constructor( private val buildMeta: BuildMeta, private val posthogEndpointConfigProvider: PosthogEndpointConfigProvider, ) { - - fun createPosthog(): PostHog { + fun createPosthog(): PostHogInterface { val endpoint = posthogEndpointConfigProvider.provide() - return PostHog.Builder(context, endpoint.apiKey, endpoint.host) - // Record certain application events automatically! (off/false by default) - // .captureApplicationLifecycleEvents() - // Record screen views automatically! (off/false by default) - // .recordScreenViews() - // Capture deep links as part of the screen call. (off by default) - // .captureDeepLinks() - // Maximum number of events to keep in queue before flushing (default 20) - // .flushQueueSize(20) - // Max delay before flushing the queue (30 seconds) - // .flushInterval(30, TimeUnit.SECONDS) - // Enable or disable collection of ANDROID_ID (true) - .collectDeviceId(false) - .logLevel(getLogLevel()) - .build() - } - - private fun getLogLevel(): PostHog.LogLevel { - return if (buildMeta.isDebuggable) { - PostHog.LogLevel.DEBUG - } else { - PostHog.LogLevel.INFO - } + return PostHogAndroid.with( + context, + PostHogAndroidConfig( + apiKey = endpoint.apiKey, + host = endpoint.host, + captureApplicationLifecycleEvents = false, + captureDeepLinks = false, + captureScreenViews = false, + ).also { + it.debug = buildMeta.isDebuggable + it.sendFeatureFlagEvent = false + } + ) } } diff --git a/services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PosthogAnalyticsProvider.kt b/services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PosthogAnalyticsProvider.kt index e371c6fef4..16cac5722d 100644 --- a/services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PosthogAnalyticsProvider.kt +++ b/services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PosthogAnalyticsProvider.kt @@ -16,8 +16,7 @@ package io.element.android.services.analyticsproviders.posthog -import com.posthog.android.PostHog -import com.posthog.android.Properties +import com.posthog.PostHogInterface import com.squareup.anvil.annotations.ContributesMultibinding import im.vector.app.features.analytics.itf.VectorAnalyticsEvent import im.vector.app.features.analytics.itf.VectorAnalyticsScreen @@ -37,30 +36,31 @@ class PosthogAnalyticsProvider @Inject constructor( ) : AnalyticsProvider { override val name = "Posthog" - private var posthog: PostHog? = null + private var posthog: PostHogInterface? = null private var analyticsId: String? = null override fun init() { posthog = createPosthog() - posthog?.optOut(false) + posthog?.optIn() + // Timber.e("PostHog distinctId: ${posthog?.distinctId()}") identifyPostHog() } override fun stop() { // When opting out, ensure that the queue is flushed first, or it will be flushed later (after user has revoked consent) posthog?.flush() - posthog?.optOut(true) - posthog?.shutdown() + posthog?.optOut() + posthog?.close() posthog = null analyticsId = null } override fun capture(event: VectorAnalyticsEvent) { - posthog?.capture(event.getName(), event.getProperties()?.toPostHogProperties()) + posthog?.capture(event.getName(), properties = event.getProperties()?.keepOnlyNonNullValues()) } override fun screen(screen: VectorAnalyticsScreen) { - posthog?.screen(screen.getName(), screen.getProperties()?.toPostHogProperties()) + posthog?.screen(screen.getName(), properties = screen.getProperties()) } override fun updateUserProperties(userProperties: UserProperties) { @@ -74,7 +74,7 @@ class PosthogAnalyticsProvider @Inject constructor( // Not implemented } - private fun createPosthog(): PostHog = postHogFactory.createPosthog() + private fun createPosthog(): PostHogInterface = postHogFactory.createPosthog() private fun identifyPostHog() { val id = analyticsId ?: return @@ -86,24 +86,15 @@ class PosthogAnalyticsProvider @Inject constructor( // posthog?.identify(id, lateInitUserPropertiesFactory.createUserProperties()?.getProperties()?.toPostHogUserProperties(), IGNORED_OPTIONS) } } - - private fun Map?.toPostHogProperties(): Properties? { - if (this == null) return null - - return Properties().apply { - putAll(this@toPostHogProperties) - } - } - - /** - * We avoid sending nulls as part of the UserProperties as this will reset the values across all devices. - * The UserProperties event has nullable properties to allow for clients to opt in. - */ - /* - private fun Map.toPostHogUserProperties(): Properties { - return Properties().apply { - putAll(this@toPostHogUserProperties.filter { it.value != null }) - } - } - */ +} + +private fun Map.keepOnlyNonNullValues(): Map { + val result = mutableMapOf() + for (entry in this) { + val value = entry.value + if (value != null) { + result[entry.key] = value + } + } + return result }