简体   繁体   中英

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

I am trying to publish an obfuscated JAR created by the Gradle 6.0.1 ProGuard Plugin to a Maven repository. I've learned much about Gradle configurations, variants and artifacts over the last days, but I seem to be unable to make this work. I believe the relevant documentation is the one here .

I have created a minimal example showing my intended setup on Github .

If I run ./gradlew publish on this project I get the following error.

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').

I also tried the deprecated maven plugin. Unfortunately this plugin ignored the custom ProGuard jar.

Can someone give me any advice on how to replace the original JAR from the JAR task with the obfuscated Jar from the proguard task?

EDIT: I was able to derive a solution from this thread . The minimal example on Github contains the patched version. Feel free to have a look. I will put the working build.gradle into an answer below.

Adding classifier = "proguard" solved it, although I'm not familar with proguard to determine if the publication is correct.

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

Here's what was published for me:

在此处输入图片说明

I can see that the original JAR is 592 bytes while the proguard one is 410 bytes, so I am assuming it worked correctly.

Also while debugging your issue, I refactored to use the Kotlin DSL which I recommend using.

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"))
}

As already editted into the question I found a solution and updated the Github-Project accordingly. Since Stackoverflow likes to have local information and not to depend on links, I post the working build.gradle file as an answer here. The Rest of the Github-Project is just the Java library project created by gradle init .

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'
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM