Skip to main content

Android SDK

Use Toggly's native Android SDK in Kotlin applications with Jetpack Compose or traditional Views.

Quick reference

Grab the printable Kotlin / Android cheat sheet (download PDF) — Compose composables, Views, ViewModel, storage options.

Overview​

The Android SDK is a modular feature flags solution built entirely in Kotlin with coroutines and Flow support. It provides Jetpack Compose composables, traditional View extensions, and multiple storage options.

Modules​

ModuleArtifactDescription
Coreio.toggly:toggly-android-coreCore functionality, storage, and API client (required)
Composeio.toggly:toggly-composeJetpack Compose composables and state
Viewsio.toggly:toggly-viewsAndroid Views, LiveData, and ViewModel support
Roomio.toggly:toggly-roomRoom database storage adapter
DataStoreio.toggly:toggly-datastoreAndroidX DataStore storage adapter

Requirements​

  • Android 7.0+ (API level 24+)
  • Kotlin 1.9+
  • Java 17+

Installation​

Add the dependencies to your build.gradle.kts:

dependencies {
// Core module (required)
implementation("io.toggly:toggly-android-core:1.0.0")

// UI modules (pick what you need)
implementation("io.toggly:toggly-compose:1.0.0") // Jetpack Compose
implementation("io.toggly:toggly-views:1.0.0") // Android Views

// Storage modules (pick one, or use built-in SharedPreferences)
implementation("io.toggly:toggly-room:1.0.0") // Room database
implementation("io.toggly:toggly-datastore:1.0.0") // DataStore
}

Quick Start​

Initialize the SDK​

import io.toggly.core.Toggly
import io.toggly.core.models.TogglyConfig
import io.toggly.core.storage.SharedPreferencesStorage

class MyApplication : Application() {
override fun onCreate() {
super.onCreate()

// Configure with your Toggly app key
Toggly.configure(
config = TogglyConfig(
appKey = "your-app-key",
environment = "Production"
),
storage = SharedPreferencesStorage(this)
)

// Initialize asynchronously
lifecycleScope.launch {
Toggly.shared.init()
}
}
}

Jetpack Compose Usage​

import io.toggly.compose.*

@Composable
fun MyScreen() {
// Use rememberFeatureFlag hook
val isNewDashboardEnabled by rememberFeatureFlag("new-dashboard")

if (isNewDashboardEnabled) {
NewDashboardScreen()
} else {
LegacyDashboardScreen()
}
}

// Or use Feature composable
@Composable
fun WelcomeSection() {
Feature("welcome-banner") {
WelcomeBanner()
}

// On and off with negate
Feature("beta-feature") {
BetaFeatureContent()
}
Feature("beta-feature", negate = true) {
StableFeatureContent()
}
}

// Feature gate with multiple features
@Composable
fun AdminSection() {
FeatureGate(
featureKeys = listOf("admin-access", "premium-features"),
requirement = FeatureRequirement.ALL
) {
AdminPanel()
}
}

Android Views Usage​

import io.toggly.views.*

class MyActivity : AppCompatActivity() {
private val viewModel: FeatureFlagViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// Bind view visibility to feature flag
newFeatureButton.bindToFeatureFlag(
featureKey = "new-feature",
lifecycleOwner = this
)

// Or use LiveData
viewModel.featureFlagLiveData("new-dashboard").observe(this) { isEnabled ->
newDashboardView.visibility = if (isEnabled) View.VISIBLE else View.GONE
}

// Toggle between two views
toggleViews(
featureKey = "new-checkout",
lifecycleOwner = this,
enabledView = newCheckoutView,
disabledView = legacyCheckoutView
)
}
}

Coroutines and Flow Usage​

import io.toggly.core.Toggly
import kotlinx.coroutines.flow.collect

class MyViewModel : ViewModel() {
private val toggly = Toggly.shared

init {
// Collect feature flag changes
viewModelScope.launch {
toggly.featureFlagFlow("my-feature").collect { isEnabled ->
_uiState.update { it.copy(featureEnabled = isEnabled) }
}
}
}

// Simple feature check
suspend fun checkFeature() {
val isEnabled = toggly.isFeatureOn("my-feature")
// Use the result
}

// Feature gate with multiple features
suspend fun checkAccess() {
val hasAccess = toggly.evaluateFeatureGate(
featureKeys = listOf("feature-a", "feature-b"),
requirement = FeatureRequirement.ALL
)
}
}

Configuration Options​

TogglyConfig(
appKey = "your-app-key",
baseUri = "https://definitions.toggly.io",
environment = "Production",
featureDefaults = mapOf(
"feature-a" to true,
"feature-b" to false
),
refreshInterval = 180_000L,
useSignedDefinitions = false, // ETag / If-None-Match on refresh
verifySignatures = false, // ES256 via JWKS (SignedDefsVerify)
maxSignatureAgeSeconds = null, // optional freshness window
enableLiveUpdates = true
)

Signed definitions details: Configuration → Signed definitions.

Storage Options​

SharedPreferences (Built-in)​

import io.toggly.core.storage.SharedPreferencesStorage

Toggly.configure(
config = config,
storage = SharedPreferencesStorage(context, "toggly_prefs")
)

Room Database​

import io.toggly.room.createRoomStorage

Toggly.configure(
config = config,
storage = createRoomStorage(context, "toggly.db")
)

DataStore​

import io.toggly.datastore.createDataStoreStorage

Toggly.configure(
config = config,
storage = createDataStoreStorage(context)
)

In-Memory (Testing)​

import io.toggly.core.storage.MemoryStorage

Toggly.configure(
config = config,
storage = MemoryStorage()
)

Entity context​

Pass the screen entity per evaluation — not via setIdentity. See Entity & page context.

Android is a client: local registerContext only.

Toggly.shared.registerContext("Order") { order: Order ->
TogglyEntityContext(
kind = "Order",
key = order.id.toString(),
attributes = mapOf("Status" to order.status),
)
}

val on = Toggly.shared.isFeatureEnabled("OrderBadge", context = order, kind = "Order")

Gates fail closed without context. Identity is user only.

Identity and Targeting​

Set user identity for targeted feature flags:

// Set identity
Toggly.shared.setIdentity("user-123")

// Clear identity
Toggly.shared.setIdentity(null)

Events​

Listen to SDK events:

viewModelScope.launch {
Toggly.shared.events.collect { event ->
when (event) {
is TogglyEvent.Initialized -> {
// SDK initialized with flags
}
is TogglyEvent.Refreshed -> {
// Flags refreshed from server
}
is TogglyEvent.Error -> {
// Handle error
Log.e("Toggly", "Error: ${event.error}")
}
is TogglyEvent.FeatureChanged -> {
// Feature flag changed
Log.d("Toggly", "${event.featureKey}: ${event.oldValue} -> ${event.newValue}")
}
// ... other events
}
}
}

Offline Support​

The SDK automatically caches feature flags for offline use. Choose a persistent storage option (SharedPreferences, Room, or DataStore) to enable offline support:

// Feature flags persist across app restarts
val storage = SharedPreferencesStorage(context)
Toggly.configure(config = config, storage = storage)

// Flags are available immediately from cache
val isEnabled = Toggly.shared.isFeatureOn("my-feature")

Local-Only Mode​

Use the SDK without connecting to Toggly.io:

val config = TogglyConfig(
appKey = "", // Empty app key for local-only mode
defaultFlags = mapOf(
"new-dashboard" to true,
"beta-feature" to false
)
)
Toggly.configure(config = config, storage = MemoryStorage())

Debug Information​

Get debug information about the SDK state:

val debugInfo = Toggly.shared.getDebugInfo()
Log.d("Toggly", "App Key: ${debugInfo.appKey}")
Log.d("Toggly", "Environment: ${debugInfo.environment}")
Log.d("Toggly", "Identity: ${debugInfo.identity}")
Log.d("Toggly", "Feature Flags: ${debugInfo.featureFlagCount}")

Next Steps​