Marco Milani

Android & IoT Developer

Home Projects Blog About Contact

Kotlin Multiplatform Jetpack Compose

Written on:

Sharing UIs across platforms.

Kotlin Multiplatform Jetpack Compose

  • Kotlin Multiplatform Jetpack Compose is a declarative framework for sharing user interfaces across multiple platforms.
  • It is based on Kotlin Multiplatform and Jetpack Compose, and is available for:
  • Android
  • Desktop
  • iOS (in beta)
  • Web (in alpha)
KMP Compose Platforms KMP Compose Logo

KMP Jetpack Compose - Why?

Challenges

KMP Jetpack Compose – ViewModel 1

Alternatives to familiar Android tools:

Using Moko MVVM

Add dependencies in commonMain:

commonMainApi("dev.icerock.moko:mvvm-core:0.16.1")
commonMainApi("dev.icerock.moko:mvvm-compose:0.16.1")
commonMainApi("dev.icerock.moko:mvvm-flow:0.16.1")
commonMainApi("dev.icerock.moko:mvvm-flow-compose:0.16.1")

Factory method for viewModels:

@Composable
fun <T : ViewModel> getViewModel(
    key: Any,
    factory: ViewModelFactory<T>
): T {
    return getViewModel(
       key = key,
       klass = factory.kClass,
       viewModelBlock = factory::createViewModel
    )
}

ViewModel Usage

homepageViewModel: HomepageViewModel = getViewModel(
  key = "homepage_view_model",
  factory = viewModelFactory {
     KoinHelper().getHomePageViewModel()
  }
)

getHomePageViewModel can be a common method or an expect function with platform-specific actual implementations.

fun getHomePageViewModel() : HomepageViewModel
actual fun getHomePageViewModel() : HomepageViewModel{
  return HomepageViewModel(get(), get())
}
actual fun getHomePageViewModel():HomepageViewModel{
  return get<HomepageViewModel>()
}

Image Loading: Coil & Kamel

Coil v3 supports multiplatform; Kamel is built specifically for Compose Multiplatform.

implementation("media.kamel:kamel-image:1.0.0")

Kamel Usage

KamelImage(
  resource = asyncPainterResource(data = url),
  contentDescription = contentDescription,
  contentScale= contentScale,
  modifier= modifier.fillMaxSize(),
  onFailure = {
     LoggerVisibility.Error.log("NetworkImage", "Error on loading image: $url")
  }
)

The resource parameter can be a URL, string, or file.

Firebase in KMP

GitLive is a project that provides Firebase support for KMP.

api("dev.gitlive:firebase-config:1.13.0")

After setup, use Firebase just as you would in Android:

val firebaseRemoteConfig = Firebase.remoteConfig
firebaseRemoteConfig.fetchAndActivate()

Navigation

implementation("org.jetbrains.androidx.navigation:navigation-compose:2.7.0-alpha07")

Configure NavHost as you would in Android Compose:

NavHost(
   navController = LocalNavController.current.navController,
   startDestination = NavigationRoute.HomePageScreen.uniqueName,
   modifier = Modifier.fillMaxSize()
){
   composable(route = NavigationRoute.HomePageScreen.uniqueName) {
      HomepageScreen()
   }
   composable(
     route = NavigationRoute.CharactersDetailScreen.uniqueName + NavigationRoute.CharactersDetailScreen.pathParam,
     arguments = listOf(navArgument("id"){type = NavType.IntType}),
     deepLinks = listOf(NavDeepLink(NavigationRoute.CharactersDetailScreen.deeplinkBase +
NavigationRoute.CharactersDetailScreen.uniqueName + NavigationRoute.CharactersDetailScreen.pathParam))
        ){
        it.arguments?.getInt("id")?.run {
            CharacterDetailScreen(this)
        }
   }
}

Pros & Cons

Pros

  • One Team
  • One codebase
  • Multiple apps with shared code
  • Ability to write native code anytime

Cons

  • Jetpack Compose is still in beta or alpha for some platforms
  • Many APIs are experimental and not yet production-ready