Ausblick
expect und actual
Gemeinsamer Code deklariert, die Plattformen liefern die Umsetzung
(Beispiel aus dem Wizard-Projekt, Tag kmp-00):
// commonMain
expect fun getPlatform(): Platform
// androidMain
actual fun getPlatform(): Platform = AndroidPlatform()
// iosMain
actual fun getPlatform(): Platform = IOSPlatform()Das Beispiel stammt aus dem Projekt, das der Wizard erzeugt
(kmp-00).
In der Wetter-App haben wir diese Dateien beim Übernehmen gelöscht.
AndroidPlatform liest die Android-Version über Build.VERSION.SDK_INT,
IOSPlatform die iOS-Version über UIDevice. In androidMain und
iosMain stehen also die nativen APIs der jeweiligen Plattform zur Verfügung.
So ließe sich zum Beispiel Dynamic Color zurückholen: unter Android die Farben aus dem Hintergrundbild, unter iOS die festen Farben.
Ressourcen
Bilder, Icons und Texte liegen in shared/src/commonMain/composeResources/
und werden über die generierte Klasse Res angesprochen:
Image(painterResource(Res.drawable.compose_multiplatform), null)Das ersetzt R.drawable… aus der Android-App. Auch dieses Beispiel
stammt aus dem Projekt des Wizards; in der Wetter-App haben wir den
Ordner beim Übernehmen gelöscht.
Bibliotheken
Vor dem Einbinden prüfen: Gibt es die Bibliothek für KMP?
- Ktor, kotlinx.serialization, Navigation 3, ViewModel: ja (haben wir benutzt)
- Room und DataStore: ja
- Retrofit, Gson: nein, nur Android bzw. JVM
Eine Sammlung von Bibliotheken für KMP: kmp-awesome . Für die Wetter-App war Ktor statt Retrofit deshalb die richtige Wahl.
Übungen
- Koordinaten in der Städteliste auf zwei Nachkommastellen runden
- Dynamic Color unter Android mit
expect/actual - Zurück-Pfeil in der
TopAppBarals Ressource incomposeResources - Stadtsuche, Vorhersage, Favoriten aus dem Android-Teil umsetzen
Hinweise:
- Runden:
String.formatgibt es in Common Kotlin nicht. Eine Möglichkeit:(value * 100).roundToInt() / 100.0(mit100.0, sonst rechnet Kotlin mit ganzen Zahlen). Aus 47,999 wird dann aber „48.0“ statt „48.00“; für genau zwei Nachkommastellen muss man auffüllen. - Dynamic Color: In
commonMainz. B.@Composable expect fun dynamicColorScheme(darkTheme: Boolean): ColorScheme?deklarieren. InandroidMainwie im ursprünglichen Theme mitLocalContextund der Prüfung auf Android 12 umsetzen, iniosMainnullzurückgeben. Das Theme nimmt danndynamicColorScheme(darkTheme) ?: if (darkTheme) DarkColorScheme else LightColorScheme. - Zurück-Pfeil: Den Ordner
shared/src/commonMain/composeResources/drawable/anlegen (beim Übernehmen gelöscht) und die Vector-XML von fonts.google.com/icons hineinlegen. Verweise auf Android-Ressourcen funktionieren hier nicht:android:tintentfernen undandroid:fillColorauf einen Farbwert wie#000000setzen (Anleitung ). Nach einem Build steht das Icon bereit, z. B. fürarrow_back.xml:painterResource(Res.drawable.arrow_back)in einemIconButton, wie im Android-Teil. Die Imports unterscheiden sich von Android:org.jetbrains.compose.resources.painterResourcesowieResundarrow_backausweatherkmptif24.shared.generated.resources. - Stadtsuche: Die Referenzlösung aus
schritt-11lässt sich wie in diesem Kapitel übernehmen. Ktor und die Geocoding-API funktionieren in KMP genauso. Anzupassen sind dieselben Stellen wie oben:viewModel { CityListViewModel() }stattviewModel()und kein"%.2f".format(…)in der Städteliste. - Favoriten: Room und DataStore funktionieren auch in KMP, siehe Room für KMP und das Codelab Room nach KMP migrieren . Ein Beispiel mit Room unter Android und iOS ist die Todo-App aus dem Vorjahr: TodosKMP2025 .