Kotlin Multiplatform, Compose Multiplatform and Flutter
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. See the section bibliography for the reference material consulted while preparing these pages. |
Baseline date: 2026-10-07. This page is shorter than the platform pages, because the multiplatform tools reuse their APIs. The Kotlin Multiplatform section is at Kotlin Multiplatform, and the native details are in Android and iOS.
Coil 3 in Compose Multiplatform
Coil 3 is a Kotlin Multiplatform library: the same AsyncImage runs on Android, iOS, desktop and web in commonMain. A
network fetcher artifact is required for each target (coil-network-ktor3 is the multiplatform choice, and
coil-network-okhttp is Android and JVM only).
// commonMain
dependencies {
implementation("io.coil-kt.coil3:coil-compose:3.6.3")
implementation("io.coil-kt.coil3:coil-network-ktor3:3.6.3")
}
// plus one Ktor engine per platform: ktor-client-okhttp (Android), ktor-client-darwin (iOS), ktor-client-cio (desktop)
@Composable
fun Cover(url: String, blurhash: String?) {
AsyncImage(
model = url,
contentDescription = null,
placeholder = rememberBlurHashPainter(blurhash), // from the KMP BlurHash library, below
contentScale = ContentScale.Crop,
modifier = Modifier.aspectRatio(2f / 3f),
)
}
Cache sizes and the loader are configured with SingletonImageLoader.setSafe in common code or the platform entry
points, see Coil getting started. Format support follows the platform:
Skia decodes JPEG, PNG and WebP, and AVIF depends on the Skia build and the platform version, so serve WebP or JPEG when
you are unsure.
BlurHash in Kotlin Multiplatform
vanniktech/blurhash (Maven Central, 0.3.0) decodes and encodes BlurHash in
common code, and converts the result to a Compose ImageBitmap. Check its README for the exact functions in the version you
install, then wrap the call in a remember:
@Composable
fun rememberBlurHashPainter(hash: String?): Painter? = remember(hash) {
hash?.let { decodeBlurHashToImageBitmap(it, 32, 32) }?.let { BitmapPainter(it) } // your wrapper over the library call
}
The algorithm is in the BlurHash page. A fully shared decoder avoids keeping separate Kotlin and Swift copies of the woltapp files.
Video with expect and actual
There is no shared multiplatform video player in the Compose Multiplatform core. The usual pattern is an expect composable
with an actual per platform, each wrapping the native player:
// commonMain
@Composable
expect fun VideoPlayer(url: String, modifier: Modifier = Modifier)
// androidMain: Media3 ExoPlayer inside AndroidView, see the Media3 page
@Composable
actual fun VideoPlayer(url: String, modifier: Modifier) { /* AndroidView { PlayerView(it).apply { player = exoPlayer } } */ }
// iosMain: AVPlayerViewController inside UIKitViewController, see the AVFoundation page
@Composable
actual fun VideoPlayer(url: String, modifier: Modifier) { /* UIKitViewController(factory = { AVPlayerViewController() }) */ }
Both platforms play HLS natively, so one backend manifest serves both, see Media3 and AVFoundation. Libraries that provide a ready-made multiplatform player exist (search the KMP library index), so check their maintenance status first.
Flutter
Flutter has the same needs and equivalent packages:
-
cached_network_image shows a network image with a placeholder and a fade-in, backed by a disk cache and a memory cache. Use
memCacheWidthto decode at the displayed size. -
flutter_blurhash:
BlurHash(hash: hash, image: url)shows the hash while the image loads, and can also be used as theplaceholderofCachedNetworkImage. -
video_player plays HLS through ExoPlayer and AVPlayer.
CachedNetworkImage(
imageUrl: url,
memCacheWidth: 640,
placeholder: (context, url) => BlurHash(hash: blurhash),
fit: BoxFit.cover,
)
Choose the variant by the logical size times the device pixel ratio, as in the other platform pages.