Flagbearer for Android
The Kotlin SDK for Flagbearer, for Android apps. Requires Android 6.0 (API 23) or later and has no dependencies.
Server-side Kotlin uses the Java SDK instead.
Install
Gradle (Kotlin DSL):
dependencies {
implementation("dev.flagbearer:flagbearer-android:VERSION")
}Replace VERSION with the latest release, listed on
Maven Central.
Keys
Use a client key, which starts with fbc_. Client keys are public and safe to
include in an app. Server keys, which start with fbs_, are secret and belong
only on your server.
Set up one client
Create one client for the whole app, in your Application class:
import dev.flagbearer.android.Flagbearer
class App : Application() {
lateinit var flags: Flagbearer
override fun onCreate() {
super.onCreate()
flags = Flagbearer(this, clientKey = "fbc_...")
}
}Flags load in the background and are kept on the device, so the app starts with the flags each user last had, even offline.
While the app is in the foreground, a change you make in the dashboard reaches it within a couple of seconds, over a live connection. If that connection drops, the SDK checks every 30 seconds until it's back. After five minutes in the background it stops both, and catches up when the app returns.
Users
When the signed-in user is known or changes, call identify from a coroutine:
flags.identify(User(key = user.id, email = user.email))The email is optional. Include it to turn flags on for testers by email. After
sign-out, call identify(User()).
Checking a flag
if (flags.isEnabled("new-checkout")) {
showNewCheckout()
}isEnabled never waits and never throws. It returns false until the current
user's flags have loaded, and when the flag doesn't exist. Pass another default
as flags.isEnabled("new-checkout", defaultValue = true).
flags.status is FlagsStatus.LOADING until the current user's flags arrive.
Use it to hold back UI that mustn't switch between the default and the real
value.
Jetpack Compose
Read a flag as state, so the screen redraws when it changes:
@Composable
fun rememberFlag(flags: Flagbearer, key: String, defaultValue: Boolean = false): Boolean {
var enabled by remember(key) { mutableStateOf(flags.isEnabled(key, defaultValue)) }
DisposableEffect(key) {
val subscription = flags.subscribe { enabled = flags.isEnabled(key, defaultValue) }
onDispose { subscription.close() }
}
return enabled
}if (rememberFlag(flags, "new-checkout")) NewCheckout() else Checkout()subscribe calls its listener on the main thread whenever flags or status
change. Close what it returns to stop listening.
Error reports
allFlags() returns every flag's current value, so error reports show exactly
which flags were on. It doesn't count as checking them.
crashReporter.setContext("flags", flags.allFlags())
// {new-checkout=true, dark-mode=false}When something is wrong
The SDK never crashes or blocks the app over a flag problem. It keeps the last
flags, or defaults, and says what's wrong in Logcat under the Flagbearer tag:
- A key the server refuses is explained once, with the server's reason.
- A server key (
fbs_) is never sent. The log says to use a client key. - In debuggable builds, checking a flag that doesn't exist warns once per flag.
Pass debug = true to also log each fetch, and to get the missing-flag warning
in release builds.
Options
val flags = Flagbearer(
context = this,
clientKey = "fbc_...",
user = User(key = "42"), // the user at launch, if already known
debug = false,
appVersion = null, // defaults to the app's versionName
cacheFlags = true, // start with the flags this user last had
)