Kotlin Multiplatform shares your code across platforms, but the iOS app still has to be compiled on macOS: Xcode builds the app, and its build phase calls Gradle to turn the shared module into a framework with Kotlin/Native. So a Windows or Linux team can write the iOS app but not build it. VibeView cloud builds run both toolchains for you. The CLI uploads your project source, the build runs in a clean environment, and the finished build lands next to your app, ready to run on a device you open in a browser tab.
This guide takes one Kotlin Multiplatform app from source to running builds on both platforms, then to a signed Android release. It works the same from Windows, Linux or macOS.
What you need
- A VibeView account and the CLI:
npm install -g vibeview && vibeview login. CLI 0.42.0 or later suggests the commands; on an older CLI, type them in when it asks. - A Kotlin Multiplatform project with the Gradle wrapper committed (
gradlewandgradle/wrapper/) and an Xcode project for the iOS app, such as the one the Kotlin Multiplatform wizard generates.
You don’t need Xcode, the Android SDK or a JDK locally. Every plan includes cloud builds each month; builds beyond your plan’s allowance draw from usage credit. The pricing page has each plan’s numbers.
Part 1: debug builds on cloud devices
-
Start the builds from your project root.
vibeview build --cloud --platform allThe first run asks for each platform’s build command and where the result lands, and saves the answers to
vibeview.json. For the wizard’s layout the CLI suggests:{ "defaultPlatform": "android", "platforms": { "android": { "build": { "command": "./gradlew :androidApp:assembleDebug", "artifact": "androidApp/build/outputs/apk/debug/*.apk" } }, "ios": { "build": { "command": "xcodebuild -project iosApp/iosApp.xcodeproj -scheme iosApp -configuration Debug -sdk iphonesimulator -derivedDataPath iosApp/build CODE_SIGNING_ALLOWED=NO", "artifact": "iosApp/build/Build/Products/Debug-iphonesimulator/*.app" } } } }The Android command builds the one module that applies the Android application plugin, whatever it’s called. The iOS command uses the Xcode project’s shared scheme, or its app target’s name when it doesn’t share one. When the CLI finds more than one of either, it asks you to enter the command instead.
-
Watch the logs. The CLI packs every file git tracks plus untracked files that
.gitignoredoesn’t exclude, uploads them, and streams each build’s output. Every iOS build downloads the Kotlin/Native compiler before it compiles, so it takes a few minutes longer than the Android one. Add--no-waitto start the builds and leave;vibeview builds logs <id> --followpicks one back up. -
Run them. A succeeded build lands in the app’s Build history with a
cloudbadge. If the project had no app yet, the build creates one from the binary (name, bundle id and icon included) and the CLI writes itsappIdintovibeview.json. Open the build’s page and choose Run this build to start it on a cloud iPhone or Android emulator.
You’ll know it worked when the build page shows added to app builds on its timeline and the app opens on the device. If the build page says the app runs only on some devices, check the iOS app’s minimum iOS version: a recent wizard project sets one that the oldest iOS simulators don’t run.
Which Java the builds use
Android builds run Gradle on Java 17 and have Java 21 installed beside it, so a jvmToolchain(17) or jvmToolchain(21) resolves without downloading anything. iOS builders have Java 21, which the Xcode build phase’s Gradle runs on. The Cloud Builds docs have the details, including how to run Gradle itself on Java 21.
Part 2: a signed .aab for Google Play
The release is a signed .aab for the store, not a build that runs on a VibeView device, so it lands on the Builds page with a Download action. For Kotlin Multiplatform it’s the Android app module’s own release task.
-
Get a keystore. Upload the one you have with
vibeview credentials add --platform android --file release.jks, or let VibeView make one withvibeview credentials generate --platform android --name release. -
Point Gradle at it. Add the Kotlin DSL signing block from App Signing to the end of the
android { }block inandroidApp/build.gradle.kts. VibeView sets the four properties it reads only during a production build, so your local builds keep working as before. -
Build the release.
vibeview build --cloud --production --platform androidThe first run offers
./gradlew :androidApp:bundleRelease, with the artifact atandroidApp/build/outputs/bundle/release/*.aab. Thenvibeview submit --platform android --latest --track internaluploads it to Google Play; the Android cloud build guide covers the one-time Play Console setup.
For iOS, a production build is your own xcodebuild archive command signed with your Apple credentials: see App Signing.
Troubleshooting
- The Android build fails with
exit code 127orPermission deniedon./gradlew. The Gradle wrapper isn’t committed, or lost its executable bit. Commitgradlewandgradle/wrapper/, and rungit update-index --chmod=+x gradlew. - The iOS build fails in the “Compile Kotlin Framework” phase. That’s Gradle compiling the shared module, so the error above it is a Kotlin one. Run your shared module’s Gradle build locally to reproduce it.
- An artifact isn’t found. Run
vibeview buildfrom the repository root, wheregradlewis. The artifact paths start there.
Frequently asked questions
Frequently asked questions
Can I build the iOS app of a Kotlin Multiplatform project without a Mac?
Yes. The iOS cloud build runs on a macOS builder with Xcode and Java installed, and the Xcode build runs Gradle for the shared module there. The simulator build opens on a cloud iPhone in your browser. You still need an Apple Developer account to sign and publish a production build.
Does it work with Compose Multiplatform?
Yes. The wizard’s Compose Multiplatform template builds and runs on both platforms with the commands above.
Next steps
- Kotlin Multiplatform cloud builds: what the builders have, what it costs and what it doesn’t do
- Cloud Builds, App Signing and Store Submission: the reference docs
- Build a native iOS app without a Mac, plus Android: the same path for a Swift or Kotlin app
- Build a React Native Android app in the cloud: Google Play setup and submission in more depth