Cannot access Compose in the androidApp module of my KMP project


I am new to Kotlin Multiplatform and I am getting started on Android Studio Rabbit 1. I created a new project, selected KMP Application and started like this. There are now a lot of different build.gradle files, a file for each module like ios and android, so I though maybe I needed to add a dependency somewhere, but i didn't changed anything yet.

Now i would like to start building my UI. In most examples that I found they used Jetpack Compose to create a Compose View in androidApp. But this is where I'm stuck because inside this I don't have the Compose dependency so I can't do anything, not even build a simple Compose Column. This is in contrast to commonMain where there is the file App.kt where I do have access to composables.

I also noted that the way the folders are displayed has changed recently so I would like to know where I should build the Compose UI for the androidApp.

1
Oct 9 at 1:41 PM
User AvatarXCarb
#android#kotlin#gradle#kotlin-multiplatform#compose-multiplatform

Accepted Answer

In the past there was a lot of contradictory information about how to best create a KMP app. By now this is consolidated in the Kotlin Multiplatform Plugin for Android Studio and IntelliJ IDEA, which is the recommended way to create a new KMP app now. I'm not entirely sure if that is what you used, but you should use it. The issue you described won't occur here.

With the installed plugin you can select the template "Kotlin Multiplatform" in the "New Project" wizard:

Using Android Studio, the resulting project structure<sup>1</sup> will be displayed like this:

Please note that this is not a direct one-to-one representation of the directory structure on the file system. Some less relevant parts are left out and others are conflated to make it more clear. You can always switch from the "Android" view to the "Project" view to see the structure on the file system.

Now, on the top level you have the following:

  • app - contains the actual app. That includes the entry points for the ui-based targets and any shared (UI) code.
  • core - contains code that should be shared between all targets (including the server), irregardless of the UI framework chosen. So no Compose code here.
  • server - entry point for the server component and code that is specific to the server only.

You'll notice that app has no entry point for the iosApp. Although it is there on the file system, it is largely irrelevant here because it only contains Swift code that needs to be opened using Apple's Xcode IDE.

You shouldn't place your UI code in the entry point modules androidApp, desktopApp and webApp directly, they should only contain the code that is required to actually launch your app. The shared module is where the actual app should be built, because most of will be common to all entry points.

When you need to provide platform-specific UI code at one point or another you should use the followong sub modules for that:

  • iosArm64Mains
  • iosMain
  • iosSimulatorArm64Main
  • jsMain
  • jvmMain
  • wasmJsMain
  • kotlin (which is a re-labeled androidMain)

They are only implicitly related to the entry points. Instead, they are explicitly associated with the compilation target used by the Kotlin compiler. The suffix Main is meant to distinguish these modules from Test modules that would live alongside them, had we selected to create test modules as well during project setup.

commonMain, however, contains all code that is not platform-specific. This is where the majority of your Compose code will be located. When you open it you'll find an example App composable there already, the root composable containing the entire UI. You can build your own app from here.

Android specific composables need to be placed in androidMain (just displayed as "kotlin" as explained above), not androidApp. You do not need to add any additional dependencies, you'll directly have access to Jetpack Compose here, including the Android-specific parts that are not part of Compose Multiplatform.

Eventually you need to call platform-specific code from commonMain. The easiest way to do that is by following the expect/actual pattern also showcased in the example code.


<sup><sup>1</sup> With the (current, at the time of writing) Kotlin Multiplatform Plugin version 262.9437.133-AS, assuming you selected all build targets, Shared UI and omitted tests.</sup>

User Avatartyg
Oct 9 at 4:00 PM
0