Hi all, I have multi module kmm project that support the following four targets - iOS - Android - JV...
m
Hi all, I have multi module kmm project that support the following four targets • iOS • Android • JVM • JS Some of these modules depend on each other ex: Module A doesn’t have any dependencies Module B depend on Module A and a pod project for the iOS Module C depend on Module B Now, Module C will contains all the dependencies that Module B have along with the pod project. Is there is a way not to include all Module B dependencies inside module C?
u
Did you try
api
instead of
implements
m
Yes, I’m using
api
not
implementation
u
As in all dependencies in C that are meant for B are declared as
api
? B/build.gradle: api(project(“:A”)) api(pod(… ``````
m
I’m not following. You can’t add pod file in the list of dependencies
Copy code
iOSMain by getting {
    dependencies {
        implementation(pod("")) // this won't work
    }
}
How we import pod project is using the following
Copy code
cocoapods {
    pod("POD NAME HERE", "POD VERSION HERE")
}
then it is available on the iOS target But if you are talking about Module C dependencies, it is all added as
api(project(":MODULE NAME"))
k
Is there is a way not to include all Module B dependencies inside module C?
This is pretty confusing. It would be easier to understand if you post the build configs associated. I assume you need Module B’s dependencies in C, or C wouldn’t work, so are you asking how not to export them?
m
@kpgalligan Module A
Copy code
plugins {
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    id("com.android.library")
}

kotlin {
    android()
    jvm()
    if (os.isMacOsX) {
        ios()
        if (System.getProperty("os.arch") != "x86_64") { // M1Chip
            iosSimulatorArm64()
        }
    }
    js(IR)

    if (os.isMacOsX) {
        cocoapods {
            this.summary = "ModuleA summary"
            this.version = rootProject.version.toString()
            this.ios.deploymentTarget = "13.0"
            this.osx.deploymentTarget = "12.0"
            this.tvos.deploymentTarget = "13.0"
            this.watchos.deploymentTarget = "8.0"
            framework {
                this.baseName = "ModuleA"
            }
        }
    }

    sourceSets {
        val commonMain by getting
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val jvmMain by getting
        val jvmTest by getting
        val androidMain by getting
        val androidTest by getting {
            dependencies {
                implementation("junit:junit:4.13.2")
            }
        }
        val jsMain by getting
        val jsTest by getting
        if (os.isMacOsX) {
            val iosMain by getting
            val iosTest by getting
            if (System.getProperty("os.arch") != "x86_64") { // M1Chip
                val iosSimulatorArm64Main by getting {
                    this.dependsOn(iosMain)
                }
                val iosSimulatorArm64Test by getting {
                    this.dependsOn(iosTest)
                }
            }
        }
    }
}

android {
    compileSdk = 32
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 21
        targetSdk = 32
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    /**
     * Because Software Components will not be created automatically for Maven publishing from
     * Android Gradle Plugin 8.0. To opt-in to the future behavior, set the Gradle property android.
     * disableAutomaticComponentCreation=true in the `gradle.properties` file or use the new
     * publishing DSL.
     */
    publishing {
        multipleVariants {
            withSourcesJar()
            withJavadocJar()
            allVariants()
        }
    }
}
Module B
Copy code
plugins {
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    id("com.android.library")
}

kotlin {
    android()
    jvm()
    if (os.isMacOsX) {
        ios()
        if (System.getProperty("os.arch") != "x86_64") { // M1Chip
            iosSimulatorArm64()
        }
    }
    js(IR)

    if (os.isMacOsX) {
        cocoapods {
            this.summary = "ModuleB summary"
            this.version = rootProject.version.toString()
            this.ios.deploymentTarget = "13.0"
            this.osx.deploymentTarget = "12.0"
            this.tvos.deploymentTarget = "13.0"
            this.watchos.deploymentTarget = "8.0"
            framework {
                this.baseName = "ModuleB"
            }
            pod("LOCAL POD") {
                version = "1.0.0"
                source = path(project.file("../iOSLibs/POD FOLDER NAME"))
            }
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                api(project(":ModuleA"))
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val jvmMain by getting
        val jvmTest by getting
        val androidMain by getting
        val androidTest by getting {
            dependencies {
                implementation("junit:junit:4.13.2")
            }
        }
        val jsMain by getting
        val jsTest by getting
        if (os.isMacOsX) {
            val iosMain by getting
            val iosTest by getting
            if (System.getProperty("os.arch") != "x86_64") { // M1Chip
                val iosSimulatorArm64Main by getting {
                    this.dependsOn(iosMain)
                }
                val iosSimulatorArm64Test by getting {
                    this.dependsOn(iosTest)
                }
            }
        }
    }
}

android {
    compileSdk = 32
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 21
        targetSdk = 32
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    /**
     * Because Software Components will not be created automatically for Maven publishing from
     * Android Gradle Plugin 8.0. To opt-in to the future behavior, set the Gradle property android.
     * disableAutomaticComponentCreation=true in the `gradle.properties` file or use the new
     * publishing DSL.
     */
    publishing {
        multipleVariants {
            withSourcesJar()
            withJavadocJar()
            allVariants()
        }
    }
}
Module C
Copy code
plugins {
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    id("com.android.library")
}

kotlin {
    android()
    jvm()
    if (os.isMacOsX) {
        ios()
        if (System.getProperty("os.arch") != "x86_64") { // M1Chip
            iosSimulatorArm64()
        }
    }
    js(IR)

    if (os.isMacOsX) {
        cocoapods {
            this.summary = "ModuleC summary"
            this.version = rootProject.version.toString()
            this.ios.deploymentTarget = "13.0"
            this.osx.deploymentTarget = "12.0"
            this.tvos.deploymentTarget = "13.0"
            this.watchos.deploymentTarget = "8.0"
            framework {
                this.baseName = "ModuleC"
            }
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                api(project(":ModuleB"))
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val jvmMain by getting
        val jvmTest by getting
        val androidMain by getting
        val androidTest by getting {
            dependencies {
                implementation("junit:junit:4.13.2")
            }
        }
        val jsMain by getting
        val jsTest by getting
        if (os.isMacOsX) {
            val iosMain by getting
            val iosTest by getting
            if (System.getProperty("os.arch") != "x86_64") { // M1Chip
                val iosSimulatorArm64Main by getting {
                    this.dependsOn(iosMain)
                }
                val iosSimulatorArm64Test by getting {
                    this.dependsOn(iosTest)
                }
            }
        }
    }
}

android {
    compileSdk = 32
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 21
        targetSdk = 32
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    /**
     * Because Software Components will not be created automatically for Maven publishing from
     * Android Gradle Plugin 8.0. To opt-in to the future behavior, set the Gradle property android.
     * disableAutomaticComponentCreation=true in the `gradle.properties` file or use the new
     * publishing DSL.
     */
    publishing {
        multipleVariants {
            withSourcesJar()
            withJavadocJar()
            allVariants()
        }
    }
}
Using the previous
build.gradle.kts
scripts I get Module A imported in Module C and I get the imported pod in Module B inside Module C ex: com.moduleA is now available in Module C And cocoapods.localPod is now available in Module C I don’t want that.
k
I’m not sure it’ll solve anything, but why are they api dependencies?
m
Was just testing 😅
k
I would not have them as api. I don’t know if you can “hide” a module dependency from a downstream module, but I haven’t personally tried to hard to do that.
m
Well the downstream dependency is causing me this issue => https://kotlinlang.slack.com/archives/C3SGXARS6/p1671116797868829 And to be honest I’m completely lost
k
That’s a linker error. What’s
TtC10ModuleAKMMFunctions
and where is it? Do you have a local pod because you’re trying to include some Objc code?
m
The pod is a local pod on my machine and I’m importing it
KMMFunctions
is a class name with some functions that I’m using inside KMM. Both the class and functions have the
@objc
annotation
k
You’re using a local pod to build your Swift
@objc
, then? I mean, the basic problem is cinterop looks like it imports the headers, but the pod setup isn’t providing the binary. I would guess that’s because it’s a local pod. I’ve never used a local pod as a dependency for cinterop, so I don’t know how that would work. You’ll probably need to add
Copy code
pod("LOCAL POD") {
        version = "1.0.0"
        source = path(project.file("../iOSLibs/POD FOLDER NAME"))
    }
to any downstream project you want to use it in, but you’ll need to make sure you change the cinterop package name, and you might have linker issues later (“symbols multiply defined”). Building local native source is rather difficult. cinterop just does headers, and as mentioned, I’ve never tried to use a local pod as a dependency.
m
Worth a try, gonna try it out and let you know how it went
When I added the pod one more time in the last module
Copy code
pod("ModuleA") {
    version = "1.0.0"
    source = path(project.file("../iOSLibs/ModuleA"))
}
as you said, it did give me the error “*symbol multiply defined*” so I changed the package name in the Gradle manually to this
Copy code
pod("ModuleA") {
    version = "1.0.0"
    packageName = "ModuleA1"
    source = path(project.file("../iOSLibs/ModuleA"))
}
This did fix the linker issue. Should this be considered a bug and an expected behaviour?!
k
Should this be considered a bug and an expected behaviour?!
No idea. I doubt they designed Kotlin pod dependencies for local pods like that, but that’s a JetBrains question.
m
Got you, thanks a lot for all the help 🤗
t
hey @Moussa I've been trying to add a local cocoapod dependency too, can you please share your local pod's folder structure and which change translated to
packageName = "ModuleA1"
for the above to work for you?
m
Hey @Tejeshwar Amirthy, I’m currently away from my laptop and will be back in a couple of hours. I will share with you a dummy KMM project that uses local dependency in Cocoapods for iOS
t
Would really appreciate that, thanks🙏
m
@Tejeshwar Amirthy sorry for being late. You can find a simple demo of that exact scenario in this demo repo => https://github.com/hamada147/kmp-demo And I’m here for any follow up questions 🤗
t
thanks @Moussa!
264 Views