本文主要ProGuard常用语法、标准proguard.cfg文件内容、常用proguard.cfg代码段及proguard与log level结合解决debug模式日志问题。关于ProGuard的作用、使用及bug分析可见ProGuard的作用、使用及bug分析。
1、ProGuard的常用语法
-libraryjars class_path 应用的依赖包,如android-support-v4
-keep [,modifier,...] class_specification 不混淆某些类
-keepclassmembers [,modifier,...] class_specification 不混淆类的成员
-keepclasseswithmembers [,modifier,...] class_specification 不混淆类及其成员
-keepnames class_specification 不混淆类及其成员名
-keepclassmembernames class_specification 不混淆类的成员名
-keepclasseswithmembernames class_specification 不混淆类及其成员名
-assumenosideeffects class_specification 假设调用不产生任何影响,在proguard代码优化时会将该调用remove掉。如system.out.println和Log.v等等
-dontwarn [class_filter] 不提示warnning
关于proguard更多语法可见:http://proguard.sourceforge.net/index.html#manual/usage.html
2、标准proguard.cfg文件内容
参考android标准,修改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# see http://sourceforge.net/tracker/?func=detail&aid=2787465&group_id=54750&atid=474707 -optimizations !code/simplification/arithmetic -optimizations !code/simplification/cast -allowaccessmodification # To prevent name conflict in incremental obfuscation. -useuniqueclassmembernames # dex does not like code run through proguard optimize and preverify steps. -dontoptimize -dontpreverify # Don't obfuscate. We only need dead code striping. # -dontobfuscate # Add this flag in your package's own configuration if it's needed. #-flattenpackagehierarchy # Some classes in the libraries extend package private classes to chare common functionality # that isn't explicitly part of the API -dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclassmembers # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native -keepclasseswithmembernames class * { native <methods>; } # class$ methods are inserted by some compilers to implement .class construct, # see http://proguard.sourceforge.net/manual/examples.html#library -keepclassmembernames class * { java.lang.Class class$(java.lang.String); java.lang.Class class$(java.lang.String, boolean); } # Keep classes and methods that have the guava @VisibleForTesting annotation -keep @com.google.common.annotations.VisibleForTesting class * -keepclassmembers class * { @com.google.common.annotations.VisibleForTesting *; } # Keep serializable classes and necessary members for serializable classes # Copied from the ProGuard manual at http://proguard.sourceforge.net. -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 <fields>; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # Please specify classes to be kept explicitly in your package's configuration. # -keep class * extends android.app.Activity # -keep class * extends android.view.View # -keep class * extends android.app.Service # -keep class * extends android.content.BroadcastReceiver # -keep class * extends android.content.ContentProvider # -keep class * extends android.preference.Preference # -keep class * extends android.app.BackupAgent -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } # The support library contains references to newer platform versions. # Don't warn about those in case this app is linking against an older # platform version. We know about them, and they are safe. # See proguard-android.txt in the SDK package. -dontwarn android.support.** |
源文件见<android_root>/build/core/proguard.flags , 将14行 -dontobfuscate解除注释。
3、常用proguard.cfg代码段
不混淆某类的构造方法,需指定构造函数的参数类型,如JSONObject
1 2 3 |
-keepclassmembers class cn.trinea.android.common.service.impl.ImageCache { public <init>(int); } |
不混淆某个包所有类或某个类class、某个接口interface, 不混淆指定类则把**换成类名
1 |
-keep class cn.trinea.android.common.** { *; } |
不混淆指某个方法,*可换成指定的方法或类名
1 2 3 |
-keepclassmembers class cn.trinea.android.common.service.impl.ImageCache { public boolean get(java.lang.String, android.view.View); } |
不混淆Parcelable的子类,防止android.os.BadParcelableException
1 2 3 |
-keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } |
添加android-support-v4.jar依赖包
1 2 3 4 |
-libraryjars libs/android-support-v4.jar -dontwarn android.support.v4.** -keep class android.support.v4.** { *; } -keep interface android.support.v4.app.** { *; } |
4、proguard与log level结合解决debug模式Log问题
常见的Android debug日志的打法是定义一个静态变量DEBUG_STATUS,如果为true,则打印log,否则不打印。对于release模式该变量为false,debug模式变量为true。这里介绍一个更好的方法,不用担心正式发布时一不小心错改了该变量。
proguard的作用就是在release模式压缩、优化、混淆代码,其中的压缩和优化就包括去除不必要的代码,我们可以利用这一特性解决debug日志的问题,在proguard.cfg中添加
1 2 3 4 |
-assumenosideeffects class android.util.Log { public static *** d(...); public static *** v(...); } |
表示Log.d和Log.v代码无副作用,在proguard时会被从源码中remove掉,这样release模式(正式发布)就不会打印日志了,而debug模式(平常调试)照常打印,不用修改一点代码大赞吧,嘿嘿。当然这种方式有个弊端,如果使用拼接字符串方式,拼接的操作还是会存在的,如何优雅的屏蔽掉 Debug 版日志也可以参考:Android Debug 版本判断及为什么 BuildConfig.DEBUG 始终为 false
1
想请问下大神,就是混淆的时候有没有办法保证方法的参数名字不被混淆?比如void print(String name),混淆之后参数名字还是叫name,而不是param1之类的无具体含义的。
这个貌似不行,对于编译器来说本质上参数就是无意义的
-keepparameternames
-libraryjars 和 -keep class 在 AndroidStudio 中不可以一起使用,否则用 Gradle 构建会提示 declared twice, 我是去掉 -libraryjars 解决的
[赞]
去除log的功能,虽然log没打出来,传递的参数还是会求值吧我测试用Log.d(TAG, f());, f()里两句话 System.err.println(“error test”); return “error test” + System.currentTimeMillis();,发现System.err.println还是执行了。有没有办法让Log.d的参数不求值
是的,参数确实还是会被执行,你这里可以考虑将 System.out.println 也混淆掉,err 最好还是留着。如果参数是字符串拼接,目前就没有太好的方式通过混淆去掉了。
if(BuildConfig.DEBUG) Log.d();
http://blog.csdn.net/u013220682/article/details/43446995,是不是抄袭博主的
哈哈,貌似他连颜色都没改
去除 log 的功能是不是已经失效了?
没有啊,我之前测试过正常啊,你那边有问题吗。