Exploring the Kotlin Multiplatform Wizard
Start your multi-platform development journey with the Kotlin Multiplatform Wizard and unleash the potential of building applications for mobile, desktop, and server from a single code base.
This blog post examines the capabilities of the new Kotlin Multiplatform Wizard in detail and provides an in-depth look at the possibilities and functionality it offers.
Introduction
I recently received an email about the latest Compose Multiplatform release. The email introduced Compose Multiplatform 1.5.10 and the subject line, “The Perfect Time To Get Started,” piqued my interest.
In the past, I set up Compose Multiplatform for Kotlin Multiplatform in mobile projects. That process involved several steps and considerable effort. However, I never had the opportunity to explore the Desktop or Server aspects of Kotlin Multiplatform.
So I was excited to create a Kotlin Multiplatform (KMP) project with the Kotlin Multiplatform Wizard. The wizard seemed like a great tool to streamline the process and simplify getting started with KMP development.
I wanted a project that included:
- Android and iOS with a shared Compose UI,
- a desktop app,
- and a server app.
The web application support wasn’t available yet, so I had to be patient there.

After clicking “DOWNLOAD,” I opened the project in Android Studio.

Android Studio initially shows the “Android” view; I prefer the “Project” view.

Android
I ran the Android app for the first time with no issues by selecting the “composeApp” configuration.

No surprises— after building and starting the app, we see a simple “Hello World!” application.

iOS
Next, I tried iOS. It still feels odd to launch an iOS app from Android Studio…

Unfortunately, it did not work initially.
/bin/sh -c /Users/tobiaswissmuller/Desktop/KotlinProject/build/ios/iosApp.build/Debug-iphonesimulator/iosApp.build/Script-F36B1CEB2AD83DDC00CB74D5.sh
** BUILD FAILED **
The following build commands failed:
PhaseScriptExecution Compile\ Kotlin\ Framework /Users/tobiaswissmuller/Desktop/KotlinProject/build/ios/iosApp.build/Debug-iphonesimulator/iosApp.build/Script-F36B1CEB2AD83DDC00CB74D5.sh (in target 'iosApp' from project 'iosApp')
(1 failure)
/Users/tobiaswissmuller/Desktop/KotlinProject/build/ios/iosApp.build/Debug-iphonesimulator/iosApp.build/Script-F36B1CEB2AD83DDC00CB74D5.sh: line 7:./gradlew: Permission denied
Command PhaseScriptExecution failed with a nonzero exit codeThe fix was simple: make gradlew executable.
$ cd /Users/tobiaswissmuller/Desktop/KotlinProject
$ chmod +x gradlewAfter that, the iOS “Hello World!” app compiled and launched.

Desktop
Now for something completely new to me in KMP: launching a desktop app. This app can run on macOS, Windows, or Linux.
To compile and launch the desktop application, click the green “Play” icon next to the main function in composeApp/src/desktopMain/kotlin.

…or so the documentation said.
This time I encountered an error:
Cannot locate tasks that match ':composeApp:compileJava' as task 'compileJava' is ambiguous in project ':composeApp'. Candidates are: 'compileDebugAndroidTestJavaWithJavac', 'compileDebugJavaWithJavac', 'compileDebugUnitTestJavaWithJavac', 'compileReleaseJavaWithJavac', 'compileReleaseUnitTestJavaWithJavac'.This is a known issue with a workaround. See more details here.
Open a terminal in the project root and run the Gradle task directly:
$./gradlew:composeApp:runThat launched another “Hello World!”— the desktop variant.

Server
Finally, the server application.
Like the desktop app, you can press the green play button next to the main function— this time in server/src/main/kotlin/com.ramus.kmp/Application.kt.

This produced the following error message:
"/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java" -javaagent:/Applications/Android Studio.app/Contents/lib/idea_rt.jar=52601:/Applications/Android Studio.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-server-netty-jvm/2.3.6/dd89a079ea09ecc3ebf3d1d647ae8e16f0c4ebdb/ktor-server-netty-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-server-core-jvm/2.3.6/42724e1cd2883bc1d1867b67d2dff708836a84fc/ktor-server-core-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.9.20/e58b4816ac517e9cc5df1db051120c63d4cde669/kotlin-stdlib-1.9.20.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.4.11/54450c0c783e896a1a6d88c043bd2f1daba1c382/logback-classic-1.4.11.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.8.22/b25c86d47d6b962b9cf0f8c3f320c8a10eea3dd1/kotlin-stdlib-jdk8-1.8.22.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.8.22/4dabb8248310d833bb6a8b516024a91fd3d275c/kotlin-stdlib-jdk7-1.8.22.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-jdk8/1.7.1/31b0f471577d3c228d331fde355e14ccb071c90a/kotlinx-coroutines-jdk8-1.7.1.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/2.0.7/41eb7184ea9d556f23e18b5cb99cad1f8581fc00/slf4j-api-2.0.7.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-codec-http2/4.1.97.Final/893888d09a7bef0d0ba973d7471943e765d0fd08/netty-codec-http2-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.eclipse.jetty.alpn/alpn-api/1.1.3.v20160715/a1bf3a937f91b4c953acd13e8c9552347adc2198/alpn-api-1.1.3.v20160715.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-transport-native-kqueue/4.1.97.Final/68268a71eb3061068a3c082ab1ecf77bee73b3a7/netty-transport-native-kqueue-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-transport-native-epoll/4.1.97.Final/d569aa0dbbe7bccac689a69ca2a15c7eae2bc619/netty-transport-native-epoll-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-reflect/1.8.22/b52be44bc57cb6fd2169a29aefa4507c4e49c858/kotlin-reflect-1.8.22.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/com.typesafe/config/1.4.2/4c40a633e7994cfb0354244efb6d03fcb11c3ecf/config-1.4.2.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/23.0.0/8cc20c07506ec18e0834947b84a864bfc094484e/annotations-23.0.0.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-core/1.4.11/2f9f280219a9922a74200eaf7138c4c17fb87c0f/logback-core-1.4.11.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-server-host-common-jvm/2.3.6/9d59f7198bb61a0873ddc91e5546715344622307/ktor-server-host-common-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core-jvm/1.7.1/63a0779cf668e2a47d13fda7c3b0c4f8dc7762f4/kotlinx-coroutines-core-jvm-1.7.1.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-codec-http/4.1.97.Final/af78acec783ffd77c63d8aeecc21041fd39ac54f/netty-codec-http-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-handler/4.1.97.Final/abb86c6906bf512bf2b797a41cd7d2e8d3cd7c36/netty-handler-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-codec/4.1.97.Final/384ba4d75670befbedb45c4d3b497a93639c206d/netty-codec-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-transport/4.1.97.Final/f37380d23c9bb079bc702910833b2fd532c9abd0/netty-transport-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-buffer/4.1.97.Final/f8f3d8644afa5e6e1a40a3a6aeb9d9aa970ecb4f/netty-buffer-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-common/4.1.97.Final/7cceacaf11df8dc63f23d0fb58e9d4640fc88404/netty-common-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-transport-classes-kqueue/4.1.97.Final/29be6504ec6d9f5a173dfe562196998b2b365502/netty-transport-classes-kqueue-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-transport-native-unix-common/4.1.97.Final/d469d84265ab70095b01b40886cabdd433b6e664/netty-transport-native-unix-common-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-transport-classes-epoll/4.1.97.Final/795da37ded759e862457a82d9d92c4d39ce8ecee/netty-transport-classes-epoll-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-serialization-jvm/2.3.6/578d35a2dcc790fa0fcfb2f88c9a7fce98483ae5/ktor-serialization-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-events-jvm/2.3.6/7361b04c85d908d618848cf48851b92ece5e59ab/ktor-events-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-http-jvm/2.3.6/550659a94f8b9ce66c27cef5eddd599cd96443a8/ktor-http-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-utils-jvm/2.3.6/5deb03c1ee8ba69b200951c27358e0b812cb073e/ktor-utils-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.netty/netty-resolver/4.1.97.Final/cec8348108dc76c47cf87c669d514be52c922144/netty-resolver-4.1.97.Final.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-websockets-jvm/2.3.6/2445e00903b2d5ff718d2204ae454ed169ea6a6c/ktor-websockets-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-http-cio-jvm/2.3.6/562d00ab9b583e2251b297095784c317a56b7a75/ktor-http-cio-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-io-jvm/2.3.6/4b8aa5850072fa773ddd80104e5353e1325d2b6a/ktor-io-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-network-jvm/2.3.6/23ab56a7a6d3c6b1a32ccaf5a15ba8f9eda4916/ktor-network-jvm-2.3.6.jar:/Users/tobiaswissmuller/.gradle/caches/modules-2/files-2.1/org.fusesource.jansi/jansi/2.4.0/321c614f85f1dea6bb08c1817c60d53b7f3552fd/jansi-2.4.0.jar com.ramus.kmp.ApplicationKt
Error: Could not find or load main class com.ramus.kmp.ApplicationKt
Caused by: java.lang.ClassNotFoundException: com.ramus.kmp.ApplicationKt
Process finished with exit code 1To build the necessary files, run Build / Rebuild Project.

After that, I pressed the play button again, opened my browser, and navigated to http://localhost:8080/, which brought up the following screen:

Conclusion
The announcement for the new Compose Multiplatform delivered on its promises, despite a few hiccups. Jump-starting a KMP project has never been easier.
If you have any further questions, need specific code examples, or require additional assistance, please leave a comment or send me a message.
Thank you for reading!