Android SDK
Use Toggly's native Android SDK in Kotlin applications with Jetpack Compose or traditional Views.
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
| Module | Artifact | Description |
|---|---|---|
| Core | io.toggly:toggly-android-core | Core functionality, storage, and API client (required) |
| Compose | io.toggly:toggly-compose | Jetpack Compose composables and state |
| Views | io.toggly:toggly-views | Android Views, LiveData, and ViewModel support |
| Room | io.toggly:toggly-room | Room database storage adapter |
| DataStore | io.toggly:toggly-datastore | AndroidX 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
- Learn about Jetpack Compose Integration with composables and state
- Explore Views Support for traditional Android UI
- See Storage Options for different persistence strategies
- Read about Configuration options
- Check Advanced Usage for identity management and events