Kotlin SDK
Integrate the FlashAnalytics Kotlin SDK in native Android apps.
Use the Kotlin SDK for native Android apps when you want app lifecycle, screen tracking, deep links, notification lifecycle, native crash capture, caught error reporting, and experiment assignment in a native integration.
Install
dependencies {
implementation("app.flashanalytics:flashanalytics-kotlin:1.1.0")
}Application setup
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
FlashAnalyticsAndroid.init(
application = this,
options = FlashAnalyticsOptions(
appId = "YOUR_APP_ID",
endpoint = "https://api.flashanalytics.app",
captureAppLifecycle = true,
captureScreenViews = true,
captureDeepLinks = true,
capturePushLifecycle = true,
captureNativeCrashes = true,
captureVariants = CaptureVariantsOptions(
onAssignmentsChanged = { assignments ->
// called whenever the local cache changes
}
),
defaultNotificationTtlMs = 300_000L,
)
)
}
}Quick start
val analytics = FlashAnalyticsAndroid.getInstance()
analytics.track("app_opened")
CoroutineScope(Dispatchers.Main).launch {
val variant = analytics.assignExperiment("checkout-cta")
val assignments = analytics.autoAssignExperiments()
}
analytics.assignExperimentAsync("checkout-cta") { result ->
// handle result
}Experiments
Enable captureVariants to keep a local cache of assignments in sync automatically. On each new session all experiments are fetched; after identify() only profile-mode assignments are refreshed; on session expiry only session-mode entries are removed.
// All cached assignments — no API call
val all = analytics.getAllExperiments()
// Single experiment — checks cache first, falls back to API if not found (suspend)
val assignment = analytics.getExperimentById("checkout-cta")
println(assignment?.variantName)
// Callback wrapper for non-coroutine code
analytics.getExperimentByIdAsync("checkout-cta") { result ->
println(result?.variantName)
}
// Manual assignment (always calls the API)
CoroutineScope(Dispatchers.Main).launch {
val variant = analytics.assignExperiment("checkout-cta")
val assignments = analytics.autoAssignExperiments()
}
analytics.assignExperimentAsync("checkout-cta") { result ->
// handle result
}Auto capture
- App lifecycle via
captureAppLifecycle - Screen views via
captureScreenViews - Deep links via
captureDeepLinks - Native crashes via
captureNativeCrashesorcaptureErrors - Experiment auto-assignment via
captureVariants - Push lifecycle helpers via
capturePushLifecycle
Manual error tracking
try {
riskyOperation()
} catch (e: Exception) {
FlashAnalyticsAndroid.getInstance().trackError(
throwable = e,
eventName = "payment_failed",
properties = mapOf("orderId" to orderId),
)
}Notification lifecycle
The SDK supports delivered, opened, dismissed, action-clicked, and expired events. Android still needs receiver registration, notification intents, and payload forwarding from the host app.
val decision = analytics.handleIncomingNotificationLifecycle(
values = message.data + mapOf(
"notificationId" to notificationId,
"messageId" to messageId,
"provider" to "firebase",
),
source = "android_local_notification",
)
if (decision.shouldDisplayNotification) {
// build and show your notification
}analytics.trackNotificationEvent(
event = FlashNotificationEvent.OPENED,
intent = intent,
source = "android_intent",
appState = "terminated",
coldStart = true,
)Session access
val session = analytics.getSession()
println(session?.id)
println(session?.estimatedExpiresAt)
println(session?.estimatedTtlMs)