14

Good day. I've written a kotlin android library and uploaded it on bintray. But when I try to use it (via gradle compile) in some project, it fails to build with following errors:

> com.android.build.api.transform.TransformException: com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK META-INF/library_release.kotlin_module
File1: C:\Users\Charlie\.android\build-cache\2939fbc6b0336396c9c4912d615880645b2c729d\output\jars\classes.jar
File2: C:\Users\Charlie\OneDrive\Dev\Projects\AndroidStudio\MetuCardLib\demo\build\intermediates\bundles\default\classes.jar

I've looked up both of these .jar files and they both contained META-INF folder with library_release.kotlin_module file. But more importantly generated .aar (android archive published in bintray) contained this folder as well as this file. I've checked other decent bintray android libraries and they don't seem to include any META-INF files. However those that do include it (in most cases they contain license files) produce the same DuplicateFileException and the way to resolve it is to explicitly exclude them in use-project's gradle file.

What's the use of this library_release.kotlin_module file and how can I disable its generation during publishing? Because I don't want to explicitly exclude from every project which is using this library and I don't want to ask other developers to do so.

Here's the library's repo: https://github.com/arslancharyev31/Anko-ExpandableTextView/ And it's bintray repo: https://bintray.com/arslancharyev31/android/Anko-ExpandableTextView

arslancharyev31
  • 1,801
  • 3
  • 21
  • 39

3 Answers3

31

The original purpose of .kotlin_module files is to store the package parts mapping to the compiled class files. The compiler uses them to resolve top-level function calls in a library attached to the project. Also, Kotlin reflection uses the .kotlin_module files to construct the top level members metadata at runtime. See more: Improving Java Interop: Top-Level Functions and Properties

Given that, you don't want to disable their generation in library projects, because it might break compilation against the libraries.

Instead, you can get rid of the duplicates by using packagingOptions in your app build.gradle, as said here:

android {
    // ...

    packagingOptions {
        exclude 'META-INF/library_release.kotlin_module'
    }
}

Note: excluding these files from an application APK interferes with reflection at runtime and therefore is is not the best solution either.


Another option is to use unique module names in your libraries:

compileReleaseKotlin.kotlinOptions.freeCompilerArgs += ["-module-name", "my.library.id"]

Choose the task that produces the output that is then packed into the AAR. It might not be compileReleaseKotlin, and also note that doing this might affect the tests compilation for this variant.

Or, what's more reliable, just choose unique Gradle module names, because the Kotlin module is named after the Gradle project.

hotkey
  • 140,743
  • 39
  • 371
  • 326
  • 9
    Regarding the unique Gradle module names: on a highly modularized project, with multiple inner-modules level, you can easily end up having inner modules with the same name, with that making sense. The Kotlin compiler could probably be smarter about that, and use the _fully qualified_ module name. – Marc Plano-Lesay Oct 06 '18 at 05:25
  • 1
    On android, we are seeing the same file duplicated in 2 or more places. For example one might be under `build/intermediates/javac/debug/classes/META-INF/` and another under `build/tmp/kotlin-classes/debug/META-INF/` so then if we select `pickFirst` in the packaging options, that does not work. – Ray Hunter Oct 26 '20 at 21:15
1

I was able to resolve this by renaming modules to be uniquem when simpler module names conflicted.

Brill Pappin
  • 4,692
  • 1
  • 36
  • 36
1

EDIT: as we just learned the hard way - kotlin module name should only contain all filesystems supported characters.

We used ':' in the module name causing jar to contain file "company:product.kotlin_module". This will fail to extract on windows.

I thin in android realm currently(tested on Android gradle plugin 7.0.2)best solution would be to use android kotlin options section

android{
   kotlinOptions{
      moduleName = "com.example.mylibrary"
   }
}

It results in META-INF/com.example.mylibrary.kotlin_module - which should be sufficently unique content of aar

madabrowski
  • 1,273
  • 14
  • 17