文章原文:https://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/examples.html
你可以在ProGuard的分布的例子目录中找到一些配置文件的示例.
要收缩,优化和混淆一个简单的JAVA应用程序,你通常会创建一个配置文件就像myconfig.pro一样,可以使用
bin/proguard @myconfig.pro
配置文件指定输入,输出和程序的入口:
-injars myapplication.jar -outjars myapplication_out.jar -libraryjars/lib/rt.jar -printmapping myapplication.map -keep public class mypackage.MyMain { public static void main(java.lang.String[]); }
注意使用
系统属性. ProGuard 在解析问件时会自动替换它.
该 -keep
选项指定要保存应用程序的入口点. 在这种情况下,访问修饰符pubic 和static并不真正需要, 因为我们知道先验该指定类和方法具有适当的访问标志.它仅仅是看起来熟悉这种方法.
需要注意的是所有类型的名称被完全指定: mypackage.MyMain
and java.lang.String[]
.
我们写了一个混淆的映射文件-printmapping,对以后需要混淆的堆栈或扩展增量混淆.
我们可以通过其他的选项进一步完善结果:
-optimizationpasses 3 -overloadaggressively -repackageclasses '' -allowaccessmodification这些选项不是必须的,他们通过执行多达3次的优化过程并积极混淆类成员和报名( package names), 从输出的jar包里去掉一些额外的字节。
一般情况下,你可能需要处理: 本地方法(native methods), 回调方法(callback methods), 枚举(enumerations), 序列化(serializable classes), bean类(bean classes),注释(annotations), and 资源文件(resource files).
mypackage.MyApplet
:-injars in.jar -outjars out.jar -libraryjars/lib/rt.jar -keep public class mypackage.MyApplet
典型的小应用程序的方法将被自动保留,因为mypackage.MyApplet是库rt.jar里面Applet类的延伸.
如果使用,你应该添加处理选项: native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files.
mypackage.MyMIDlet
:-injars in.jar -outjars out.jar -libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar -libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar -overloadaggressively -repackageclasses '' -allowaccessmodification -microedition -keep public class mypackage.MyMIDlet
注意我们现在的目标是 Java Micro Edition run-time environment of midpapi20.jar
and cldcapi11.jar
,不是 Java 标准的运行环境 rt.jar
. 你可以挑选合适的JME环境通过挑选合适包。
典型的MIDlet的方法将会被自动保留,因为mypackage.MyMIDlet是库midpapi20.jar里面MIDlet类的延伸。
该 -microedition
选项确保了JME对类文件进行预校验, producing compact StackMap
attributes.不再需要运行一个外部预校验。
如果你在一个不区分大小的平台上使用外部预校验工具时要小心.因为如果该工具解压你的处理jar的话,那么你就应该使用 ProGuard的 -dontusemixedcaseclassnames
选项.
如果适用,你应该添加处理本地方方法和资源文件的选项。
注意,你仍然需要适应相应的jad文件中MIDlet的jar文件的大小;ProGuard不会为你做这些。
mypackage.MyApplet
:
-injars in.jar -outjars out.jar -libraryjars /usr/local/java/javacard2.2.2/lib/api.jar -dontwarn java.lang.Class -overloadaggressively -repackageclasses '' -allowaccessmodification -keep public class mypackage.MyApplet
这个的配置跟MIDlet非常相似, 所不同的是,现在针对JAVA CARD的运行环境. 这个环境没有java.lang.Class,所以我们告诉ProGuard不需要担心它。
mypackage.MyXlet
:
-injars in.jar -outjars out.jar -libraryjars /usr/local/java/jtv1.1/javatv.jar -libraryjars /usr/local/java/cdc1.1/lib/cdc.jar -libraryjars /usr/local/java/cdc1.1/lib/btclasses.zip -overloadaggressively -repackageclasses '' -allowaccessmodification -keep public class mypackage.MyXlet
配置跟MIDlet非常相似,所不同的是,现在针对Java TV API的CDC的运行环境。
-injars bin/classes -outjars bin/classes-processed.jar -libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar -dontpreverify -repackageclasses '' -allowaccessmodification -optimizations !code/simplification/arithmetic -keep public class mypackage.MyActivity
我们针对androidd的运行时间,并保持activity作为切入点。预校验对DEX编译器和Dalvik虚拟机是无关紧要的,所以我们可以用 -dontpreverify
选项将其关闭.
该 -optimizations
选项禁用了一些Dalvik1.0和1.5无法处理的算法. 注意,Delvik虚拟机也不能处理 aggressive overloading (静态属性).
如果使用, 你应该添加 native methods, callback methods, enumerations, annotations, and resource files的处理。
-injars bin/classes -injars libs -outjars bin/classes-processed.jar -libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar -dontpreverify -repackageclasses '' -allowaccessmodification -optimizations !code/simplification/arithmetic -keepattributes *Annotation* -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.view.View { public(android.content.Context); public (android.content.Context, android.util.AttributeSet); public (android.content.Context, android.util.AttributeSet, int); public void set*(...); } -keepclasseswithmembers class * { public (android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public (android.content.Context, android.util.AttributeSet, int); } -keepclassmembers class * implements android.os.Parcelable { static android.os.Parcelable$Creator CREATOR; } -keepclassmembers class **.R$* { public static ; }
最重要的是,我们保持了所有可以可以通过应用程序的androidManifest.xml文件中应用的基础类。如果你的清单文件中包含其他类和方法,你可能需要指定这些为好。
我们保持注释,因为它们可能被自定义的RemoteViews使用。
我们保留所有自定义View和其他有典型构造器的类,因为它们可能会在xml布局文件中引用。
我们同样需要保留实现Parcelable接口里有static的,因为他们通过introspection(反射?)被访问。
最后,我们保持引用内部类生成的R类的static属性。以防你的代码通过反射访问这些属性。注意,编译器已经内联了这些基本属性,所以ProGuard可以删除所有这样的类(因为类没有被引用,所以不需要)。
如果你使用了Google APIs,你最好还是指定那些,例如:
-libraryjars /usr/local/android-sdk/add-ons/google_apis-7_r01/libs/maps.jar
如果你使用了google的可选许可验证库(optional License Verification Library),你可以混淆它的和你的代码。你必须保持他的ILicensingService接口的正常工作。
-keep public interface com.android.vending.licensing.ILicensingService
如果你使用的是android的兼容性库,你应该添加以下行,让ProGuard知道库引用的一些类不是在所有版本的API上都是可用的:
-dontwarn android.support.**
如果适用,你应用添加对native methods, callback methods, enumerations, and resource files的处理。 你可能还需要添加选项用于产生有用的堆栈踪迹。你可以找到一个完整的示例在example/android.pro的GroGuard里。
Android SDK (2.3及以上版本)的构建过程在默认情况下已经集成了ProGuard。你只需要启动它(发布版本)加入proguard.config=proguard.cfg到文件build.properties。如有问题,你可能要检查自动生成的文件proguard.cfg包含上面所讨论的设置。生成的Ant构建文件已经为你设置了输入和输出文件。
想了解更多信息,可以查看android sdk的官方开发指南。
-injars in.jar -outjars out.jar -libraryjars/lib/rt.jar -printmapping out.map -keepparameternames -renamesourcefileattribute SourceFile -keepattributes Exceptions,InnerClasses,Signature,Deprecated, SourceFile,LineNumberTable,*Annotation*,EnclosingMethod -keep public class * { public protected *; } -keepclassmembernames class * { java.lang.Class class$(java.lang.String); java.lang.Class class$(java.lang.String, boolean); } -keepclasseswithmembernames class * { native ; } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private 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(); }
这种配置应该保留我们曾经想要访问的库的一切。只有当
该 -keepclassmembernames选项对类$方法不是严格必须的。这些方法是在JDK1.2及以上由javac编译器和jikes的编译器分别插入来实现.class的构造器
. ProGuard 会自动检测他们,处理他们,即使他们的名字已经被混淆了。但是,其他的混淆器会根据他们的原始名字。这可能有助于保护它们。在这种情况下,这些其他的混淆器会对使用过的库进一步混淆。
“异常”属性必须被保留下来,所以编译器知道哪些异常的方法可能会抛出。
该“内部类”属性(更准确的说,它源名称的一部分)也必须保留下来,否则,对于任何可以从库外引用的内部类。javac编译器将无法找到他们。
当用jdk5.0或更高版本完成时,“signature”属性也要求能够访问一般的类型。
该 -keepparameternames
选项保持参数名称中"LocalVariableTable" and "LocalVariableTypeTable" 公开库方法的属性。有些IDE提供这些名字给正在使用这个库的开发者。
最后,我们要保留“Depreated”的属性,让属性产生有用的堆栈踪迹。
我们还得增加一些选项来处理 native methods, enumerations, serializable classes, and annotations 类,这些都有例子来讨论。
-injars in.jar -outjars out.jar -libraryjars/lib/rt.jar -printseeds -keepclasseswithmembers public class * { public static void main(java.lang.String[]); }
注意使用 -keepclasseswithmembers
. 我们不希望保留所有的类, 我们只是保留所有有main方法的类和这些方法(main).
该选项 -printseeds选项打印出哪些类恰好被保留,因此,我们肯定知道我们得到了我们想要的
如果适用, 你应该处理 native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files 这些类。
-injars in.jar -outjars out.jar -libraryjars/lib/rt.jar -printseeds -keep public class * extends java.applet.Applet
我们只是保留所有继承Applet的类
同样, -printseeds
打印出哪些恰好被保留的applet。
如果适用, 你应该处理 native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files 这些类。
-injars in.jar -outjars out.jar -libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar -libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar -overloadaggressively -repackageclasses '' -allowaccessmodification -microedition -printseeds -keep public class * extends javax.microedition.midlet.MIDlet
我们只是保留所有继承MIDlet的类
该-microedition选项确保类文件是Java Micro Edition要进行预校验的,产生 简洁的StackMap属性。它不再需要运行一个外部的预校验。
如果你在一个不区分大小写的文件系统上进行外部平台上预校验时,要小心, 像 Windows. 因为这个工具解压你的处理jar,你应该使用 ProGuard's -dontusemixedcaseclassnames
选项.
该 -printseeds
打印那些恰好被保留的midlets.
如果适用, 你应该处理 native methods and resource files 这些类选项.
请注意,你仍然必须适应相应的jad文件中的MIDlet的jar文件大小;ProGuard不会为你做这些。
-injars in.jar -outjars out.jar -libraryjars /usr/local/java/javacard2.2.2/lib/api.jar -dontwarn java.lang.Class -overloadaggressively -repackageclasses '' -allowaccessmodification -printseeds -keep public class * implements javacard.framework.Applet
我们只是保留所有继承Applet的类
该 -printseeds
打印那些恰好被保留的Applet.
-injars in.jar -outjars out.jar -libraryjars /usr/local/java/jtv1.1/javatv.jar -libraryjars /usr/local/java/cdc1.1/lib/cdc.jar -libraryjars /usr/local/java/cdc1.1/lib/btclasses.zip -overloadaggressively -repackageclasses '' -allowaccessmodification -printseeds -keep public class * implements javax.tv.xlet.Xlet
我们只是保留所有继承Xlet的类
该 -printseeds
打印那些恰好被保留的Xlet.
-injars in.jar -outjars out.jar -libraryjars/lib/rt.jar -libraryjars /usr/local/java/servlet/servlet.jar -printseeds -keep public class * implements javax.servlet.Servlet
就像保留所有xlet一样保留所有servlet。该servletAPI不是标准的运行时JAR的一部分,所以我们将其指定为库。不要忘记使用合适的路径名。
我们保留所有实现Servlet借口的类。我们适应implements这个关键词,因为它看起来在这方面很相似,但它相当于继承,尽可能与 ProGuard的有关
该 -printseeds
打印那些恰好被保留的servlet.
如果适用, 你应该处理 native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files 类选项。
-injars in.jar -injars /usr/local/java/scala-2.9.1/lib/scala-library.jar -outjars out.jar -libraryjars/lib/rt.jar -dontwarn scala.** -keepclasseswithmembers public class * { public static void main(java.lang.String[]); } -keep class * implements org.xml.sax.EntityResolver -keepclassmembers class * { ** MODULE$; } -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool { long eventCount; int workerCounts; int runControl; scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack; scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack; } -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinWorkerThread { int base; int sp; int runState; } -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinTask { int status; } -keepclassmembernames class scala.concurrent.forkjoin.LinkedTransferQueue { scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference head; scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference tail; scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference cleanMe; }
作为处理的应用,配置是基本相同的。因为Scala被编译成普通的java字节码。但是,这个例子也可以处理Scala运行库。经过处理的jar比原始的要小,比原始的代码要小(用于Scala代码示例)。
该 -dontwarn
选项告诉ProGuard在Scala运行时的一些假象(至少Scala2.9.1)。请注意,该选项应始终小心使用。( tells ProGuard not to complain about some artefacts in the Scala runtime, the way it is compiled by the scalac
compiler (at least in Scala 2.9.1 and older). Note that this option should always be used with care.)
附加 -keep选项确保一些反射访问的类和属性不会被删除和重命名。
如果适用, 你应该处理 native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files 这些类的选项。
处理本地方法(processing native methods)
如果你的应用, applet, servlet, library, 等, 包含本地方法的,你想要保留他们的名字和他们的类名,以便你仍然可以链接本地酷。下面的选项将会使用:-keepclasseswithmembernames class * { native; }
注意使用 -keepclasseswithmembernames。我们不是想保留所有的类和所有的本地方法;我们只是想保留有关的在混淆里。
ProGuard不会看你的本地代码,所以不会自动保存本地代码调用的类或者类成员。这些入口,你必须明确指出。回调方法在下面作为一个典型的例子讨论。
-keep class mypackage.MyCallbackClass { void myCallbackMethod(java.lang.String); }
这将会在那些被删除或者重命名里保留指定的类和方法。
-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }
更复杂的应用,applet,servlets,libraries等,可能包含序列化的类。这取决于它们的使用方式,它们可能需要特别注意
-keepclassmembers class * implements java.io.Serializable { private 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(); }
该 -keepclassmembers
选项确保了任何的序列化方法被保留。通过使用这个选项而不是基本的-keep选项,我们不会强迫保留所有的序列化类,只是保留了那些实际使用的。
-keepnames class * implements java.io.Serializable -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; !static !transient; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); }
该serialVersionUID
and serialPersistentFields
线会确保这些属性被保留,如果它们存在。该<属性>线保留所有的非static,非transieant属性用它们原来的名字。序列化和反序列化通过反射来处理后就会发现一致的名称。
serialVersionUID
属性。我认为原来的代码将难以维持,由于序列化的UID是从序列化类的功能列表来计算的。轻微的改变类就会改变改变序列化UID的计算。在Sun的Java对象序列化的流唯一标识符(Stream Unique Identifiers)的部分,功能列表是被指定的。下面指令至少能保证部分与原类的兼容性: -keepnames class * implements java.io.Serializable -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; !static !transient; !private ; !private ; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); }
新的选项强制保留所有的元素参与运算。此外, 用户必须手动指定所有序列化类的接口 (就像 "-keep interface MyInterface
"),因为计算UID时候,这些名字也可以使用。次优的替代方法是简单的保持所有的借口用"-keep interface *
".
注意上述方案可能保存更多的类和类成员,有些是不必要。例如大量的类实现了序列化的借口,但只有一小部分实际上永远被序列化。了解你的应用,并调整配置往往会产生更紧凑的结果。
处理bean类(Processing bean classes)
如果你的应用程序,applet,servlet,library等广泛使用反射来找你的bean类或getter,setter方法,那么配置可能变得非常痛苦。 确保bean类的名字或者setter,getter的名字不会改变就会非常重要,例如:-keep public class mypackage.MyBean { public void setMyProperty(int); public int getMyProperty(); } -keep public class mypackage.MyBeanEditor
如果有太多的元素需要明确列出,类名字和方法通配符可能就会非常有用。这个例子包含了mybeans包里所有类里所有可能的setters,getters:
-keep class mybeans.** { void set*(***); void set*(int, ***); boolean is*(); boolean is*(int); *** get*(); *** get*(int); }
该'***'通配符匹配任何类型(原始的或非原始的,数组或非数组)。带有'int'参数的方法匹配列出的属性。
处理注解(Processing annotations)
如果你的应用程序,applet,servlet,library等使用了注解,你可能想在处理输出的时候保留它们。 注解是对代码的执行没有直接影响的属性的表示。不过,它们的值可以通过反射来取回,而且允许开发人员相应的调整执行行为。默认情况下,ProGuard对待注解属性是随意的,它们会在混淆的时候被删除,如果需要,你必须明确指出,就像这样:-keepattributes *Annotation*
为了简便起见,我们指定一个通配符属性名称,它将匹配RuntimeVisibleAnnotations
, RuntimeInvisibleAnnotations
, RuntimeVisibleParameterAnnotations
,RuntimeInvisibleParameterAnnotations
, and AnnotationDefault
。根据处理的代码的作用,可以改进该选项,例如不保留运行时不可见的注释(它只在编译的时候使用)。
一些代码可以进一步利用发射弄清除匿名内部类封装的方法。在这种情况下,相应的属性必须被保留:
-keepattributes EnclosingMethod
数据库驱动程序实现了驱动程序借口。由于它们经常是动态创建,你可能想保留那些正在处理作为入口的实现类。
-keep class * implements java.sql.Driver
该选项还摆脱了ProGuard的使出有关(java.sql.Driver)的Class.forName的构造器,如果你在代码里实例化驱动程序(而不是必须实现自己的任何驱动程序)。
-keep class * extends javax.swing.plaf.ComponentUI { public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent); }
这个方法也保留自己的类名。
-keepattributes Exceptions -keep interface * extends java.rmi.Remote {; } -keep class * implements java.rmi.Remote { (java.rmi.activation.ActivationID, java.rmi.MarshalledObject); }
第一个-keep选项让你保留所有的远程接口和它们的方法。第二个保留所有实现类中有RMI特殊构造器的,如果有的话。
第二个异常必须被保留,因为RMI处理代码会通过反射来检查方法签名是否兼容。
-adaptresourcefilenames **.properties,**.gif,**.jpg -adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF
在这种情况下,-adaptresourcefilenames选项重命名属性文件和图片文件在处理输出的基础上(如果有的话)。该-adaptresourcefilecontents选项会在属性文件和清单文件中找这些名字,并通过混淆的名称来替换这些名称(如果有的话)。你可能回想适配过滤器,来满足你的应用。
如果你打算合并几个输入jars到一个输出jar里,你需要选择一个,通常通过过滤器指定:
-injars in1.jar -injars in2.jar(!META-INF/MANIFEST.MF) -injars in3.jar(!META-INF/MANIFEST.MF) -outjars out.jar
该过滤器将会复制第一个jar里的清单文件并忽略第二个和第三个输入jar里的清单文件。需要中的的是ProGuard将会保留jar里文件的顺序不做改变;清单文件不一定放到第一个。
-printmapping out.map -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable
我们保留所有的资源文件属性,但是我们可以通过字符串“SourceFile”替换它们的值。我们可以使用任何字符串。这个字符串已经存在于所有的类文件里,因此它不占用任何额外的空间。如果你正在使用J++,你想要保留“SourceDir”的属性。
我们还需要保留所有方法的表的行号。
当这两个属性都存在,在Java运行时将打印出异常的堆栈踪迹时将会有行号的信息。
该信息仅在我们映射混淆名称返回到原始名称的时候有用,因此我们需要保存映射文件out.map。该信息可用于通过恢复工具来恢复原始堆栈踪迹。
mycompany.myapplication.MyMain mycompany.myapplication.Foo mycompany.myapplication.Bar mycompany.myapplication.extra.FirstExtra mycompany.myapplication.extra.SecondExtra mycompany.util.FirstUtil mycompany.util.SecondUtil
让我们假设类名mycompany.myapplication.MyMain是被配置保留的主应用程序类。其他所有的类名都可以被混淆。
默认情况下,包里包含不能重命名的类的话,包名也不能重命名,这样包名就被保留了。混淆后的类名称就像这样:
mycompany.myapplication.MyMain mycompany.myapplication.a mycompany.myapplication.b mycompany.myapplication.a.a mycompany.myapplication.a.b mycompany.a.a mycompany.a.b
该-flattenpackagehierarchy
选项进一步混淆包名,通过扁平化混淆包的包层次:
-flattenpackagehierarchy 'myobfuscated'
混淆后的类名如下所示:
mycompany.myapplication.MyMain mycompany.myapplication.a mycompany.myapplication.b myobfuscated.a.a myobfuscated.a.b myobfuscated.b.a myobfuscated.b.b
另外,-repackageclasses选项混淆整个包,由混淆的类组成的一个单一的包。
-repackageclasses 'myobfuscated'这时,混淆后的类名如下:
mycompany.myapplication.MyMain mycompany.myapplication.a mycompany.myapplication.b myobfuscated.a myobfuscated.b myobfuscated.c myobfuscated.d
另外指定的 -allowaccessmodification
选项允许类和类成员的访问权限被放大,给重新打包混淆类提供机会:
-repackageclasses 'myobfuscated' -allowaccessmodification这时,混淆后的类名如下:
mycompany.myapplication.MyMain myobfuscated.a myobfuscated.b myobfuscated.c myobfuscated.d myobfuscated.e myobfuscated.f
指定的目标包永远是根目录的包。例如:
-repackageclasses '' -allowaccessmodification混淆类名后,最短的名字:
mycompany.myapplication.MyMain a b c d e f
注意,不是所有级别的包名称的混淆都是代码可以接受的。值得注意的是,你可能不的不考虑将你的应用程序包含不得不配置的资源文件。
-injars classes -injars in1.jar -injars in2.jar -injars in3.jar -outjars out.jar
这个配置把一个类文件夹和3个jar包合并到一个单一的输出jar里out.jar。
如果你想保留输入Jar的结构(或 wars, ears, zips, or directories),你可以指定一个输出的目录 (或 a war, an ear, or a zip). 例如:
-injars in1.jar -injars in2.jar -injars in3.jar -outjars out
输入jar就会在目录中重建出来,用原来的名字。
你也可以将其归档到更高级别的档案。例如
-injars in1.jar -injars in2.jar -injars in3.jar -outjars out.war
其他的方法,你可以配合更高层次档案成简单的档案。
-injars in.war -outjars out.jar
该配置将所有jars里面的in.war处理内容(加上in.war任何其他内容)放到out.jar里。
如果你想拼合输入的jar(和/或 wars, ears, zips, or directories)输出的jars (和/或 wars, ears, zips, or directories), 你可以组合-injars和-outjars选项。例如:
-injars base_in1.jar -injars base_in2.jar -injars base_in3.jar -outjars base_out.jar -injars extra_in.jar -outjars extra_out.jar
该配置将所有的base_in的*.jar处理放到base_out.jar里,把extra_in.jar处理结果放到extra_out.jar里。需要注意的是,额外的空格只是为了显示更清晰。
这个分组,归档和扁平化和可以任意组合。 ProGuard 总是试图用一个合理的方式打包输出文档,尽量按要求重建输入项。
-injars in.jar(!images/**) -outjars out.jar
这个配置移除了图片目录和其子目录的所有文件。
这种过滤器可以方便的避免有关输出时候的重复文件。例如,只保留第一个输入jar里面的清单文件:
-injars in1.jar -injars in2.jar(!META-INF/MANIFEST.MF) -injars in3.jar(!META-INF/MANIFEST.MF) -outjars out.jar
另一个有用的应用程序是通过ProGuard忽略大量不相关的运行时库jar的类来加速处理。
-libraryjars/lib/rt.jar(java/**,javax/**)
过滤器使ProGuard过滤com.sun.**类,事实上,这不影响普通应用的处理。
另外,也可以在过滤jar(wars,ears,zips)本身,它们的名字,例如:
-injars in(**/acme_*.jar;) -outjars out.jar
注意过滤器的分号,在它前面的过滤器适用于jar包的名i在。在这种情况下,只有 acme_*.jar
包是从它的目录和子目录读的。 过滤器对war的名字,ear的名字和zip的名字可以添加额外的前缀。所有类型的过滤器可以组合。它们是有交互的。
另一方面,你还可以过滤输出,以控制哪些内容去哪里。例如:
-injars in.jar -outjars code_out.jar(**.class) -outjars resources_out.jar
该配置分割处理输出,把**.class文件发送到code_out.jar里,把其他的所有文件发送到resources_out.jar里。
再次声明,过滤器是可以任意组合的,尤其是当输入和输出结合的时候。
最简单的方法是指定你的输入Jar(和/或wars,ears,zips,和directories)和一个输出目录。ProGuard将会在这个目录里用原来的jar名字重建输入jar。
-injars application1.jar -injars application2.jar -injars application3.jar -outjars processed_applications
处理后,该目录processed_application将包含一个处理的应用程序的jar的版本,具有它的名字。
-injars proguardgui.jar -outjars proguardgui_out.jar -injars proguard.jar -outjars proguard_out.jar -libraryjars/lib/rt.jar -applymapping proguard.map -keep public class proguard.gui.ProGuardGUI { public static void main(java.lang.String[]); }
我们正在阅读的这2个未处理的jar作为输入。它们的处理内容将转到相应的输出jar。该-applymapping选项,确保代码的ProGuard的部分得到先前产生混淆的映射。最终的应用程序将包括混淆的ProGuard的jar和附加混淆的GUI的jar。
在这个例子中所添加的代码是明确的;它不会影响原有的代码。该proguard_out.jar与初始化步骤产生的是相同的。如果你预想增加更多复杂的代码来扩展你的代码,你应该在原来处理步骤指定选项--useuniqueclassmembernames, -dontshrink, 和-dontoptimize。这些选项确保混淆jar将始终保持可以,没有改变。然后,你可以知道基础的jar作为库jar:
-injars proguardgui.jar -outjars proguardgui_out.jar -libraryjars proguard.jar -libraryjars/lib/rt.jar -applymapping proguard.map -keep public class proguard.gui.ProGuardGUI { public static void main(java.lang.String[]); }
即使,你对收缩,优化,混淆你的midlets不感兴趣,如MIDlet所示的例子, 你仍然可以使用Java Micro Edition的ProGuard预校验的类文件。ProGuard产生比传统的外部预校验器稍微更简洁的结果。
-injars in.jar -outjars out.jar -libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar -libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar -dontshrink -dontoptimize -dontobfuscate -microedition
我们不处理输入,只是确保目标的类文件被Java Micro Edition的-microedition选项进行预校验。需要注意的是,我们不需要任何-keep选项来指定入;所有类文件只是预校验。
-injars in.jar -outjars out.jar -libraryjars/lib/rt.jar -dontshrink -dontoptimize -dontobfuscate -target 1.6
我们不处理输入,只需要通过-target选项重定向类文件。它们将被java6自动预校验。需要注意的是,我们不需要任何-keep选项来指定入口;所有的类文件只是更新和预校验。
-injars in.jar -libraryjars/lib/rt.jar -dontoptimize -dontobfuscate -dontpreverify -printusage -keep public class mypackage.MyApplication { public static void main(java.lang.String[]); }
我们不指定输出的jar,只是打印出一些结果。我们通过跳过其他处理步骤节省了一些时间。
Java编译器内联原始的常量和字符串常量(static final 属性的)。因此ProGuard通过分析列出那些类文件没有使用的属性,即使它们在源文件中使用。我们可以添加一个-keepclassmembers选项,保留这些字段,以免它们被列出:
-keepclassmembers class * { static final % *; static final java.lang.String *; }
这些选项打印出输入jar里所有类文件的内部结构:
-injars in.jar -dontshrink -dontoptimize -dontobfuscate -dontpreverify -dump
注意我们不需要指定java运行的jar,因为我们不处理输入jar。
你可以在目录中找到例子/注解/lib中ProGuard的分布一组预定义的注解。注释类在annotations.jar定义。 在相应的ProGuard的配置(或meta-configuration,如果你喜欢)中指定annotations.pro。使用这些文件,你可以注释你的代码。例如,java源文件Application.java可以注释如下:
@KeepApplication public class Application { .... }
应用程序的ProGuard的配置文件可以借助于这些注解来简化:
-injars in.jar -outjars out.jar -libraryjars/lib/rt.jar -include lib/annotations.pro
注释实际上是在替换应用程序依赖的 -keep选项。你可能仍然希望那个添加传统的-keep选项处理native methods, enumerations, serializable classes, and annotations。
目录的例子/注解中包含许多的例子,说明了一些可能性。