Search code examples
androidkotlingradlekotlin-multiplatform

Cannot create and build Kotlin Multiplatform Shared Module in existing Android codebase


I am trying to follow this tutorial for Android application works on iOS using Kotlin Multiplatform.

https://www.jetbrains.com/help/kotlin-multiplatform-dev/multiplatform-integrate-in-existing-app.html#make-your-code-cross-platform

Basically my goal is to reuse the business logic Kotlin code in existing Android code so our team can experiment on new iPhone user base.

However after I tried the step for adding new Kotlin Multiplatform Shared Module. It cannot compile.

The error is

Unresolved reference: libs

I tried comparing with the source code they provided.

https://github.com/Kotlin/kmm-integration-sample/tree/final

It seems that the Android Studio version and/or the Gradle version of the sample code is outdated.

My code of shared/build.gradle.kts is below

plugins {
    alias(libs.plugins.kotlinMultiplatform)
    alias(libs.plugins.androidLibrary)
}

kotlin {
    androidTarget {
        compilations.all {
            kotlinOptions {
                jvmTarget = "1.8"
            }
        }
    }
    
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "shared"
            isStatic = true
        }
    }

    sourceSets {
        commonMain.dependencies {
            //put your multiplatform dependencies here
        }
        commonTest.dependencies {
            implementation(libs.kotlin.test)
        }
    }
}

android {
    namespace = "net.petrabarus.poc.android.shared"
    compileSdk = 34
    defaultConfig {
        minSdk = 24
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
}

while the code of shared/build.gradle.kts in the sample code is below.

plugins {
    kotlin("multiplatform")
    id("com.android.library")
}

kotlin {
    android()
    
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "shared"
        }
    }

    sourceSets {
        val commonMain by getting
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val androidMain by getting
        val androidTest by getting
        val iosX64Main by getting
        val iosArm64Main by getting
        val iosSimulatorArm64Main by getting
        val iosMain by creating {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
            iosSimulatorArm64Main.dependsOn(this)
        }
        val iosX64Test by getting
        val iosArm64Test by getting
        val iosSimulatorArm64Test by getting
        val iosTest by creating {
            dependsOn(commonTest)
            iosX64Test.dependsOn(this)
            iosArm64Test.dependsOn(this)
            iosSimulatorArm64Test.dependsOn(this)
        }
    }
}

android {
    compileSdk = 31
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 21
        targetSdk = 31
    }
}

It seems that the newest one uses the shared dependency configuration from Gradle.

https://docs.gradle.org/current/userguide/platforms.html

I added this libs.versions.toml below from the KMM Project Wizard

https://kmp.jetbrains.com/

[versions]
agp = "8.2.0"
kotlin = "1.9.22"

[plugins]
androidLibrary = { id = "com.android.library", version.ref = "agp" }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }

The error is now like below


Error resolving plugin [id: 'org.jetbrains.kotlin.multiplatform', version: '1.9.22']
> The request for this plugin could not be satisfied because the plugin is already on the classpath with an unknown version, so compatibility cannot be checked.

This is the code

https://github.com/petrabarus/poc-android-export-kmm-module-to-maven/tree/add-shared

What did I do wrong, and how do I fix this?

The Android Studio I am using is below

Android Studio Hedgehog | 2023.1.1
Build #AI-231.9392.1.2311.11076708, built on November 9, 2023
Runtime version: 17.0.7+0-17.0.7b1000.6-10550314 aarch64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
macOS 14.2.1
GC: G1 Young Generation, G1 Old Generation
Memory: 1024M
Cores: 8
Metal Rendering is ON
Registry:
    external.system.auto.import.disabled=true
    ide.text.editor.with.preview.show.floating.toolbar=false

Non-Bundled Plugins:
    com.jetbrains.kmm (0.8.2(231)-25)
    org.jetbrains.compose.desktop.ide (1.6.0)


Solution

  • I tried to match the dependencies and version of the libraries from the shared/build.gradle.kts, root build.gradle.kts and libs.versions.toml

    // gradle/libs.versions.toml
    [versions]
    agp = "8.2.0"
    kotlin = "1.9.0"
    
    [plugins]
    androidLibrary = { id = "com.android.library", version.ref = "agp" }
    kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
    
    //build.gradle.kts
    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    plugins {
        id("com.android.library") version "8.2.0" apply false
        id("com.android.application") version "8.2.0" apply false
        id("org.jetbrains.kotlin.android") version "1.9.0" apply false
        id("org.jetbrains.kotlin.multiplatform") version "1.9.0" apply false
    }
    

    Now the error change to

    Build was configured to prefer settings repositories over project repositories but repository 'ivy' was added by build file 'shared/build.gradle.kts'
    

    The problem is in these lines

        listOf(
            iosX64(),
            iosArm64(),
            iosSimulatorArm64()
        ).forEach {
            it.binaries.framework {
                baseName = "shared"
                isStatic = true
            }
        }
    

    Finally I tried matching the settings.gradle.kts with the KMM Project Wizard.

    Previous is

    pluginManagement {
        repositories {
            google()
            mavenCentral()
            gradlePluginPortal()
        }
    }
    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            google()
            mavenCentral()
        }
    }
    

    Now is

    pluginManagement {
        repositories {
            maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
            google()
            mavenCentral()
            gradlePluginPortal()
        }
    }
    dependencyResolutionManagement {
        //repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            google()
            mavenCentral()
            maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
        }
    }
    

    The build runs! I am not sure why, but it runs!