使用 Scala 的 Proguard - 错误 4

Posted

技术标签:

【中文标题】使用 Scala 的 Proguard - 错误 4【英文标题】:Proguard with Scala - Error 4 【发布时间】:2015-02-27 16:41:43 【问题描述】:

Proguard 5.1 在收缩阶段失败并显示“错误:4”。 proguard配置文件如下:

-injars      ReversiRaw.jar
-outjars     Reversi.jar
-libraryjars <java.home>/lib/rt.jar
-libraryjars <java.home>/lib/ext/jfxrt.jar

-dontwarn scala.**

-dontnote
-dontwarn
-ignorewarnings

-keepclasseswithmembers public class * 
    public static void main(java.lang.String[]);


-keepclassmembers class * 
    ** MODULE$;

这主要是文档中给出的默认 Scala 配置。 正在压缩以进行复制的 jar 文件的下载链接:download

“错误:4”是什么,如何解决或避免?

【问题讨论】:

我也遇到了这个问题。我是 Proguard 的新手 【参考方案1】:

另一个解决方案可能是使用 gradle。

这是构建的gradle源码,获取fat文件(shadowJar文件),用proguard收缩jar文件。

buildscript 
    repositories  
        flatDir dirs: '/Users/smcho/Dropbox/smcho/bin/jar/proguard5.2/lib'
        mavenCentral()
        jcenter()
    
    dependencies 
        classpath ':proguard'
        classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.0'
    


apply plugin: 'scala'
apply plugin: 'com.github.johnrengelman.shadow'

repositories
    mavenCentral()


shadowJar 
  manifest 
    attributes 'Main-Class': 'HelloWorld'
  


dependencies
    compile "org.scala-lang:scala-library:2.11.5"


task proguard(type: proguard.gradle.ProGuardTask) 
//    injars './build/classes'
    injars './build/libs/scala_all_jar-all.jar'
    outjars './build/libs/main.jar'
    libraryjars "$System.getProperty('java.home')/lib/rt.jar"

    dontwarn
    dontnote
    ignorewarnings

    keepattributes 'SourceFile,LineNumberTable'

    keepclasseswithmembers 'public class *  \
        public static void main(java.lang.String[]); \
    '

您需要将flatDir dirs 设置为指向您的proguard 文件所在的位置。

gradle build 会得到编译的类和 jar 文件,gradle shadowJar 会得到大 jar 文件,gradle proguard 会得到名为 main.jar 的精简 jar 文件。

我也上传了来源:https://dl.dropboxusercontent.com/u/10773282/share/2015/scala_all_jar.zip

【讨论】:

【参考方案2】:

虽然 prosseek 的回答很有帮助,但我能够获得一个简单的 Hello-World proguard 配置,而无需求助于类文件。 (与 prosseek 不同,我没有尝试过 Uberjar)。

改编自the Scala example in the Proguard manual,我得到了一个简单的*.pro,看起来像:

-injars      build/install/HelloScala/lib/helloscala-1.0.jar
-injars      build/install/HelloScala/lib/scala-library-2.11.6.jar(!META-INF/MANIFEST.MF)
-outjars     helloscalapro.jar
-libraryjars <java.home>/lib/rt.jar

-dontwarn scala.**

//etc.

从 Scala 库中过滤掉清单。

当我传递给injar 的 Scala 库版本与我编译它时使用的 Scala 版本不同(补丁)时,我也得到了错误 4。

【讨论】:

【参考方案3】:

当我的 injar jar 文件是通过 sbt assembly 命令从插件程序集中获得的胖 jar 时,我也遇到了同样的问题。 解决这个问题的方法不是使用 fat jar,而是使用 scala 生成的类,以及其他 java/scala 库来获取精简的 jar 文件。

在我的 mac (OS X 10.10) 上,我有这个 proguard 文件(名为 your.pro)。

-injar classes
-injar /usr/local/Cellar/scala/2.11.5/libexec/lib/scala-library.jar(!META-INF/MANIFEST.MF)
-outjar main.jar
-libraryjar /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Classes/classes.jar

-dontwarn
-dontnote
-ignorewarnings

-optimizationpasses 2
-optimizations !code/allocation/variable

-keep,allowoptimization,allowshrinking class *  *; 
-keepattributes SourceFile,LineNumberTable

-keepclasseswithmembers public class *  public static void main(java.lang.String[]); 

这是目录结构。

.
├── classes
│   ├── HelloWorld$.class
│   ├── HelloWorld$delayedInit$body.class
│   ├── HelloWorld.class
│   └── META-INF
│       └── MANIFEST.MF
├── src
│   └── hello.scala
└── your.pro

hello.scala如下:

object HelloWorld extends App 

    println("Hello, world")

您可以使用scalac src/hello.scala -d classes 获取classes 目录中的类文件。应添加 MANIFEST 文件以区分哪个是主类。小心最后一个空行。

Manifest-Version: 1.0
Main-Class: HelloWorld
... blank line should be here ...

类文件是从 scala 生成的。 使用proguard @your.pro,我可以获得工作 jar 文件。

我在https://dl.dropboxusercontent.com/u/10773282/share/2015/scala_class.zip上传了示例

【讨论】:

以上是关于使用 Scala 的 Proguard - 错误 4的主要内容,如果未能解决你的问题,请参考以下文章

Android、Scala 和 Proguard

为 Scala AWS Lambda 使用 Proguard

使用 Scala 编写的库在 Android 应用上运行 Proguard

尝试使用 ProGuard 优化 Java+Scala 时出现 java.lang.***Error

Scala 可运行 JAR 的 ProGuard 进程

Proguard 警告:找不到引用的类 scala。*