META-INF/versions/9/module-info.class:损坏的 class 文件? (此功能需要 ASM6)
META-INF/versions/9/module-info.class: broken class file? (This feature requires ASM6)
我在使用 Bouncycastle 时遇到问题,只有在 运行 :lint
任务时才会出现。
一般好像是Java9字节码版本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: broken class file? (This feature requires ASM6)
同样适用于:
// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation "com.google.code.gson:gson:2.8.6"
自从 1.4.1
升级到 1.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\module-info.class: broken class file? (Module requires ASM6)
更新:请看我当前的,它解决了问题。
此答案仅作为 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"
这个问题显然是在版本 1.61
/ 2.8.6
中引入的(可能是用 Java 9 构建的)。
当 Google 把人带回自己的答案时,这很烦人,这不是真正的答案。我没有保留版本或编辑 JAR,而是编写了一个 DeleteModuleInfoTask
和一个 shell 脚本,它们自动从任何给定的 Java 依赖项中删除 module-info.class
。
由于commandLine
只接受一个命令,几乎要调用一个脚本。这应该作为自定义 Exec
任务的一个很好的例子。
对于Linux:module_info.sh
考虑versions/9/module-info.class
和module-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}///
if [ -d "$DIRNAME" ]; then
cd ${DIRNAME} || exit 1
find . -name -.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:module_info.bat
取决于7-Zip:
@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\module-info.class > NUL:
7z d %%G versions\module-info.class > NUL:
7z d %%G module-info.class > NUL:
)
)
更新:经过一些测试,我得出的结论是,在 Windows 上开发时手动编辑文件可能会更好,因为 Android Studio 和 Java 会锁定JAR,随后将阻止编辑并留下临时文件。
文件 tasks.gradle
提供 DeleteModuleInfoTask
:
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
确保只为单个模块注册这些任务。
根据 resmon
“资源监视器”>“关联句柄”,studio64
和 java
可能会锁定 JAR 文件,因此 7-Zip 可能只能在 Android Studio 和 Java 关闭时编辑存档;至少它在 Linux.
上对 CI 很好用
文件 module-info.class
是自 Java 9 以来引入的 Java 模块系统的一部分。根据 this issue 在 Android IssueTracker 上,自 Android Studio 3.4 以来,错误已得到修复。
如前所述,这是在 Java 9 中引入的,Android 不支持。您可以只使用 packagingOptions
删除那些 类。
android {
packagingOptions {
exclude "**/module-info.class"
}
}
这应该不会影响实际执行的代码,并且还应该删除 类 以进行 lint 检查,因为 lint 正在处理字节码。
我收到以下错误消息:
Error processing C:\Users\mypc\.gradle\caches\modules-2\files-2.1\com.google.code.gson\gson.8.680733b7df8542621dc12e21e87557e8c99b8cb\gson-2.8.6.jar:module-info.class: broken class file? (This feature requires ASM6)
在不使用像 Android Studio 这样的开发系统的情况下会发生此错误。我使用 Gradle 6.1.1.
我预防错误如下:
- 打开错误消息中命名的文件
gson-2.8.6.jar
- 删除位于根目录
中的文件module-info.class
有一个更简单的解决方法。基本上问题可以被识别为“运行 Gradle with Java 8, while handling files which were builded with Java 9”。我的新方法是使用 Java 11 构建(GitHub Actions 也使用 Java 11 构建,而 Gradle 6.7.1 目前最多支持 Java 15)。
安装 Java 11 后 sudo dnf install java-11-openjdk
alternatives --display java
将列出要使用的 JDK。
例如:/usr/lib/jvm/java-11-openjdk-11.0.11.0.9-0.el8_3.x86_64
:
附带说明,使用 JDK 11 构建也修复了此警告:
Current JDK version 1.8.0_172-b11 has a bug (https://bugs.openjdk.java.net/browse/JDK-8007720) that prevents Room from being incremental. Consider using JDK 11+ or the embedded JDK shipped with Android Studio 3.5+.
“Android Studio 3.5+ 附带的嵌入式 JDK”仍然是 Java 8 ...
我在使用 Bouncycastle 时遇到问题,只有在 运行 :lint
任务时才会出现。
一般好像是Java9字节码版本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: broken class file? (This feature requires ASM6)
同样适用于:
// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation "com.google.code.gson:gson:2.8.6"
自从 1.4.1
升级到 1.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\module-info.class: broken class file? (Module requires ASM6)
更新:请看我当前的
此答案仅作为 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"
这个问题显然是在版本 1.61
/ 2.8.6
中引入的(可能是用 Java 9 构建的)。
当 Google 把人带回自己的答案时,这很烦人,这不是真正的答案。我没有保留版本或编辑 JAR,而是编写了一个 DeleteModuleInfoTask
和一个 shell 脚本,它们自动从任何给定的 Java 依赖项中删除 module-info.class
。
由于commandLine
只接受一个命令,几乎要调用一个脚本。这应该作为自定义 Exec
任务的一个很好的例子。
对于Linux:module_info.sh
考虑versions/9/module-info.class
和module-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}///
if [ -d "$DIRNAME" ]; then
cd ${DIRNAME} || exit 1
find . -name -.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:module_info.bat
取决于7-Zip:
@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\module-info.class > NUL:
7z d %%G versions\module-info.class > NUL:
7z d %%G module-info.class > NUL:
)
)
更新:经过一些测试,我得出的结论是,在 Windows 上开发时手动编辑文件可能会更好,因为 Android Studio 和 Java 会锁定JAR,随后将阻止编辑并留下临时文件。
文件 tasks.gradle
提供 DeleteModuleInfoTask
:
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
确保只为单个模块注册这些任务。
根据 resmon
“资源监视器”>“关联句柄”,studio64
和 java
可能会锁定 JAR 文件,因此 7-Zip 可能只能在 Android Studio 和 Java 关闭时编辑存档;至少它在 Linux.
文件 module-info.class
是自 Java 9 以来引入的 Java 模块系统的一部分。根据 this issue 在 Android IssueTracker 上,自 Android Studio 3.4 以来,错误已得到修复。
如前所述,这是在 Java 9 中引入的,Android 不支持。您可以只使用 packagingOptions
删除那些 类。
android {
packagingOptions {
exclude "**/module-info.class"
}
}
这应该不会影响实际执行的代码,并且还应该删除 类 以进行 lint 检查,因为 lint 正在处理字节码。
我收到以下错误消息:
Error processing C:\Users\mypc\.gradle\caches\modules-2\files-2.1\com.google.code.gson\gson.8.680733b7df8542621dc12e21e87557e8c99b8cb\gson-2.8.6.jar:module-info.class: broken class file? (This feature requires ASM6)
在不使用像 Android Studio 这样的开发系统的情况下会发生此错误。我使用 Gradle 6.1.1.
我预防错误如下:
- 打开错误消息中命名的文件
gson-2.8.6.jar
- 删除位于根目录 中的文件
module-info.class
有一个更简单的解决方法。基本上问题可以被识别为“运行 Gradle with Java 8, while handling files which were builded with Java 9”。我的新方法是使用 Java 11 构建(GitHub Actions 也使用 Java 11 构建,而 Gradle 6.7.1 目前最多支持 Java 15)。
安装 Java 11 后
sudo dnf install java-11-openjdk
alternatives --display java
将列出要使用的 JDK。
例如:/usr/lib/jvm/java-11-openjdk-11.0.11.0.9-0.el8_3.x86_64
:
附带说明,使用 JDK 11 构建也修复了此警告:
Current JDK version 1.8.0_172-b11 has a bug (https://bugs.openjdk.java.net/browse/JDK-8007720) that prevents Room from being incremental. Consider using JDK 11+ or the embedded JDK shipped with Android Studio 3.5+.
“Android Studio 3.5+ 附带的嵌入式 JDK”仍然是 Java 8 ...