Brua
Install
implementation("dev.brua:brua-android:0.1.0")
GitHub: Meginhufr/brua-kotlin

Android

A BruaImage composable for Jetpack Compose, and plain Kotlin models and selection for JVM backends. Android 7 (API 24) or later.

Two modules on Maven Central. dev.brua:brua is plain Kotlin for the JVM: the AssetResponse models, the variant selection rule and the request hints, for Android apps and Kotlin backends alike. dev.brua:brua-android adds the Android side: the BruaImage composable, the device's state and an OkHttp interceptor.

Install

Kotlin
implementation("dev.brua:brua-android:0.1.0")
implementation("io.coil-kt.coil3:coil-network-okhttp:3.6.3")   // or coil-network-ktor3: Coil needs one

A backend takes dev.brua:brua alone.

Point it at your organization

One client per app, with your organization's base URL on the edge and an OkHttp client with a cache. The examples use Brua's own organization; yours is on the Integrate page of the back office, or comes from the colleague who set Brua up.

Kotlin
import dev.brua.android.BruaClient

val brua = BruaClient("https://cdn.brua.dev/assets/991ceed8-a70e-4a5f-b3d3-e0b6b3d93e44", http = okHttpClientWithCache)
val asset = brua.asset("bridge")   // null when nothing is released under the id

With the cache, each asset is kept for the edge's minute, so a merge in Brua reaches the screen within that minute with no release of yours.

Render by id

Kotlin
import dev.brua.android.BruaImage

BruaImage(id = "bridge", client = brua, Modifier.fillMaxWidth())   // nothing until it has loaded

A snapshot your backend embedded in its own JSON decodes with kotlinx.serialization and renders the same way:

Kotlin
@Serializable
data class Campaign(val title: String, val hero: AssetResponse)

BruaImage(campaign.hero, Modifier.fillMaxWidth())

An app that switches themes itself passes the scheme:

Kotlin
BruaImage(id = "mark", client = brua, Modifier.size(28.dp), colorScheme = if (dark) ColorScheme.Dark else ColorScheme.Light)

For a notification, a widget or a custom loader, pick the variant yourself:

Kotlin
val url = VariantSelector.url(campaign.hero, ClientState(colorScheme = ColorScheme.Dark, scale = 3.0, targetWidth = 320.0))

What you get

  • Light and dark, the Remove animations setting and the display density, followed as they change.
  • The alt text as the TalkBack description; decorative assets are skipped.
  • Files through Coil's ImageLoader, or the one you pass as imageLoader. Android decodes AVIF from Android 12, and WebP, PNG and JPEG everywhere; AndroidClient.supportedTypes says which. SVG needs coil-svg; Lottie and Rive are rendered by their own libraries from the variant URLs.
  • Without a size, the asset's designed size in dp, shrunk to the width it gets.
  • A merge in Brua reaches the app within a minute, with no release of yours.

Next