Jetpack Compose
A complete Compose app with an application-scoped AirStrings instance, reactive string collection, and ICU plural formatting.
A minimal but complete Android app using the AirStrings Android SDK with Jetpack Compose. One application-scoped instance, provided to the composition tree, collected reactively in composables. For every configuration field in detail, see the Android SDK reference.
Strings used in this example
| Key | Format | Value |
|---|---|---|
home.welcome_title | text | Welcome! |
home.items_count | icu | {count, plural, one {# item} other {# items}} |
Add the dependencies
The SDK is distributed via JitPack. In settings.gradle.kts:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven("https://jitpack.io")
}
}In your module's build.gradle.kts, add the SDK and the lifecycle-aware Compose collector:
dependencies {
implementation("com.github.symbionix-sl:airstrings-sdk-android:v1.1.1")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
}Create the instance in your Application
AirStrings.create is application-scoped: it lives for the process lifetime, loads the cache immediately, and refreshes in the background and on foreground return.
import android.app.Application
import com.airstrings.sdk.AirStrings
import com.airstrings.sdk.AirStringsConfiguration
class DemoApplication : Application() {
lateinit var airStrings: AirStrings
private set
override fun onCreate() {
super.onCreate()
airStrings = AirStrings.create(
this,
AirStringsConfiguration(
organizationId = "org_...",
projectId = "proj_...",
environmentId = "env_...",
publicKeys = listOf("pk_..."),
),
)
}
}Register it in AndroidManifest.xml with android:name=".DemoApplication" on the application element.
Provide it to the composition
Provide the instance once at the root with CompositionLocalProvider, then any composable can reach it through LocalAirStrings.
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.CompositionLocalProvider
import com.airstrings.sdk.compose.LocalAirStrings
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val airStrings = (application as DemoApplication).airStrings
setContent {
CompositionLocalProvider(LocalAirStrings provides airStrings) {
WelcomeScreen()
}
}
}
}Collect and render
Collect the strings StateFlow with collectAsStateWithLifecycle() for reactive reads, and use format() for ICU plurals.
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.airstrings.sdk.compose.LocalAirStrings
@Composable
fun WelcomeScreen() {
val airStrings = LocalAirStrings.current
val strings by airStrings.strings.collectAsStateWithLifecycle()
Column {
Text(strings["home.welcome_title"] ?: "home.welcome_title")
Text(airStrings.format("home.items_count", mapOf("count" to 5)))
}
}Gotcha: subscript access (airStrings["key"]) reads strings.value synchronously and does not trigger recomposition. In Compose, always collect the strings StateFlow via collectAsStateWithLifecycle() so your UI updates when a new bundle lands. Subscript access is for non-Compose code: ViewModels, services, one-shot reads.