【Developer Log】ProGuard扰码可执行JAR包
在项目上线之前需要通过ProGuard来对java的class进行混淆,以避免反编译方式,来保护自己的代码。ProGuard网上有很多资料,可以参考:http://blog.csdn.net/zhangdaiscott/article/details/45368261。在此,记录扰码可执行JAR包出现的问题,已经相关的解决方式。
1、引用第三方库的处理方式
引用第三方库,应避免修改第三方库的类名和public的方法、参数,否则在proguard回报很多warning,而执行失败。在Eclipse打包为可执行jar包时有以下的几个选择。
Extract方式是缺省的方式,会将第三方jar包解压成为具体的*.class ,然后和我们自己的*.class一起封装成为jar。Proguard会对所有class进行扰码,因此包括了第三方jar包。
最直接的方式就是让第三方jar包不参与proguard的混淆,因此我们可以选择余下两种方式,这里我选择了Package方式。我们用7Zip对jar包进行解压,会看到第三方jar包仍以jar包的方式存在。
2、可执行main要保留
我们需要保留jar包中的资源,特别是MANIFEST.MF文件,下面是这个文件的例子:
Rsrc-Class-Path: ./ log4j-core-2.4.1.jar log4j-api-2.4.1.jar gson-2.4. jar mysql-connector-java-5.1.37.jar
Class-Path: .
Rsrc-Main-Class: MyPackage.App
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
这里设计两个具有Main的可执行类MyPackage.App,和org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader(顾名思义,load第三方库的)。我们必须确保能够找到这两个类的main,也就是这两个类的全名(包名和类名)以及mian的方法名字都必须保留正确。增加一下配置即可:
-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF
-whyareyoukeeping class *
-keep public class MyPackage.App {
public static void main(java.lang.String[]);
}-keep public class org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader {
public static void main(java.lang.String[]);
}
对应与GUI中,如下几图:
有些参数是可以调整的,例如可以不选择Keep parameter
3、关于Gson
如果我们采用Gson来进行Json的处理,由于Gson和类中定义的成员名字有关,如果对这些名字进行混淆,则无法正确进行Json的解析,有两种方法处理:
1)在上图中右下方的“Keep additional names and class membe names”中选择相关的类和成员。一般这些成员都是private的。
2)更合适的方式如下,在代码中加入@SerializedName
@SerializedName("clientName")
private String clientName;
@SerializedName("ServerName")
private String ServerName;
此外,对于要封装成JSON字符串的属性,必须提供getter方法,例如上面如果不提供getClientName,则json字符串中没有该属性。对应的,如果进行解析,则必须提供setter方法。
出现一个奇怪的现象待查。如果定义一个数组Vector<String> urls,当然也给出@SerializedName("urls")。如果我们将此定义在继承类,在运行的时候会报错,如下所示。需要将此定义在基类来解决,有些奇怪,先记录下来
- 错误:java.lang.IllegalArgumentException: class c.d declares multiple JSON fields named h
- java.lang.IllegalArgumentException: class c.d declares multiple JSON fields named h
- at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:167) ~[gson-2.4.jar:?]
- at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:97) ~[gson-2.4.jar:?]
- at com.google.gson.Gson.getAdapter(Gson.java:360) ~[gson-2.4.jar:?]
- at com.google.gson.internal.bind.ArrayTypeAdapter$1.create(ArrayTypeAdapter.java:48) ~[gson-2.4.jar:?]
- at com.google.gson.Gson.getAdapter(Gson.java:360) ~[gson-2.4.jar:?]
- at com.google.gson.Gson.fromJson(Gson.java:813) ~[gson-2.4.jar:?]
- at com.google.gson.Gson.fromJson(Gson.java:752) ~[gson-2.4.jar:?]
相关链接:开发日志