I've got more of a concrete example to play with n...
# multiplatform
c
I've got more of a concrete example to play with now. I've implemented a multiplatform project targeting desktop and android. I've got a library module that has common, desktop and android code, and an android app module and a desktop app module. Both platforms use the exact same implementation of services using a java library that works on both android and desktop. I'd like to not have to duplicate the code, but I don't know how I can achieve re-use in a multiplatform project world.
My 'dream' architecture
j
What code are you requiring in the lib_module Android source set that is Android specific? My library has an architecture very similar to this (with additional native targets).
Something like this should do what you want:
Copy code
kotlin {
    android()
    jvm()

    sourceSets {
        val commonMain by getting
        // this is "Generic JVM Module" (really a source set, not module)
        val jvmCommonMain by creating {
            dependsOn(commonMain)
            dependencies {
                // this is "Java lib that totally works on JVM and Android"
                implementation("java.lib:1.0")
            }
        }
        val androidMain by getting {
            dependsOn(jvmCommonMain)
        }
        val jvmMain by getting {
            dependsOn(jvmCommonMain)
        }
    }
}
In my project, the library dependency has separate JVM and Android artifacts, which share 99% the same API with a single function that differs. So most code is shared in the jvmCommon source set, with the platform-specific code utilizing the differing function in androidMain and jvmMain. The build.gradle.kts looks more like this:
Copy code
kotlin {
    android()
    jvm()

    sourceSets {
        val commonMain by getting
        val jvmCommonMain by creating {
            dependsOn(commonMain)
            dependencies {
                // this is compileOnly to resolve dependency in IDE
                // replaced in Android and JVM source sets
                compileOnly("java.lib-jvm:1.0")
            }
        }
        val androidMain by getting {
            dependsOn(jvmCommonMain)
            dependencies {
                // Android-specific lib artifact
                implementation("java.lib-android:1.0")
            }
        }
        val jvmMain by getting {
            dependsOn(jvmCommonMain)
            dependencies {
                // JVM-specific lib artifact
                implementation("java.lib-jvm:1.0")
            }
        }
    }
}
e
that mostly works but see the links from the issues I posted above for problems with this approach currently
j
My understanding of the crux of the jvmCommon source set limitations is that there is no commonization done between the JVM and Android platform APIs, as occurs with common native source sets. I've found this can mostly be worked around by assuming the jvmCommon source set uses the JVM platform APIs and be aware of APIs that are not truly common with Android and avoid them in the jvmCommon code. This is why I use the JVM library artifact as the
compileOnly
dependency in the jvmCommon source set, also avoiding the API that's not common with the Android artifact.
a
what about creating a seperate module (not a common source sets) that you can add it as dependency to both?
e
you won't be able to add an expect/actual that differs by desktop/android to that common module. ok for some applications, awkward for others
a
You actually can. We are currently doing that exact same thing, our sub projects have expect/actual implementations and they work flawlessly
c
I did not realise you could do a
dependsOn(jvmCommonMain)
I'll have a play with this later!
@andylamax do you reckon you could elaborate a little more about that? I've tried the jvmCommonMain approach but I think I'm missing something, not sure where I should be creating the source sets
I'm lying, I'm an idiot, it worked perfectly, I just got confused with all the modules I had!
This is what I've got now, fortunately I've not gone to the point where I've wanted to have
actual
implementations in my jvmCommon module, so I've been able to just stuff my semi interesting service layer stuff in there and it's all working well! thanks for the help peeps!
p.s. https://www.tldraw.com/ is awesome for little doodles