META-INF/versions/9/module-info.class:损坏的类文件?(此功能需要 ASM6)

2022-09-02 22:17:51

我在使用Bouncycastle时遇到问题,这仅在运行任务时出现。:lint

一般情况下,Java 9字节码53.0/ASM版本冲突。

这些是依赖项:

// https://mvnrepository.com/artifact/org.bouncycastle
implementation "org.bouncycastle:bcprov-jdk15on:1.64"
implementation "org.bouncycastle:bcpkix-jdk15on:1.64"

这会导致任务引发处理错误::lint

> Task :mobile:lint
Error processing bcpkix-jdk15on-1.64.jar:META-INF/versions/9/module-info.class: broken class file? (This feature requires ASM6)
Error processing bcprov-jdk15on-1.64.jar:META-INF/versions/9/module-info.class: broken class file? (This feature requires ASM6)

META-INF/versions/9/module-info.class:损坏的类文件?(此功能需要 ASM6)

这同样适用于:

// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation "com.google.code.gson:gson:2.8.6"

从 升级到 后,情况又是一样的:1.4.11.4.2-native-mt

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2-native-mt"

kotlin-stdlib-1.4.0.jar:META-INF\versions\9\module-info.class: broken class file?(模块需要 ASM6)


答案 1

如前所述,这是在Java 9中引入的,Android不支持。您可以使用 来删除这些类。packagingOptions

android {
    packagingOptions {
        exclude "**/module-info.class"
    }
}

这应该不会影响实际执行的代码,并且还应该删除用于 lint 检查的类,因为 lint 正在处理字节码。


答案 2

更新:请参阅我当前的答案,这确定了问题。
这个答案只是作为Gradle脚本的一个例子。


使用旧版本(可能使用 Java 8 构建)时,没有这样的处理错误:

// https://mvnrepository.com/artifact/org.bouncycastle
implementation "org.bouncycastle:bcprov-jdk15on:1.60"
implementation "org.bouncycastle:bcpkix-jdk15on:1.60"

// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation "com.google.code.gson:gson:2.8.5"

这个问题显然是在版本 / 中引入的(可能是用 Java 9 构建的)。1.612.8.6


当谷歌把一个人带回自己的答案时,这很烦人,这并不是一个真正的答案。我没有保留版本或编辑JAR,而是编写了一个和一个shell脚本,它可以自动从任何给定的Java依赖项中删除。

由于只接受单个命令,因此几乎必须调用脚本。这应该可以作为自定义任务的一个很好的例子。DeleteModuleInfoTaskmodule-info.classcommandLineExec

对于 Linux:考虑和:module_info.shversions/9/module-info.classmodule-info.class

#!/usr/bin/env bash
GRADLE_CACHE_DIR=$HOME/.gradle/caches/modules-2/files-2.1
ZIP_PATHS=(META-INF/versions/9/module-info.class module-info.class)   
if [[ $# -ne 3 ]]; then
  echo "Illegal number of parameters"
  exit 1
else
  if [ -d "$GRADLE_CACHE_DIR" ]; then
    DIRNAME=${GRADLE_CACHE_DIR}/$1/$2/$3
    if [ -d "$DIRNAME" ]; then
      cd ${DIRNAME} || exit 1
      find . -name ${2}-${3}.jar | (
        read ITEM;
        for ZIP_PATH in "${ZIP_PATHS[@]}"; do
          INFO=$(zipinfo ${ITEM} ${ZIP_PATH} 2>&1)
          if [ "${INFO}" != "caution: filename not matched:  ${ZIP_PATH}" ]; then
            zip ${ITEM} -d ${ZIP_PATH} # > /dev/null 2>&1
          fi
        done
      )
      exit 0
    fi
  fi
fi

对于 Windows:取决于 7-Zipmodule_info.bat

@echo off
REM delete module.info from JAR file - may interfere with the local IDE.
for /R %USERPROFILE%\.gradle\caches\modules-2\files-2.1\%1\%2\%3\ %%G in (%2-%3.jar) do (
  if exist %%G (
      7z d  %%G META-INF\versions\9\module-info.class > NUL:
      7z d  %%G versions\9\module-info.class > NUL:
      7z d  %%G module-info.class > NUL:
  )
) 

更新:经过一些测试,我得出的结论是,在Windows上开发时手动编辑文件可能更好,因为Android Studio和Java将锁定JAR,这将随后阻止编辑并留下临时文件。


文件提供:tasks.gradleDeleteModuleInfoTask

import javax.inject.Inject

abstract class DeleteModuleInfoTask extends Exec {
    @Inject
    DeleteModuleInfoTask(String dependency) {
        def os = org.gradle.internal.os.OperatingSystem.current()
        def stdout = new ByteArrayOutputStream()
        def stderr = new ByteArrayOutputStream()
        ignoreExitValue true
        standardOutput stdout
        errorOutput stderr
        workingDir "${getProject().getGradle().getGradleUserHomeDir()}${File.separator}caches${File.separator}modules-2${File.separator}files-2.1${File.separator}${dependency.replace(":", File.separator).toString()}"
        String script = "${getProject().getRootDir().getAbsolutePath()}${File.separator}scripts${File.separator}"
        def prefix = ""; def suffix = "sh"
        if (os.isWindows()) {prefix = "cmd /c "; suffix = "bat"}
        String[] item = dependency.split(":")
        commandLine "${prefix}${script}module_info.${suffix} ${item[0]} ${item[1]} ${item[2]}".split(" ")
        // doFirst {println "${commandLine}"}
        doLast {
            if (execResult.getExitValue() == 0) {
                if (stdout.toString() != "") {
                    println "> Task :${project.name}:${name} ${stdout.toString()}"
                }
            } else {
                println "> Task :${project.name}:${name} ${stderr.toString()}"
            }
        }
    }
}

用法示例:

// Bouncycastle
tasks.register("lintFixModuleInfoBcPkix", DeleteModuleInfoTask, "org.bouncycastle:bcpkix-jdk15on:1.64")
lint.dependsOn lintFixModuleInfoBcPkix

tasks.register("lintFixModuleInfoBcProv", DeleteModuleInfoTask, "org.bouncycastle:bcprov-jdk15on:1.64")
lint.dependsOn lintFixModuleInfoBcProv

// GSON
tasks.register("lintFixModuleInfoGson", DeleteModuleInfoTask, "com.google.code.gson:gson:2.8.6")
lint.dependsOn lintFixModuleInfoGson

// Kotlin Standard Library
tasks.register("lintFixModuleInfoKotlinStdLib", DeleteModuleInfoTask, "org.jetbrains.kotlin:kotlin-stdlib:1.4.32")
lint.dependsOn lintFixModuleInfoKotlinStdLib

请确保仅为单个模块注册这些任务。

根据“资源监视器”>“关联句柄”,并且可能对JAR文件进行锁定,因此7-Zip可能只能在Android Studio和Java关闭时编辑存档;至少它非常适合Linux上的CI。resmonstudio64java


推荐