在 gradle android library kotlin 项目中禁用 META-INF/* 生成

Posted

技术标签:

【中文标题】在 gradle android library kotlin 项目中禁用 META-INF/* 生成【英文标题】:Disable META-INF/* generation in gradle android library kotlin project 【发布时间】:2017-12-27 04:36:33 【问题描述】:

美好的一天。我已经编写了一个 kotlin android 库并将其上传到 bintray。但是当我尝试在某些项目中使用它(通过 gradle compile)时,它无法构建并出现以下错误:

> 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

我查看了这两个 .jar 文件,它们都包含 META-INF 文件夹和 library_release.kotlin_module 文件。但更重要的是生成的 .aar(在 bintray 中发布的 android 存档)包含此文件夹以及此文件。我检查了其他不错的 bintray android 库,它们似乎不包含任何 META-INF 文件。然而,那些确实包含它的(在大多数情况下它们包含许可证文件)会产生相同的DuplicateFileException,解决它的方法是在 use-project 的 gradle 文件中明确排除它们。

这个library_release.kotlin_module 文件有什么用?如何在发布期间禁用它的生成?因为我不想从每个使用这个库的项目中明确排除,也不想要求其他开发人员这样做。

这是图书馆的回购:https://github.com/arslancharyev31/Anko-ExpandableTextView/ 它是 bintray 仓库:https://bintray.com/arslancharyev31/android/Anko-ExpandableTextView

【问题讨论】:

【参考方案1】:

.kotlin_module 文件的最初目的是存储包部分映射到已编译的类文件。编译器使用它们来解析附加到项目的库中的***函数调用。此外,Kotlin 反射使用 .kotlin_module 文件在运行时构造***成员元数据。查看更多:Improving Java Interop: Top-Level Functions and Properties

鉴于此,您不想在库项目中禁用它们的生成,因为它可能会破坏针对库的编译。

相反,您可以通过在您的应用程序build.gradle 中使用packagingOptions 来消除重复项,如here 所说:

android 
    // ...

    packagingOptions 
        exclude 'META-INF/library_release.kotlin_module'
    

注意:从应用程序 APK 中排除这些文件会干扰运行时的反射,因此也不是最佳解决方案。


另一种选择是在您的库中使用唯一的模块名称:

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

选择产生输出然后打包到 AAR 中的任务。 它可能不是compileReleaseKotlin,另外请注意,这样做可能会影响此变体的测试编译。

或者,更可靠的是,选择唯一的 Gradle 模块名称,因为 Kotlin 模块是以 Gradle 项目命名的。

【讨论】:

关于唯一的 Gradle 模块名称:在高度模块化的项目中,具有多个内部模块级别,您可以轻松地最终拥有具有相同名称的内部模块,这是有道理的。 Kotlin 编译器可能对此更聪明,并使用 fully qualified 模块名称。 在 android 上,我们看到同一个文件在 2 个或多个位置重复。例如,一个可能在build/intermediates/javac/debug/classes/META-INF/ 下,另一个在build/tmp/kotlin-classes/debug/META-INF/ 下,那么如果我们在打包选项中选择pickFirst,那将不起作用。【参考方案2】:

当更简单的模块名称发生冲突时,我可以通过将模块重命名为 uniquem 来解决此问题。

【讨论】:

【参考方案3】:

编辑:正如我们刚刚学到的艰难方法 - kotlin 模块名称应该只包含所有文件系统支持的字符。

我们在模块名称中使用了“:”,导致 jar 包含文件“company:product.kotlin_module”。这将无法在 Windows 上提取。

我目前在 android 领域瘦身(在 Android gradle 插件 7.0.2 上测试)最好的解决方案是使用 android kotlin 选项部分

android
   kotlinOptions
      moduleName = "com.example.mylibrary"
   

它导致 META-INF/com.example.mylibrary.kotlin_module - 这应该是足够独特的

【讨论】:

以上是关于在 gradle android library kotlin 项目中禁用 META-INF/* 生成的主要内容,如果未能解决你的问题,请参考以下文章

Android Gradle 插件Android Library 依赖库混淆配置 ( ProductFlavor#consumerProguardFiles 配置 | 依赖库混淆配置 )

Android Library Gradle发布JAR

在 Android Studio 和 Gradle 的 Android App Module 中使用不同构建类型的 Library Module

如何在不公开源代码的情况下使用 gradle 创建 Android Library Jar?

Android Studio怎样加入工程(project)为library(针对非gradle)

android studio 怎么引入library