NewiPhone Duo, live in your browser. Try it →
Vibeview
Pricing
Cloud Builds · Kotlin Multiplatform

Build a Kotlin Multiplatform iOS app without a Mac

Rokas Kašinskas — Co-founder, VibeViewPublished 2026-10-16Updated 2026-10-16

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 (gradlew and gradle/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

  1. Start the builds from your project root.

    vibeview build --cloud --platform all

    The 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.

  2. Watch the logs. The CLI packs every file git tracks plus untracked files that .gitignore doesn’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-wait to start the builds and leave; vibeview builds logs <id> --follow picks one back up.

  3. Run them. A succeeded build lands in the app’s Build history with a cloud badge. If the project had no app yet, the build creates one from the binary (name, bundle id and icon included) and the CLI writes its appId into vibeview.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.

  1. Get a keystore. Upload the one you have with vibeview credentials add --platform android --file release.jks, or let VibeView make one with vibeview credentials generate --platform android --name release.

  2. Point Gradle at it. Add the Kotlin DSL signing block from App Signing to the end of the android { } block in androidApp/build.gradle.kts. VibeView sets the four properties it reads only during a production build, so your local builds keep working as before.

  3. Build the release.

    vibeview build --cloud --production --platform android

    The first run offers ./gradlew :androidApp:bundleRelease, with the artifact at androidApp/build/outputs/bundle/release/*.aab. Then vibeview submit --platform android --latest --track internal uploads 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 127 or Permission denied on ./gradlew. The Gradle wrapper isn’t committed, or lost its executable bit. Commit gradlew and gradle/wrapper/, and run git 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 build from the repository root, where gradlew is. 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

Try it yourself

Open a live iOS simulator or Android emulator in your browser.

Start free