https://kotlinlang.org logo
#android
Title
# android
x

Xabier Gorostidi

11/03/2023, 4:46 PM
Hi everyone, I’m creating a Kotlin library for Android, and when consuming that library from another Kotlin app which uses named parameters on functions I get the error indicating named parameters are not included in bytecode. Nothing new so far, even though we consume it from Kotlin and not Java it doesn’t work. It seems I need to compile the library including
javaParameters = true
. The documentation states: “Generate metadata for Java 1.8 reflection on method parameters”. Do I need to do that in order to preserve named parameters from Kotlin (lib) => Kotlin (app)? What is exactly that metadata, would I be exposing anything else relevant? If I attach the sources.jar file, wouldn’t be enough for the app to infer the naming parameters?
e

ephemient

11/03/2023, 5:06 PM
the compiler doesn't read the sources jar, only the ide
it sounds like you're not shipping the module metadata
x

Xabier Gorostidi

11/03/2023, 5:08 PM
Thanks for the response. How is that module metadata shipped? Through
javaParameters = true
parameter?
e

ephemient

11/03/2023, 5:10 PM
no, it's in
META-INF/*.kotlin_module
files and
@kotlin.Metadata
annotations that the Kotlin compiler always produces
make sure you're not stripping them out
x

Xabier Gorostidi

11/03/2023, 5:10 PM
Oh right, I thought you were referring to that one. Ok thanks for your help!
e

ephemient

11/03/2023, 5:12 PM
Java parameter names are basically only used by Java reflection and nothing else
👍 1
x

Xabier Gorostidi

11/04/2023, 3:03 PM
Hi there, just to let you know after checking it more carefully. The app was compiled with Kotlin 1.8.22, the library was also compiled with 1.8.22. However, I had Dokka with 1.7.10, which forced Kotlin to be 1.7.10 and somehow didn’t export extension functions and named parameters well.
🧵 1
p

Pedro Varela

11/04/2023, 10:51 PM
Xavier, check if you have in build Gradle minify enabled true, if that is the case check add -keep class kotlin.Metadata { *; } to your proguard rules. That might help you.
x

Xabier Gorostidi

11/04/2023, 11:12 PM
Good point also Pedro, thanks a lot!
Sorry to reach you back regarding this topic. I’ve done several tests and the results are blowing my mind: • WORKS ◦ Library in Kotlin 1.7.10 (assemble*Release* with obfuscation) ◦ App in Kotlin 1.7.10 • IT DOESN’T WORK ◦ Library in Kotlin 1.8.22 (assemble*Release* with obfuscation) ◦ App in Kotlin 1.8.22 • WORKS ◦ Library in Kotlin 1.8.22 (assemble*Debug* without obfuscation) ◦ App in Kotlin 1.8.22 • IT DOESN’T WORK ◦ Library in Kotlin 1.9.10 (assemble*Release* with obfuscation) ◦ App in Kotlin 1.9.10 When it doesn’t work, I’ve tried adding the R8 exceptions on all modules of the library:
Copy code
-keep class kotlin.Metadata
-keep,allowobfuscation class kotlin.Metadata { *; }
In fact, inspecting the content of the AAR I can see the
_kotlin.metadata
file there with the same 70B size than when it works. The symptoms of the errors are like the metadata is not processed. Kotlin naming parameters, top level functions and so on are not resolved. Clicking on a top level function for example, when it works, it is displayed in Kotlin with that public function’s high order function parameters. However when it doesn’t, it’s displayed in Java with a private interface based content. I don’t really know but somehow obfuscation + Kotlin version are involved here.
e

ephemient

11/09/2023, 6:48 PM
the kotlin metadata version is increased with each release, and the obfuscator needs to understand it in order to update it properly while performing its other transformations. so that's not surprising
x

Xabier Gorostidi

11/09/2023, 6:54 PM
I don’t know if I’m getting the message, within the library project I have a sample module that consumes the AAR file from
lib
’s folder each time I rebuild the library. I mean, all of them are fresh compilations. You mean the obfuscator of the app needs to understand the metadata of the library in order to interprete it?
e

ephemient

11/09/2023, 6:56 PM
when the obfuscator mangles to the classes in a library, if it doesn't make corresponding changes to the Kotlin metadata, downstream consumers will not be able to use the metadata (as it doesn't match)
the obfuscator of the app doesn't matter, that happens after the Kotlin compilation of the app itself, which is the only part that should care about the metadata (unless you're using reflection at runtime)
but it sounds like you're using proguard or r8 in your library
or reflection?
x

Xabier Gorostidi

11/09/2023, 6:58 PM
I’m using R8.
Shouldn’t it perform those corresponding changes to the Kotlin Metadata by default?
e

ephemient

11/09/2023, 6:59 PM
it can't if it doesn't understand the Kotlin metadata version
which changes on every major release
not an issue for apps that don't need to
-keep kotlin.Metadata
, only libraries that want to be obfuscated, which (AFAIK) is rare
x

Xabier Gorostidi

11/09/2023, 7:05 PM
You’re right, obfuscated libraries are rare, just for commercial use normally. Thanks for that ref. So based on the table, I was always using AGP
7.3.0
, and testing Kotlin
1.7.10
to
1.8.22
. It seems there’s a major version change of R8 3.x to 4.x. Is that what you mean?
e

ephemient

11/09/2023, 7:06 PM
yes
x

Xabier Gorostidi

11/09/2023, 7:12 PM
You’re correct, now it works! Thanks a lot @ephemient, didn’t realize that could affect on this behavior.
To be honest, I’ve always doubts on which Kotlin version should a Kotlin library be shipped. An old one like
1.7.10
, or the latest like
1.9.20
. The latter choice implies us to stay on alert not using Kotlin features introduced on 1.8.x and 1.9.x, to not force a 1.7.x consumer update Kotlin for us.
e

ephemient

11/09/2023, 7:20 PM
even if you voluntarily avoid new language features, Kotlin will default to newer metadata, which will force your consumers to be at most 1 version behind
x

Xabier Gorostidi

11/09/2023, 9:48 PM
Thanks once again. So I guess it’s safer to use old versions then, in this case 1.7.10.