更新:请查看我当前的answer,它解决了问题。
此答案仅作为 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}/$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: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\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.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 "Resource Monitor" > "Associated Handles",studio64 和 java 可能会锁定 JAR 文件,因此 7-Zip 可能只能在 Android Studio 和Java 已关闭;至少它很好地适用于 Linux 上的 CI。