JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
16.33k stars 1.18k forks source link

Multi Module app is Failed to Run when Generated as .aar used in other Native project #4492

Closed sureshmaidaragi1919 closed 2 months ago

sureshmaidaragi1919 commented 8 months ago

Describe the bug I have created the KMM multi module project as shown below

-- KmmUI -- KmmNetwork -- KmmCore -- kmmpwpitara (Shared)

When I generate .aar file by cmd ./gradlew pitaraShared:assemble, And use the generated .aar in Native Android app it showing file to find Module UI's imported file

Affected platforms

Versions

To Reproduce Steps and/or the code snippet to reproduce the behavior:

  1. Created Multi modular KMM projects targeting only Android and iOS
  2. Generated .aarfor Android and .framework by cmd ./gradlew pitaraShared:assemble
  3. Put the the generated file native android project under libs and implement in build.gradle.kts(app) file
  4. in Native Code try using the one of the function which calls KMM modules components/functions/class
  5. App results in below error

Expected behavior It should work in Multi module as well;

Screenshots

in below screen shot,kmmpwui/ui/widget/UtilsKt; is from kmmui modules file called in kmm's shared kmmpwpitara module and used in Native app project as attached screen. and gives the error

Screenshot 2024-03-16 at 10 19 43 AM

Additional context If KMM projects still fully didn't support Multi modular architecture let us know in prior

pablichjenkov commented 8 months ago

Not just KMP but also traditional Android, an .aar doesn't include the dependent submodules in the .aar You have to publish all submodules independently and include all of them in the final build.

sureshmaidaragi1919 commented 8 months ago

Not just KMP but also traditional Android, an .aar doesn't include the dependent submodules in the .aar You have to publish all submodules independently and include all of them in the final build.

Ho okay, Thanks for the information @pablichjenkov

sureshmaidaragi1919 commented 8 months ago

Not just KMP but also traditional Android, an .aar doesn't include the dependent submodules in the .aar You have to publish all submodules independently and include all of them in the final build.

@pablichjenkov I tried MavenLocal but still same issue, do I need to host them on sonartype?

pablichjenkov commented 8 months ago

Can you post your library pom.xml generated when you did the publication. MavenLocal should work but each library should be published to the local repository and have the correct pom.xml file.

devanshu6445 commented 8 months ago

@sureshmaidaragi1919 Hi, I think you can usemaven-publish plugin and configure each publication with the correct information such as artifactId pom info etc. It will automatically publish all the artifacts for all the targets defined in the build configuration. I have created a gradle plugin for this and it publishes all the artifacts to the repo.

sureshmaidaragi1919 commented 8 months ago

Can you post your library pom.xml generated when you did the publication. MavenLocal should work but each library should be published to the local repository and have the correct pom.xml file.

kmm-pw-ui-module-1.0.0.pom.txt

sureshmaidaragi1919 commented 8 months ago

@sureshmaidaragi1919 Hi, I think you can usemaven-publish plugin and configure each publication with the correct information such as artifactId pom info etc. It will automatically publish all the artifacts for all the targets defined in the build configuration. I have created a gradle plugin for this and it publishes all the artifacts to the repo.

Yes I did here is the snippet @devanshu6445 for one of the module

build.gradle.kts

plugins {
    id("com.android.library")
    kotlin("multiplatform")
    id("org.jetbrains.compose")
    kotlin("plugin.serialization") version "1.9.0"
    id("maven-publish")
    id("signing")
}

group = "live.pw" //todo change live.pw
version = "1.0.0"

kotlin {
    androidTarget{
        publishLibraryVariants("release")
    }
    iosArm64()
    iosSimulatorArm64()
    iosX64()

    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "shared"
            isStatic = true
            export("dev.icerock.moko:resources:0.23.0")
            export("dev.icerock.moko:graphics:0.9.0") // toUIColor here
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(kotlin("stdlib-common"))
                implementation(compose.runtime)
                implementation(compose.foundation)
                implementation(compose.material)
                implementation(libs.koin.core)
                implementation(libs.koin.compose)
                api(libs.moko.resource)
                api(libs.moko.resource.compose)
                api(libs.moko.media.compose)
                api(compose.animation)
                api(compose.material3)
                @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
                implementation(compose.components.resources)
                implementation(libs.napier)

            }
        }
        val androidMain by getting {
            dependsOn(commonMain)
            dependencies {

                api(compose.preview)
                api(compose.uiTooling)
                api("androidx.activity:activity-compose:1.7.2")
                api("androidx.appcompat:appcompat:1.6.1")
                api("androidx.core:core-ktx:1.10.1")
                implementation ("com.google.android.exoplayer:exoplayer:2.18.7")
                implementation ("com.google.android.exoplayer:exoplayer-ui:2.18.7")

                implementation(libs.lifecycle.runtime)
                implementation(libs.lifecycle.process)
                implementation("com.github.lincollincol:amplituda:2.2.2") {
                    because("Calculates the Amplitude in real time for the audio which is required for AudioWaveForm")
                }
            }
        }
        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)
        }
        commonTest.dependencies {
            // implementation(libs.kotlin.test)
        }
    }
}

android {
    namespace = "com.kmmpwplayer"
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion =
            "1.5.3" // Kotlin compiler should be compatible with Kotlin version. see for more details https://developer.android.com/jetpack/androidx/releases/compose-kotlin
    }
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    sourceSets["main"].res.srcDirs("src/androidMain/res")
    sourceSets["main"].resources.srcDirs("src/commonMain/resources")
    compileSdk = 34
    defaultConfig {
        minSdk = 24
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_19
        targetCompatibility = JavaVersion.VERSION_19
    }
    kotlin {
        jvmToolchain(19)
    }

}

.pom file attached for ref kmm-pw-player-module-1.0.0.pom.txt

sureshmaidaragi1919 commented 8 months ago

Also what is the plugin on Android Studio?

devanshu6445 commented 8 months ago

@sureshmaidaragi1919 As I can see from your build configuration, you are not configuring each publication target of maven publications. If you do that I think it will work. It is not an Android studio(IDE) plugin but rather my custom gradle plugin.

sureshmaidaragi1919 commented 8 months ago

@sureshmaidaragi1919 As I can see from your build configuration, you are not configuring each publication target of maven publications. If you do that I think it will work. It is not an Android studio(IDE) plugin but rather my custom gradle plugin.

can you help me to share any ref or doc todo that, I am not able to get exactly what I have missed

sureshmaidaragi1919 commented 8 months ago

Screenshot 2024-03-20 at 10 22 42 AM @devanshu6445

I can see the external library post running the current build

pablichjenkov commented 8 months ago

I see the ui module pom file reference core and player dependencies. The player pom seems ok, and I guess core is ok too. So with ui, player and core in your local maven. If you just use implementation("live.pw:UI:1.0.0") in your pure Android project, it should work. If you still get a missing class Exception. You can decompile the App with Android Studio or jadx and check if it was actually included or excluded by R8 I don't know. But in general gradle won't even compile if it doesn't resolve the dependecies.

devanshu6445 commented 8 months ago

@sureshmaidaragi1919 what @pablichjenkov is saying is correct but can you confirm whether this exception is only coming for the UtilsKt class or for any other classes as well. And are you using R8 for debug build as well?

sureshmaidaragi1919 commented 8 months ago

@devanshu6445 Issue is coming from other modules too, No I am not using R8 for any builds

okushnikov commented 3 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.