Skip to content

Commit 251b46a

Browse files
authored
[Android] Allow deferring sdk start for the gradle sample app (#664)
* Allow deferring sdk start * Trigger ci
1 parent 03d10dd commit 251b46a

File tree

9 files changed

+193
-96
lines changed

9 files changed

+193
-96
lines changed

platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/attributes/IClientAttributes.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ interface IClientAttributes {
1919
/** A positive integer used as an internal version number. This helps determine version recency. */
2020
val appVersionCode: Long
2121

22-
/** Consumer-facing operating system brand name */
22+
/** Consumer-facing operating system brand name. */
2323
val osBrand: String
2424

2525
/**

platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/BitdriftInit.java

Lines changed: 0 additions & 49 deletions
This file was deleted.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// capture-sdk - bitdrift's client SDK
2+
// Copyright Bitdrift, Inc. All rights reserved.
3+
//
4+
// Use of this source code is governed by a source available license that can be found in the
5+
// LICENSE file or at:
6+
// https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt
7+
8+
package io.bitdrift.gradletestapp
9+
10+
import android.content.Context
11+
import android.content.SharedPreferences
12+
import android.util.Log
13+
import io.bitdrift.capture.Capture
14+
import io.bitdrift.capture.Configuration
15+
import io.bitdrift.capture.providers.FieldProvider
16+
import io.bitdrift.capture.providers.session.SessionStrategy
17+
import io.bitdrift.gradletestapp.ConfigurationSettingsFragment.Companion.FATAL_ISSUE_ENABLED_PREFS_KEY
18+
import io.bitdrift.gradletestapp.ConfigurationSettingsFragment.Companion.SESSION_STRATEGY_PREFS_KEY
19+
import io.bitdrift.gradletestapp.SettingsApiKeysDialogFragment.Companion.BITDRIFT_API_KEY
20+
import okhttp3.HttpUrl
21+
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
22+
import timber.log.Timber
23+
import java.util.UUID
24+
25+
/**
26+
* Starts bitdrift's Captures SDK with the persisted config settings
27+
*/
28+
object BitdriftInit {
29+
/**
30+
* Init sdk with the persisted settings
31+
*/
32+
fun initFromPreferences(
33+
sharedPreferences: SharedPreferences,
34+
context: Context,
35+
): Boolean {
36+
val settingsResult = getPersistedCaptureSdkSettings(sharedPreferences)
37+
when (settingsResult) {
38+
is SdkConfigResult.Success -> {
39+
val settings = settingsResult.captureSdkInitSettings
40+
Capture.Logger.start(
41+
apiKey = settings.apiKey,
42+
apiUrl = settings.apiUrl,
43+
configuration = settings.configuration,
44+
sessionStrategy = settings.sessionStrategy,
45+
fieldProviders = settings.fieldProviders,
46+
context = context,
47+
)
48+
Log.i("GradleTestApp", "Session initialized " + Capture.Logger.sessionUrl)
49+
return true
50+
}
51+
52+
is SdkConfigResult.Failed -> {
53+
Log.e("GradleTestApp", settingsResult.message)
54+
return false
55+
}
56+
}
57+
}
58+
59+
private fun getPersistedCaptureSdkSettings(sharedPreferences: SharedPreferences): SdkConfigResult {
60+
val apiKey = sharedPreferences.getString(BITDRIFT_API_KEY, null)
61+
val apiUrl = sharedPreferences.getString("apiUrl", null)?.toHttpUrlOrNull()
62+
if (apiUrl == null || apiKey == null) {
63+
return SdkConfigResult.Failed("Invalid settings. apiUrl: $apiUrl . apiKey: $apiKey")
64+
}
65+
val fatalIssueReporterEnabled =
66+
sharedPreferences.getBoolean(FATAL_ISSUE_ENABLED_PREFS_KEY, true)
67+
68+
val sessionStrategy = getSessionStrategy(sharedPreferences)
69+
val configuration =
70+
Configuration(
71+
enableFatalIssueReporting = fatalIssueReporterEnabled,
72+
enableNativeCrashReporting = fatalIssueReporterEnabled,
73+
)
74+
75+
val userID = UUID.randomUUID().toString()
76+
val fieldProviders =
77+
listOf(
78+
FieldProvider { mapOf("user_id" to userID) },
79+
)
80+
val captureSdkInitSettings =
81+
CaptureSdkInitSettings(
82+
apiUrl = apiUrl,
83+
apiKey = apiKey,
84+
sessionStrategy = sessionStrategy,
85+
configuration = configuration,
86+
fieldProviders = fieldProviders,
87+
)
88+
return SdkConfigResult.Success(captureSdkInitSettings)
89+
}
90+
91+
private fun getSessionStrategy(sharedPreferences: SharedPreferences): SessionStrategy =
92+
if (sharedPreferences.getString(
93+
SESSION_STRATEGY_PREFS_KEY,
94+
ConfigurationSettingsFragment.SessionStrategyPreferences.FIXED.displayName,
95+
) == "Fixed"
96+
) {
97+
SessionStrategy.Fixed()
98+
} else {
99+
SessionStrategy.ActivityBased(
100+
inactivityThresholdMins = 60L,
101+
onSessionIdChanged = { sessionId ->
102+
Timber.i("Bitdrift Logger session id updated: $sessionId")
103+
},
104+
)
105+
}
106+
107+
private sealed class SdkConfigResult {
108+
data class Failed(
109+
val message: String,
110+
) : SdkConfigResult()
111+
112+
data class Success(
113+
val captureSdkInitSettings: CaptureSdkInitSettings,
114+
) : SdkConfigResult()
115+
}
116+
117+
private data class CaptureSdkInitSettings(
118+
val apiUrl: HttpUrl,
119+
val apiKey: String,
120+
val sessionStrategy: SessionStrategy,
121+
val configuration: Configuration,
122+
val fieldProviders: List<FieldProvider>,
123+
)
124+
}

platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/ConfigurationSettingsFragment.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class ConfigurationSettingsFragment : PreferenceFragmentCompat() {
6565

6666
backendCategory.addPreference(buildSessionStrategyList(context))
6767
backendCategory.addPreference(buildSwitchPreference(context))
68+
backendCategory.addPreference(buildDeferredStartSwitch(context))
6869

6970
screen.addPreference(restartPreference)
7071

@@ -96,6 +97,20 @@ class ConfigurationSettingsFragment : PreferenceFragmentCompat() {
9697
return switchPreference
9798
}
9899

100+
private fun buildDeferredStartSwitch(context: Context): SwitchPreference {
101+
val switchPreference = SwitchPreference(context)
102+
switchPreference.key = DEFERRED_START_PREFS_KEY
103+
switchPreference.title = DEFERRED_START_TITLE
104+
switchPreference.summary = SELECTION_SUMMARY
105+
switchPreference.setDefaultValue(false)
106+
switchPreference.setOnPreferenceChangeListener { _, newValue ->
107+
val summaryText = if (newValue == true) "Enabled" else "Disabled"
108+
switchPreference.summary = "$summaryText - $SELECTION_SUMMARY"
109+
true
110+
}
111+
return switchPreference
112+
}
113+
99114
private fun showApiKeysDialog(context: Context) {
100115
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
101116
SettingsApiKeysDialogFragment(sharedPreferences).show(parentFragmentManager, "")
@@ -111,9 +126,11 @@ class ConfigurationSettingsFragment : PreferenceFragmentCompat() {
111126
companion object {
112127
const val SESSION_STRATEGY_PREFS_KEY = "sessionStrategy"
113128
const val FATAL_ISSUE_ENABLED_PREFS_KEY = "fatalIssueEnabled"
129+
const val DEFERRED_START_PREFS_KEY = "deferredStart"
114130
private const val SELECTION_SUMMARY = "App needs to be restarted for changes to take effect"
115131
private const val SESSION_STRATEGY_TITLE = "Session Strategy"
116132
private const val FATAL_ISSUE_TITLE = "Fatal Issue Reporter"
133+
private const val DEFERRED_START_TITLE = "Deferred SDK Start"
117134

118135
private val SESSION_STRATEGY_ENTRIES =
119136
arrayOf(

platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/FirstFragment.kt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ import android.annotation.SuppressLint
1111
import android.content.ClipData
1212
import android.content.ClipboardManager
1313
import android.content.Context
14+
import android.content.SharedPreferences
1415
import android.os.Bundle
1516
import android.view.LayoutInflater
1617
import android.view.View
1718
import android.view.ViewGroup
1819
import android.widget.ArrayAdapter
1920
import android.widget.Spinner
2021
import android.widget.Toast
22+
import androidx.preference.PreferenceManager
23+
import io.bitdrift.gradletestapp.ConfigurationSettingsFragment.Companion.DEFERRED_START_PREFS_KEY
2124
//noinspection UsingMaterialAndMaterial3Libraries
2225
import androidx.compose.material.MaterialTheme
2326
//noinspection UsingMaterialAndMaterial3Libraries
@@ -89,6 +92,8 @@ class FirstFragment : Fragment() {
8992
private lateinit var clipboardManager: ClipboardManager
9093
private lateinit var okHttpClient: OkHttpClient
9194
private lateinit var apolloClient: ApolloClient
95+
private lateinit var sharedPreferences: SharedPreferences
96+
9297
private var firstFragmentToCopySessionSpan: Span? = null
9398

9499
override fun onCreateView(
@@ -126,6 +131,8 @@ class FirstFragment : Fragment() {
126131
savedInstanceState: Bundle?,
127132
) {
128133
super.onViewCreated(view, savedInstanceState)
134+
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(view.context)
135+
129136
Logger.logScreenView("first_fragment")
130137
binding.btnNavigateConfiguration.setOnClickListener {
131138
Logger.logScreenView("config_fragment")
@@ -148,11 +155,17 @@ class FirstFragment : Fragment() {
148155
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
149156
}
150157

151-
binding.textviewFirst.text = Logger.sessionId
152-
153158
setSpinnerAdapter(binding.spnAppExitOptions, AppExitReason.entries)
154159
setSpinnerAdapter(binding.logLevelItems, LogLevel.entries.map { it.name }.toList())
155160

161+
if (sharedPreferences.getBoolean(DEFERRED_START_PREFS_KEY, false)) {
162+
binding.btnStartSdk.setOnClickListener(this::startSdkManually)
163+
binding.btnStartSdk.visibility = View.VISIBLE
164+
binding.textviewSdkStatus.visibility = View.VISIBLE
165+
} else {
166+
binding.textviewFirst.text = Logger.sessionId
167+
}
168+
156169
okHttpClient =
157170
OkHttpClient
158171
.Builder()
@@ -326,6 +339,13 @@ class FirstFragment : Fragment() {
326339
)
327340
}
328341

342+
private fun startSdkManually(view: View) {
343+
BitdriftInit.initFromPreferences(sharedPreferences, view.context)
344+
binding.btnStartSdk.visibility = View.GONE
345+
binding.textviewSdkStatus.visibility = View.GONE
346+
binding.textviewFirst.text = Logger.sessionId
347+
}
348+
329349
enum class AppExitReason {
330350
ANR_BLOCKING_GET,
331351
ANR_BROADCAST_RECEIVER,

platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/GradleTestApp.kt

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -47,27 +47,20 @@ import android.content.SharedPreferences
4747
import android.os.Build
4848
import android.os.Bundle
4949
import android.os.StrictMode
50-
import android.util.Log
5150
import androidx.core.content.ContextCompat
5251
import androidx.preference.PreferenceManager
5352
import com.bugsnag.android.Bugsnag
5453
import io.bitdrift.capture.Capture
5554
import io.bitdrift.capture.Capture.Logger.sessionUrl
56-
import io.bitdrift.capture.Configuration
5755
import io.bitdrift.capture.LogLevel
5856
import io.bitdrift.capture.events.span.Span
5957
import io.bitdrift.capture.events.span.SpanResult
60-
import io.bitdrift.capture.providers.session.SessionStrategy
6158
import io.bitdrift.capture.timber.CaptureTree
62-
import io.bitdrift.gradletestapp.ConfigurationSettingsFragment.Companion.FATAL_ISSUE_ENABLED_PREFS_KEY
63-
import io.bitdrift.gradletestapp.ConfigurationSettingsFragment.Companion.SESSION_STRATEGY_PREFS_KEY
64-
import io.bitdrift.gradletestapp.ConfigurationSettingsFragment.SessionStrategyPreferences.FIXED
65-
import io.bitdrift.gradletestapp.SettingsApiKeysDialogFragment.Companion.BITDRIFT_API_KEY
59+
import io.bitdrift.gradletestapp.ConfigurationSettingsFragment.Companion.DEFERRED_START_PREFS_KEY
6660
import io.bitdrift.gradletestapp.SettingsApiKeysDialogFragment.Companion.BUG_SNAG_SDK_API_KEY
6761
import io.bitdrift.gradletestapp.SettingsApiKeysDialogFragment.Companion.SENTRY_SDK_DSN_KEY
6862
import io.sentry.android.core.SentryAndroid
6963
import io.sentry.android.core.SentryAndroidOptions
70-
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
7164
import papa.AppLaunchType
7265
import papa.PapaEvent
7366
import papa.PapaEventListener
@@ -87,6 +80,7 @@ class GradleTestApp : Application() {
8780

8881
override fun onCreate() {
8982
super.onCreate()
83+
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
9084
Timber.i("Hello World!")
9185
setupStrictMode()
9286
initLogging()
@@ -96,47 +90,19 @@ class GradleTestApp : Application() {
9690
}
9791

9892
private fun initLogging() {
99-
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
100-
val stringApiUrl = sharedPreferences.getString("apiUrl", null)
101-
val apiUrl = stringApiUrl?.toHttpUrlOrNull()
102-
if (apiUrl == null) {
103-
Log.e("GradleTestApp", "Failed to initialize bitdrift logger due to invalid API URL: $stringApiUrl")
93+
if (sharedPreferences.getBoolean(DEFERRED_START_PREFS_KEY, false)) {
10494
return
10595
}
106-
val fatalIssueReporterEnabled =
107-
sharedPreferences.getBoolean(FATAL_ISSUE_ENABLED_PREFS_KEY, true)
108-
val configuration =
109-
Configuration(
110-
enableFatalIssueReporting = fatalIssueReporterEnabled,
111-
enableNativeCrashReporting = fatalIssueReporterEnabled,
112-
)
113-
BitdriftInit.initBitdriftCaptureInJava(
114-
apiUrl,
115-
sharedPreferences.getString(BITDRIFT_API_KEY, ""),
116-
getSessionStrategy(),
117-
configuration,
118-
this,
119-
)
120-
// Timber
121-
if (BuildConfig.DEBUG) {
122-
Timber.plant(Timber.DebugTree())
96+
if (BitdriftInit.initFromPreferences(sharedPreferences, this)) {
97+
// Timber
98+
if (BuildConfig.DEBUG) {
99+
Timber.plant(Timber.DebugTree())
100+
}
101+
Timber.plant(CaptureTree())
102+
Timber.i("Bitdrift Logger initialized with session_url=$sessionUrl")
123103
}
124-
Timber.plant(CaptureTree())
125-
Timber.i("Bitdrift Logger initialized with session_url=$sessionUrl")
126104
}
127105

128-
private fun getSessionStrategy(): SessionStrategy =
129-
if (sharedPreferences.getString(SESSION_STRATEGY_PREFS_KEY, FIXED.displayName) == "Fixed") {
130-
SessionStrategy.Fixed()
131-
} else {
132-
SessionStrategy.ActivityBased(
133-
inactivityThresholdMins = 60L,
134-
onSessionIdChanged = { sessionId ->
135-
Timber.i("Bitdrift Logger session id updated: $sessionId")
136-
},
137-
)
138-
}
139-
140106
private fun trackAppLaunch() {
141107
// ApplicationStartInfo
142108
if (Build.VERSION.SDK_INT >= 35) {

0 commit comments

Comments
 (0)