From 3bd7ee2177d73db73ae4c763f2617faff55e9fa8 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 24 Feb 2025 10:17:29 +0100 Subject: [PATCH 1/2] fix: distinctId and anonymousId should degrade gracefully if they are strings that can't be parsed --- CHANGELOG.md | 4 + .../PosthogReactNativeSessionReplayModule.kt | 151 +++++++++++------- 2 files changed, 99 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 795e52b..f28d2e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Next +## 1.0.2 - 2025-02-24 + +- fix: distinctId and anonymousId should degrade gracefully if they are strings that can't be parsed + ## 1.0.1 - 2025-02-21 - chore: pin the iOS SDK to 3.x.x diff --git a/android/src/main/java/com/posthogreactnativesessionreplay/PosthogReactNativeSessionReplayModule.kt b/android/src/main/java/com/posthogreactnativesessionreplay/PosthogReactNativeSessionReplayModule.kt index 5e4ae2a..2771723 100644 --- a/android/src/main/java/com/posthogreactnativesessionreplay/PosthogReactNativeSessionReplayModule.kt +++ b/android/src/main/java/com/posthogreactnativesessionreplay/PosthogReactNativeSessionReplayModule.kt @@ -1,5 +1,6 @@ package com.posthogreactnativesessionreplay +import android.util.Log import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod @@ -27,57 +28,71 @@ class PosthogReactNativeSessionReplayModule(reactContext: ReactApplicationContex @ReactMethod fun start(sessionId: String, sdkOptions: ReadableMap, sdkReplayConfig: ReadableMap, decideReplayConfig: ReadableMap, promise: Promise) { val initRunnable = Runnable { - val uuid = UUID.fromString(sessionId) - PostHogSessionManager.setSessionId(uuid) - - val context = this.reactApplicationContext - val apiKey = sdkOptions.getString("apiKey") ?: "" - val host = sdkOptions.getString("host") ?: PostHogConfig.DEFAULT_HOST - val debugValue = sdkOptions.getBoolean("debug") - - val maskAllTextInputs = sdkReplayConfig.getBoolean("maskAllTextInputs") - val maskAllImages = sdkReplayConfig.getBoolean("maskAllImages") - val captureLog = sdkReplayConfig.getBoolean("captureLog") - val debouncerDelayMs = sdkReplayConfig.getInt("androidDebouncerDelayMs") - - val endpoint = decideReplayConfig.getString("endpoint") - - val distinctId = sdkOptions.getString("distinctId") ?: "" - val anonymousId = sdkOptions.getString("anonymousId") ?: "" - val theSdkVersion = sdkOptions.getString("sdkVersion") - - var theFlushAt = 20 - if (sdkOptions.hasKey("flushAt")) { - theFlushAt = sdkOptions.getInt("flushAt") - } - - val config = PostHogAndroidConfig(apiKey, host).apply { - debug = debugValue - captureDeepLinks = false - captureApplicationLifecycleEvents = false - captureScreenViews = false - flushAt = theFlushAt - sessionReplay = true - sessionReplayConfig.screenshot = true - sessionReplayConfig.captureLogcat = captureLog - sessionReplayConfig.debouncerDelayMs = debouncerDelayMs.toLong() - sessionReplayConfig.maskAllImages = maskAllImages - sessionReplayConfig.maskAllTextInputs = maskAllTextInputs - - if (!endpoint.isNullOrEmpty()) { - snapshotEndpoint = endpoint + try { + val uuid = UUID.fromString(sessionId) + PostHogSessionManager.setSessionId(uuid) + + val context = this.reactApplicationContext + val apiKey = sdkOptions.getString("apiKey") ?: "" + val host = sdkOptions.getString("host") ?: PostHogConfig.DEFAULT_HOST + val debugValue = sdkOptions.getBoolean("debug") + + val maskAllTextInputs = sdkReplayConfig.getBoolean("maskAllTextInputs") + val maskAllImages = sdkReplayConfig.getBoolean("maskAllImages") + val captureLog = sdkReplayConfig.getBoolean("captureLog") + val debouncerDelayMs = sdkReplayConfig.getInt("androidDebouncerDelayMs") + + val endpoint = decideReplayConfig.getString("endpoint") + + val distinctId = try { + sdkOptions.getString("distinctId") ?: "" + } catch (e: Throwable) { + logError("parse distinctId", e) + "" + } + val anonymousId = try { + sdkOptions.getString("anonymousId") ?: "" + } catch (e: Throwable) { + logError("parse anonymousId", e) + "" } + val theSdkVersion = sdkOptions.getString("sdkVersion") - if (!theSdkVersion.isNullOrEmpty()) { - sdkName = "posthog-react-native" - sdkVersion = theSdkVersion + var theFlushAt = 20 + if (sdkOptions.hasKey("flushAt")) { + theFlushAt = sdkOptions.getInt("flushAt") } - } - PostHogAndroid.setup(context, config) - setIdentify(config.cachePreferences, distinctId, anonymousId) + val config = PostHogAndroidConfig(apiKey, host).apply { + debug = debugValue + captureDeepLinks = false + captureApplicationLifecycleEvents = false + captureScreenViews = false + flushAt = theFlushAt + sessionReplay = true + sessionReplayConfig.screenshot = true + sessionReplayConfig.captureLogcat = captureLog + sessionReplayConfig.debouncerDelayMs = debouncerDelayMs.toLong() + sessionReplayConfig.maskAllImages = maskAllImages + sessionReplayConfig.maskAllTextInputs = maskAllTextInputs + + if (!endpoint.isNullOrEmpty()) { + snapshotEndpoint = endpoint + } + + if (!theSdkVersion.isNullOrEmpty()) { + sdkName = "posthog-react-native" + sdkVersion = theSdkVersion + } + } + PostHogAndroid.setup(context, config) - promise.resolve(null) + setIdentify(config.cachePreferences, distinctId, anonymousId) + } catch (e: Throwable) { + logError("start", e) + } finally { + promise.resolve(null) + } } // forces the SDK to be initialized on the main thread @@ -90,28 +105,47 @@ class PosthogReactNativeSessionReplayModule(reactContext: ReactApplicationContex @ReactMethod fun startSession(sessionId: String, promise: Promise) { - val uuid = UUID.fromString(sessionId) - PostHogSessionManager.setSessionId(uuid) - PostHog.startSession() - promise.resolve(null) + try { + val uuid = UUID.fromString(sessionId) + PostHogSessionManager.setSessionId(uuid) + PostHog.startSession() + } catch (e: Throwable) { + logError("startSession", e) + } finally { + promise.resolve(null) + } } @ReactMethod fun isEnabled(promise: Promise) { - promise.resolve(PostHog.isSessionReplayActive()) + try { + promise.resolve(PostHog.isSessionReplayActive()) + } catch (e: Throwable) { + logError("isEnabled", e) + promise.resolve(false) + } } @ReactMethod fun endSession(promise: Promise) { - PostHog.endSession() - promise.resolve(null) + try { + PostHog.endSession() + } catch (e: Throwable) { + logError("endSession", e) + } finally { + promise.resolve(null) + } } @ReactMethod fun identify(distinctId: String, anonymousId: String, promise: Promise) { - setIdentify(PostHog.getConfig()?.cachePreferences, distinctId, anonymousId) - - promise.resolve(null) + try { + setIdentify(PostHog.getConfig()?.cachePreferences, distinctId, anonymousId) + } catch (e: Throwable) { + logError("identify", e) + } finally { + promise.resolve(null) + } } private fun setIdentify(cachePreferences: PostHogPreferences?, distinctId: String, anonymousId: String) { @@ -125,7 +159,12 @@ class PosthogReactNativeSessionReplayModule(reactContext: ReactApplicationContex } } + private fun logError(method: String, error: Throwable) { + Log.println(Log.ERROR, POSTHOG_TAG, "Method $method, error: $error") + } + companion object { const val NAME = "PosthogReactNativeSessionReplay" + const val POSTHOG_TAG = "PostHog" } } From 26971acb2ba58ad3d06c408eb7790f62cfa50a4c Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 24 Feb 2025 10:18:07 +0100 Subject: [PATCH 2/2] format --- .../PosthogReactNativeSessionReplayModule.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/posthogreactnativesessionreplay/PosthogReactNativeSessionReplayModule.kt b/android/src/main/java/com/posthogreactnativesessionreplay/PosthogReactNativeSessionReplayModule.kt index 2771723..25ab024 100644 --- a/android/src/main/java/com/posthogreactnativesessionreplay/PosthogReactNativeSessionReplayModule.kt +++ b/android/src/main/java/com/posthogreactnativesessionreplay/PosthogReactNativeSessionReplayModule.kt @@ -26,7 +26,13 @@ class PosthogReactNativeSessionReplayModule(reactContext: ReactApplicationContex } @ReactMethod - fun start(sessionId: String, sdkOptions: ReadableMap, sdkReplayConfig: ReadableMap, decideReplayConfig: ReadableMap, promise: Promise) { + fun start( + sessionId: String, + sdkOptions: ReadableMap, + sdkReplayConfig: ReadableMap, + decideReplayConfig: ReadableMap, + promise: Promise + ) { val initRunnable = Runnable { try { val uuid = UUID.fromString(sessionId) @@ -148,7 +154,11 @@ class PosthogReactNativeSessionReplayModule(reactContext: ReactApplicationContex } } - private fun setIdentify(cachePreferences: PostHogPreferences?, distinctId: String, anonymousId: String) { + private fun setIdentify( + cachePreferences: PostHogPreferences?, + distinctId: String, + anonymousId: String + ) { cachePreferences?.let { preferences -> if (anonymousId.isNotEmpty()) { preferences.setValue(ANONYMOUS_ID, anonymousId)