Android (Kotlin)
io.splithub:splithub for Android: SplitHub.start in Application, variants and values, Jetpack Compose Experiment and TrackScreen, offline and QA.
io.splithub:splithub runs experiments and collects analytics in native Android apps. A visitor gets the same variant here as on your website, because assignment is the same hash as the web SDK. Read Apps first for what differs from the web.
The Android SDK is new. Min SDK 21; its only dependency is androidx.lifecycle:lifecycle-process, and it brings its own INTERNET permission.
Install
// app/build.gradle.kts
dependencies {
implementation("io.splithub:splithub:0.5.0")
// Optional: Jetpack Compose helpers
implementation("io.splithub:splithub-compose:0.5.0")
}
npx splithub init in a Gradle project prints these lines and a quick start. Native apps have no splithub.config.ts: experiments come from SplitHub Cloud.
Start
Once, in your Application:
class App : Application() {
override fun onCreate() {
super.onCreate()
SplitHub.start(this, "pk_live_...", property = "sh-x1h78w")
}
}
The key is your project's public key. The property is the analytics property for screens and events; leave it out to run experiments only.
Variants and events
val cta = SplitHub.variant("hero-cta") // "control", "bold", ...
val price = SplitHub.value("price") as? Map<*, *> // payload of a value experiment
SplitHub.screen("Settings") // a page view of /Settings
SplitHub.track("Video Played", mapOf("id" to 7)) // any event; a goal when marked as one
SplitHub.identify("user-42", mapOf("plan" to "pro"))
SplitHub.reset() // on log out
variant() and value() record an exposure once per variant per session. valueJson() gives the payload as JSON text for Gson, Moshi or kotlinx.serialization.
Compose
@Composable
fun Home() {
TrackScreen("Home")
Experiment("hero-cta") { variant ->
when (variant) {
"bold" -> Button(onClick = { SplitHub.track("signup") }) { Text("Start free") }
else -> Button(onClick = { SplitHub.track("signup") }) { Text("Sign up") }
}
}
val price = rememberValue("price")
}
Experiment records the exposure when the variant is shown and recomposes when variants change.
Good to know
- First launch. The app waits up to 400 ms for the experiments and shows the control meanwhile. Compose helpers update by themselves; in plain views, read variants in
SplitHub.whenReady { }. Later launches decide at once from the cached copy. - Changes in the dashboard reach the app on its next session, never in the middle of one.
- Offline. Events go out every 2 seconds and when the app goes to the background; offline, they wait on the device (up to 1,000).
- Sessions. The visitor id stays until
reset(). A new session starts after 30 minutes in the background. - Targeting. Flows can use
platform(android),app_version(at least / below), language, device (mobileortablet) and country. See Targeting flows.
QA
Force a variant on your own device. It's shown but never counted:
SplitHub.start(this, "pk_live_...", options = SplitHubOptions(forcedVariants = mapOf("hero-cta" to "bold"), debug = true))
debug = true logs every decision under the Logcat tag SplitHub.