Hi, Is there any minimal examples to use Proguard ...
# gradle
a
Hi, Is there any minimal examples to use Proguard Gradle Plugin with Kotlin/JVM with no dependencies to reduce the size of the jar (by removing unused things like classes) which is already used by Android and Compose Desktop (JVM) more details are on the thread of this message. Thank you.
I tried using it with the following:
Copy code
buildscript {
    repositories { mavenCentral() }
    dependencies {
        classpath("com.guardsquare:proguard-gradle:7.4.2") {
            exclude("com.android.tools.build")
        }
    }
}

tasks.register<proguard.gradle.ProGuardTask>("proguard") {
    configuration(file("<http://proguard-rules.pro|proguard-rules.pro>"))
    injars(tasks.shadowJar.flatMap { it.archiveFile })
    outjars(
        layout.buildDirectory.file("libs/${tasks.shadowJar.get().archiveFile.get().asFile.nameWithoutExtension}-minified.jar"),
    )

    verbose()
}
Using shadow jar to build the jar since if you use any import from Kotlin or from dependencies you will get error
ClassNotFoundException
And using Proguard to make minimal jar size, if
<http://proguard-rules.pro|proguard-rules.pro>
is empty then it will say it need the steps for what to keep, but I didn't really understand how it work, is Proguard automated tool and shouldn't be the steps of defining what to keep is optional? Even after include some rules, it says please solve all the warrnings but it didn't print any, so I have to use
./gradlew proguard --info
but that show too much information (searching online, most people suggest to use
-ignorewarnings
) and even after fixing them, I still get another error:
Copy code
* What went wrong:
Execution failed for task ':proguard'.
> 
  
  It appears you are missing some classes resulting in an incomplete class hierarchy, 
  please refer to the troubleshooting page in the manual: 
  <https://www.guardsquare.com/en/products/proguard/manual/troubleshooting#superclass>
Using the link doesn't provide any info about that kind of error. I definitely missed something, because on Compose Desktop and Android you usually don't need to touch the file and most of the time you don't even know it's exist, it's already configured and even when adding new libraries it will work without changing anything, let's say I fixed all of this, do I need to change the rules when adding libraries? I don't use reflections and all of my code are in type-safe way There are other tools like [shakyboi](https://github.com/badlogic/shakyboi) which work perfectly like expected (from 1.6MB to about kilobytes for a project only use
println
) but it's no longer maintained and doesn't work when you have more complex project, most tutorials online cover how to setup the plugin not the rules of proguard file, I would like to know more about proguard and use it like it should Because even on blank Hello World Kotlin/JVM project with zero imports, if you shadow the jar with
minimize()
option it usually around (1.6MB)
I didn't mention I was able to use proguard but without any libraries, copying the rules of proguard.pro in the
application-kotlin
example but it didn't work directly, I had to use
Copy code
-ignorewarnings
c
Compose desktop has proguard already in the release pipeline. Maybe this article helps https://medium.com/@mike_21858/using-proguard-with-jetpack-compose-desktop-size-reduction-performance-gains-and-pain-481a014c6b0a
a
Thank you, I already checked it and it was added since
1.4
or
1.3
Compose desktop Gradle Plugin but I want to use it in Kotlin/JVM project that doesn't use Android or Compose Desktop or any framework that already has Proguard setup, only Kotlin/JVM code (with a few libraries) But maybe checking the Progurad rules of Compose desktop in the source code might help I managed to get it working in a minimal setup by using the
application-kotlin
example from Proguard source code, but I had to use
-ignorewarnings
and still another issue happen when using libraries like OkHttp, Kotlinx Coroutines and Serialization
c
Usually the libraries have a proguard documentation somewhere with the rules you need to add to your proguard config file.
👍 1
a
Thank you. I will check it.
It says you need to include rules from Okio too (I'm still getting
It appears you are missing some classes resulting in an incomplete class hierarchy
once include OkHttp library), but I couldn't find it, the link is to the Okio repository I found this: https://github.com/square/okio/pull/508/files/1d484861d789409bf62e2f5d84fa53b0e7b143fd#diff-f3c2293d6d6d9905b925f8b3[…]2a44372e5278e2f01440ff48dca12 But it's quite outdated and it looks like it's removed from the repository and
README.md
Found the solution
Copy code
val javaHome = System.getProperty("java.home")
    if (System.getProperty("java.version").startsWith("1.")) {
        // Before Java 9, runtime classes are packaged in a single JAR file.
        libraryjars("$javaHome/lib/rt.jar")
    } else {
        // Starting from Java 9, runtime classes are packaged in modular JMOD files.
        libraryjars(
            mapOf("jarfilter" to "!**.jar", "filter" to "!module-info.class"),
            "$javaHome/jmods/java.base.jmod",
        )
    }

 printmapping(destinationDirectory.file("$originalJarNameWithoutExtension.map"))

    // TODO: Workaround to fix `Please correct the above warnings first`
    ignorewarnings()
    dontobfuscate()
    dontoptimize()
    dontwarn()

    configuration(file("<http://proguard.pro|proguard.pro>"))
The rules depends on your application and mainly libraries, for my use-case:
Copy code
# Proguard Kotlin Example <https://github.com/Guardsquare/proguard/blob/master/examples/application-kotlin/proguard.pro>

-keepattributes *Annotation*

-keep class kotlin.Metadata { *; }

# Entry point to the app.
-keep class MainKt { *; }

# Kotlinx Serialization <https://github.com/Kotlin/kotlinx.serialization/blob/master/rules/common.pro>

# Keep `Companion` object fields of serializable classes.
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
    static <1>$Companion Companion;
}

# Keep `serializer()` on companion objects (both default and named) of serializable classes.
-if @kotlinx.serialization.Serializable class ** {
    static **$* *;
}
-keepclassmembers class <2>$<3> {
    kotlinx.serialization.KSerializer serializer(...);
}

# Keep `INSTANCE.serializer()` of serializable objects.
-if @kotlinx.serialization.Serializable class ** {
    public static ** INSTANCE;
}
-keepclassmembers class <1> {
    public static <1> INSTANCE;
    kotlinx.serialization.KSerializer serializer(...);
}

# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault

# Don't print notes about potential mistakes or omissions in the configuration for kotlinx-serialization classes
# See also <https://github.com/Kotlin/kotlinx.serialization/issues/1900>
-dontnote kotlinx.serialization.**

# Serialization core uses `java.lang.ClassValue` for caching inside these specified classes.
# If there is no `java.lang.ClassValue` (for example, in Android), then R8/ProGuard will print a warning.
# However, since in this case they will not be used, we can disable these warnings
-dontwarn kotlinx.serialization.internal.ClassValueReferences

# Kotlinx Coroutines <https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro>

# ServiceLoader support
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}

# Most of volatile fields are updated with AFU and should not be mangled
-keepclassmembers class kotlinx.coroutines.** {
    volatile <fields>;
}

# Same story for the standard library's SafeContinuation that also uses AtomicReferenceFieldUpdater
-keepclassmembers class kotlin.coroutines.SafeContinuation {
    volatile <fields>;
}

# These classes are only required by kotlinx.coroutines.debug.AgentPremain, which is only loaded when
# kotlinx-coroutines-core is used as a Java agent, so these are not needed in contexts where ProGuard is used.
-dontwarn java.lang.instrument.ClassFileTransformer
-dontwarn sun.misc.SignalHandler
-dontwarn java.lang.instrument.Instrumentation
-dontwarn sun.misc.Signal

# Only used in `kotlinx.coroutines.internal.ExceptionsConstructor`.
# The case when it is not available is hidden in a `try`-`catch`, as well as a check for Android.
-dontwarn java.lang.ClassValue

# An annotation used for build tooling, won't be directly accessed.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# OkHttp <https://square.github.io/okhttp/features/r8_proguard/>

# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**

# A resource is loaded with a relative path so the package of this class must be preserved.
-keeppackagenames okhttp3.internal.publicsuffix.*
-adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz

# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*

# OkHttp platform used only on JVM and when Conscrypt and other security providers are available.
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**

# Okio (missing)

# FlatLaf

# Exclude the entire FlatLaf dependency from minimization to fix `no ComponentUI class for: javax.swing.<component>`
# Due to reflections, more details: <https://github.com/JFormDesigner/FlatLaf/issues/648#issuecomment-1441547550>
-keep class com.formdev.flatlaf.** { *; }
227 Views