https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
n

Nikita Khlebushkin

02/23/2020, 7:37 PM
Hello! I have a KMP module called analytics-interface with targets
ios
and
jvm
that contains class A:
Copy code
class A {
    fun foo() { ... }
}
and another KMP module called analytics with targets
ios
and
android
that contains class B:
Copy code
actual class B : A() {
    fun bar() { ... }
}
When I run
./gradlew :analytics:assembleRelease
, the analytics-release.aar artifact is generated, and when I plug it in Android library, I can do
B().bar()
but not
B().foo()
. What am I doing wrong? EDIT Added a project to reproduce the issue https://gitlab.com/NikitaKhlebushkin/kmp-multi-module
k

kpgalligan

02/23/2020, 8:12 PM
That’s odd. Code example?
n

Nikita Khlebushkin

02/23/2020, 8:33 PM
@kpgalligan, sure, which part exactly do you want?
a

Arkadii Ivanov

02/23/2020, 8:48 PM
Perhaps
analytics-interfase
dependency should be configured as
api
(not as
implementation
) for the
analytics
module.
n

Nikita Khlebushkin

02/23/2020, 8:57 PM
@Arkadii Ivanov thanks, I tried that too, no success. I set it up like this:
Copy code
sourceSets {
        val commonMain by getting {
            dependencies {
                api(project(":analytics-interface"))
                implementation(kotlin("stdlib-common"))
                implementation(kotlin("reflect"))
            }
        }
}
r

russhwolf

02/23/2020, 9:48 PM
Does it fail to build from Gradle or is it just red in the IDE? Sometimes the IDE gets confused when mixing jvm and android modules.
n

Nikita Khlebushkin

02/23/2020, 10:13 PM
@russhwolf Build of analytics neither fails in Gradle nor is red in JVM. I did not try building Android project that uses output artifact of analytics, but what I did is I followed (Ctrl + click) into decompiling of B and it shows correctly that it is inherited from A but fails to find A
I changed
android
target in analytics project to
jvm
, but it didn't help
Seems like the problem is that
B
class is expect/actual kind of classes
And expected class cannot be inherited from anything
I don't really know how to cope with this problem
Added a project to reproduce the issue https://gitlab.com/NikitaKhlebushkin/kmp-multi-module
r

russhwolf

02/24/2020, 1:10 AM
Oh yeah. I actually have seen that before. It’s not that
expect
class can’t inherit, it’s that you need to have the exact same class hierarchy between
expect
and
actual
. There’s a youtrack ticket for it at https://youtrack.jetbrains.com/issue/KT-23703
n

Nikita Khlebushkin

02/24/2020, 6:07 AM
@russhwolf it seems that the hierarchy matches as much as possible (platform doesn't allow doing
expect class B: A()
, which is the only difference. Anything I could do about it?
g

gmazzo

02/24/2020, 10:39 AM
I thinks I have the same issue: I have two multiplatform modules with the same targets: A and B. B depends on A as:
commonMainApi(project(":a"))
Then the final binary for iOS or JS does not contains any class from A
n

Nikita Khlebushkin

02/24/2020, 10:42 AM
@gmazzo did you solve it somehow?
g

gmazzo

02/24/2020, 10:47 AM
In a very very very hacky way: Instead of declaring a dependency on
A
, I’ve just added all
src/x
of
A
as a
srcDir
of
B
(and
C
).
A
was my
common
module.
Not ideal at all, but at least it works 🙃
So, if anyone has a working solution for this dependency problem, I’ll glad to know it
a

Arkadii Ivanov

02/24/2020, 10:51 AM
Well if the class B is expect/actual then to me such a behaviour is expected. I need to check but I believe I'm using this as a feature in one of my projects.
g

gmazzo

02/24/2020, 10:52 AM
In my case, it has nothing to do with `expect`/`actual`. I have some final classes on
A
, that
B
and
C
should consume. Everything compiles just fine, but then when running those classes are missing.
a

Arkadii Ivanov

02/24/2020, 10:53 AM
I mean from my point of view,
actual class B : A
should not expose you A.
Let me check
g

gmazzo

02/24/2020, 10:56 AM
Well, I’m not an expect on this, but I think if
class A
is defined in a dependency module
a
: If
a
is declared as
implementation
, then
actual class B : A
should fail to compile for exposing an internal class. If
a
is declared as
api
then it should work ok. But at least on my experience,
class A
doesn’t exist at all on native or js targets in module
b
artifact 😞
a

Arkadii Ivanov

02/24/2020, 10:58 AM
Perhaps you are right, it works as you expect if you extend e.g. a JDK class. Looks like a bug.
g

gmazzo

02/24/2020, 11:07 AM
At this point I’m not sure if it’s a bug, something we have misted or an edge case. The generated
commonJs
code for
js
receives an injection dependency for the common module, as it’d expecting to have another native pacakge published for the
common
module. For JVM targets, you’ll see a dependency on the
common
module JAR. So I think this is an edge case not covered, because it doesn’t make sense to my that behaves differently depending on the platform: for JVM: it uses the transitively model from the POM, with a common jar artifact for Native and JS: it’s basically the same, expect that there is no dependency mechanism in place. A fat artifact is required then. I think the “fast” workaround w’d be to produce fat artifacts for all the platforms. The “right” solution ’d be to support native artifact for each platforms: NPM modules and CocoaPods
n

Nikita Khlebushkin

02/24/2020, 1:28 PM
Thanks, I'll give it a try!
Would be nice to receive any feedback from JetBrains folk on whether it is expected behavior