如何使用 Gradle 发布插件将混淆器 JAR 发布为 Maven 工件

How to publish proguard JAR as Maven Artifact using Gradle Publish Plugin

我正在尝试将由 Gradle 6.0.1 ProGuard 插件创建的混淆 JAR 发布到 Maven 存储库。在过去的几天里,我学到了很多关于 Gradle 配置、变体和工件的知识,但我似乎无法完成这项工作。我相信相关文档是 here.

我创建了一个minimal example showing my intended setup on Github

如果我 运行 ./gradlew publish 在这个项目上我得到以下错误。

Execution failed for task ':publishMyLibraryPublicationToMyRepoRepository'.
> Failed to publish publication 'myLibrary' to repository 'myRepo'
   > Invalid publication 'myLibrary': multiple artifacts with the identical extension and classifier ('jar', 'null').

我还尝试了已弃用的 maven 插件。不幸的是,此插件忽略了自定义 ProGuard jar。

有人可以给我任何关于如何将 JAR 任务中的原始 JAR 替换为混淆任务中的混淆 JAR 的建议吗?

编辑: 我能够从 this thread 中得出一个解决方案。 Github 上的最小示例包含修补版本。随意看看。我将把工作 build.gradle 放入下面的答案中。

添加 classifier = "proguard" 解决了它,虽然我不熟悉 proguard 来确定发布是否正确。

artifacts {
    proguard(new File(proguard.outJarFiles[0])) {
        builtBy(proguard)
        classifier = "proguard"
    }
}

这是为我发布的内容:

我可以看到原始 JAR 是 592 字节,而混淆器是 410 字节,所以我假设它工作正常。

此外,在调试您的问题时,我重构为使用我推荐使用的 Kotlin DSL

import proguard.gradle.ProGuardTask

plugins {
    `java-library`
    `maven-publish`
}

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath("net.sf.proguard:proguard-gradle:6.2.2")
    }
}

group = "org.example"
version = "1.0.0"

repositories {
    jcenter()
}

configurations {
    val implementation by this
    val runtimeOnly by this
    create("proguard") {
        isCanBeConsumed = false
        isCanBeResolved = false
        extendsFrom(implementation, runtimeOnly)
        attributes {
            attribute(Attribute.of("org.gradle.usage", String::class.java), Usage.JAVA_API)
            attribute(Attribute.of("org.gradle.category", String::class.java), Category.LIBRARY)
            attribute(Attribute.of("org.gradle.libraryelements", String::class.java), LibraryElements.JAR)
            attribute(Attribute.of("org.gradle.dependency.bundling", String::class.java), Bundling.EXTERNAL)
        }
    }
}

dependencies {
    api("org.apache.commons:commons-math3:3.6.1")
    implementation("com.google.guava:guava:23.0")
    testImplementation("junit:junit:4.12")
}

val proguard by tasks.registering(ProGuardTask::class) {
    description = "Optimizes and obfuscates the created distribution jar."
    dependsOn(tasks.named("jar"))
    verbose()

    injars("$buildDir/libs/${project.name}-${project.version}.jar")
    outjars("$buildDir/proguard/${project.name}-${version}.jar")

    if (System.getProperty("java.version").startsWith("1.")) {
        libraryjars("${System.getProperty("java.home")}/lib/rt.jar")
    } else {
        libraryjars(mapOf("jarfilter" to "!**.jar", "filter" to "!module-info.class"), "${System.getProperty("java.home")}/jmods/java.base.jmod")
    }

    libraryjars(configurations.named("runtimeClasspath").get().files)

    printmapping("out.map")

    keep("""
        public class * {
            public protected *;
        }
    """.trimIndent())

    keepclassmembers(mapOf("allowoptimization" to true), """
        enum * {
            public static **[] values();
            public static ** valueOf(java.lang.String);
        }
    """.trimIndent())

    keepclassmembers("""
        class * implements java.io.Serializable {
            static final long serialVersionUID;
            static final java.io.ObjectStreamField[] serialPersistentFields;
            private void writeObject(java.io.ObjectOutputStream);
            private void readObject(java.io.ObjectInputStream);
            java.lang.Object writeReplace ();
            java.lang.Object readResolve ();
        }
    """.trimIndent())

    overloadaggressively()
}


val javaComponent = project.components.findByName("java") as AdhocComponentWithVariants
javaComponent.addVariantsFromConfiguration(configurations.getByName("proguard")) {
    // I have no idea what I should do here and the documentation is very confusing
}

publishing {
    publications {
        create<MavenPublication>("myLibrary") {
            from(components["java"])
            artifact(proguard.get().outJarFiles[0]) {
                builtBy(proguard.get())
                classifier = "proguard"
            }
        }
    }

    repositories {
        maven {
            name = "myRepo"
            url = uri("file://${buildDir}/repo")
        }
    }
}

tasks.named("publish").configure {
    dependsOn(tasks.named("proguard"))
}

由于已经编辑到问题中,我找到了解决方案并相应地更新了 Github-Project。由于 Whosebug 喜欢拥有本地信息而不依赖于链接,因此我 post 工作 build.gradle 文件作为此处的答案。 Github-项目的其余部分只是 gradle init 创建的 Java 库项目。

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'net.sf.proguard:proguard-gradle:6.2.2'
        classpath 'net.sf.proguard:proguard-base:6.2.2'
    }
}

plugins {
    id 'java-library'
    id 'maven-publish'
}

group = 'org.example'
version = '1.0.0'

repositories {
    jcenter()
}

dependencies {
    api 'org.apache.commons:commons-math3:3.6.1'
    implementation 'com.google.guava:guava:23.0'
    testImplementation 'junit:junit:4.12'
}

task createObfuscated(type: proguard.gradle.ProGuardTask, dependsOn: 'jar') {
    description 'Optimizes and obfuscates the created distribution jar.'
    verbose

    injars  "${buildDir}/libs/${project.name}-${version}.jar"
    outjars "${buildDir}/obf/${project.name}-${version}.jar"

    if (System.getProperty('java.version').startsWith('1.')) {
        libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
    } else {
        libraryjars "${System.getProperty('java.home')}/jmods/java.base.jmod", jarfilter: '!**.jar', filter: '!module-info.class'
    }
    libraryjars configurations.findByName('runtimeClasspath').getFiles()

    printmapping 'out.map'

    keep 'public class * { \
        public protected *; \
    }'

    keepclassmembers allowoptimization: true, 'enum * { \
        public static **[] values(); \
        public static ** valueOf(java.lang.String); \
    }'

    keepclassmembers 'class * implements java.io.Serializable { \
        static final long serialVersionUID; \
        static final java.io.ObjectStreamField[] serialPersistentFields; \
        private void writeObject(java.io.ObjectOutputStream); \
        private void readObject(java.io.ObjectInputStream); \
        java.lang.Object writeReplace(); \
        java.lang.Object readResolve(); \
     }'

     overloadaggressively
}

task copyObfuscated(type: Copy, dependsOn: createObfuscated) {
    from "${buildDir}/obf"
    into "${buildDir}/libs"
    include '*.jar'
}

task deleteObfuscated(type: Delete, dependsOn: copyObfuscated) {
    delete '${buildDir}/obf'
}

task proguard dependsOn deleteObfuscated

publishing {
    publications {
        myLibrary(MavenPublication) {
            from components.java
        }
    }

    repositories {
        maven {
            name = 'myRepo'
            url = "file://${buildDir}/repo"
        }
    }
}

publish.dependsOn proguard

wrapper {
    gradleVersion '6.0.1'
}