Android 混淆 (不定期完善第三方混淆规则)

2/13/2017来源:iOS开发人气:1028

开启混淆

在AS中,借助于SDK中自带的PRoguard工具,开启混淆只需要在release闭包中添加如下两行代码:

release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' }

其中minifyEnabled表示是否开启混淆,开启后打包出的apk就是混淆过的了。

有些代码如果被混淆了就会报错,因此需要混淆规则来定义那些不能混淆的代码。

proguard-android.txt是默认的混淆规则,该文件位于fake-path—sdk\tools\proguard目录下,它对本机上所有项目的混淆都生效,所以一般不改动这个文件。

proguard-rules.pro默认在每个项目的app模块中,我们可以在这个文件中编写适用于当前项目的混淆规则。

默认情况下,这样的写法会使两个文件中的混淆规则同时生效。

混淆语法

keep关键字

proguard中一共有三组六个keep关键字,区别如下:

关键字 描述
keep 保留类和类中的成员,防止它们被混淆或移除。
keepnames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
keepclassmembers 只保留类中的成员,防止它们被混淆或移除。
keepclassmembernames 只保留类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
keepclasseswithmembers 保留类和类中的成员,防止它们被混淆或移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。
keepclasseswithmembernames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。

通配符

通配符 描述
<field> 匹配类中的所有字段
<method> 匹配类中的所有方法
<init> 匹配类中的所有构造函数
* 匹配任意长度字符,但不含包名分隔符(.)。但如果你不写任何其它内容,只有一个*,那就表示匹配所有的东西。
** 匹配任意长度字符,并且包含包名分隔符(.),包括任意长度的子包。
*** 匹配任意参数类型。比如void set*()就能匹配任意传入的参数类型, get*()就能匹配任意返回值的类型。
匹配任意长度的任意类型参数。比如void test(…)就能匹配任意void test(String a)或者是void test(int a, String b)这些方法。

默认混淆规则

下面是proguard-android.txt文件中的内容(手动加了注释):

# This is a configuration file for ProGuard. # http://proguard.sourceforge.net/index.html#manual/usage.html #混淆时不使用大小写混合类名。 -dontusemixedcaseclassnames #不跳过library中的非public的类。 -dontskipnonpubliclibraryclasses #混淆后产生映射文件 #包含有类名->混淆后类名的映射关系 -verbose # Optimization is turned off by default. Dex does not like code run # through the ProGuard optimize and preverify steps (and performs some # of these optimizations on its own). #不进行优化,建议使用此选项,因为根据proguard-android-optimize.txt中的描述,优化可能会造成一些潜在风险,不能保证在所有版本的Dalvik上都正常运行。 -dontoptimize #不进行预校验。这个预校验是作用在java平台上的,Android平台上不需要这项功能,去掉之后还可以加快混淆速度。 -dontpreverify # Note that if you want to enable optimization, you cannot just # include optimization flags in your own project configuration file; # instead you will need to point to the # "proguard-android-optimize.txt" file instead of this one from your # project.properties file. #对注解中的参数进行保留。 -keepattributes *Annotation* #不混淆声明的这两个类,这两个类我们基本也用不上,是接入Google原生的一些服务时使用的。 -keep public class com.google.vending.licensing.ILicensingService -keep public class com.android.vending.licensing.ILicensingService # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native #不混淆任何包含native方法的类的类名以及native方法名,但当成员没有被引用时会被移除 -keepclasseswithmembernames class * { native <methods>; } # keep setters in Views so that animations can still work. # see http://proguard.sourceforge.net/manual/examples.html#beans #不混淆任何一个View中的setXxx()和getXxx()方法,因为属性动画需要有相应的setter和getter的方法实现,混淆了就无法工作了。 -keepclassmembers public class * extends android.view.View { void set*(***); *** get*(); } # We want to keep methods in Activity that could be used in the xml attribute onClick #不混淆Activity中参数是View的方法,因为有这样一种用法,在XML中配置android:onClick=”buttonClick”属性,当用户点击该按钮时就会调用Activity中的buttonClick(View view)方法,如果这个方法被混淆的话就找不到了。 -keepclassmembers class * extends android.app.Activity { public void *(android.view.View); } # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations #不混淆枚举中的values()和valueOf()方法 -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } #不混淆Parcelable实现类中的CREATOR字段,毫无疑问,CREATOR字段是绝对不能改变的,包括大小写都不能变,不然整个Parcelable工作机制都会失败。 -keepclassmembers class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator CREATOR; } #不混淆R文件中的所有静态字段,我们都知道R文件是通过字段来记录每个资源的id的,字段名要是被混淆了,id也就找不着了。 -keepclassmembers class **.R$* { public static <fields>; } # 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. #对android.support包下的代码不警告,因为兼容库的中代码是安全的 -dontwarn android.support.** # Understand the @Keep support annotation. #不混淆keep注解 -keep class android.support.annotation.Keep -keep @android.support.annotation.Keep class * {*;} -keepclasseswithmembers class * { @android.support.annotation.Keep <methods>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <fields>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <init>(...); }

自定义混淆规则

我们可以在当前项目的proguard-rules.pro中定义如下混淆规则,其中第三方混淆规则将不定期更新、完善:

##---------------Begin: proguard configuration common for all Android apps ---------- #代码混淆压缩比,在0~7之间,默认为5,一般不做修改 -optimizationpasses 5 -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclassmembers -dontpreverify -verbose -dump class_files.txt -printseeds seeds.txt -printusage unused.txt -printmapping mapping.txt #指定混淆采用的算法,后面的参数是一个过滤器 #这个过滤器是谷歌推荐的算法,一般不做更改 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* -allowaccessmodification -keepattributes *Annotation* -renamesourcefileattribute SourceFile #抛出异常时保留代码行号 -keepattributes SourceFile,LineNumberTable -repackageclasses '' #保留我们使用的四大组件,自定义的application等这些子类不被混淆 #因为这些子类都有可能被外部调用 -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.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -keep public class com.android.vending.licensing.ILicensingService -dontnote com.android.vending.licensing.ILicensingService # Explicitly preserve all serialization members. The Serializable interface # is only a marker interface, so it wouldn't save them. -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(); } # Preserve all native method names and the names of their classes. -keepclasseswithmembernames class * { native <methods>; } -keepclasseswithmembernames class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembernames class * { public <init>(android.content.Context, android.util.AttributeSet, int); } # Preserve static fields of inner classes of R classes that might be accessed # through introspection. -keepclassmembers class **.R$* { public static <fields>; } # Preserve the special static methods that are required in all enumeration classes. -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep public class * { public protected *; } -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } #实体类 -keep class com.bean.** { *; } ##---------------End: proguard configuration common for all Android apps ---------- #Gson # Gson uses generic type information stored in a class file when working with fields. Proguard # removes such information by default, so configure it to keep all of it. #避免混淆泛型 -keepattributes Signature # Gson specific classes -keep class sun.misc.Unsafe { *; } #-keep class com.google.gson.stream.** { *; } -keep class sun.misc.Unsafe.** { *; } -keep class sun.misc.Unsafe.** -keep class com.google.** { *; } #org apache -keep class org.apache.** { *; } #baidumap -keep class com.baidu.** { *; } -keep class com.baidu.** -keep class vi.com.gdi.bgl.android.**{*;} -keep class vi.com.gdi.bgl.android.** -keep class com.baidu.** {*;} -keep class vi.com.** {*;} -dontwarn com.baidu.** #chartengine -keep class org.achartengine.** { *; } -keep class org.achartengine.** #youmeng -keep class com.umeng.analytics.**{*;} -keep class com.umeng.analytics.** -keep class u.aly.** {*;} -keep class u.aly.** #alipay -keep class com.alipay.** { *; } -keep class com.alipay.** -keep class com.ta.utdid2.** { *; } -keep class com.ta.utdid2.** -keep class com.ut.device.** { *; } -keep class com.ut.device.** -keep class org.json.alipay.** { *; } -keep class org.json.alipay.** #pinyin4j -keep class com.hp.hpl.sparta..** { *; } -keep class com.hp.hpl.sparta..** -keep class demo..** { *; } -keep class demo..** -keep class net.sourceforge.pinyin4j..** { *; } -keep class net.sourceforge.pinyin4j..** #http legacy #webkit -keepclassmembers class * extends android.webkit.WebChromeClient{ public void openFileChooser(...); } #open-sdk mta-sdk libammsdk -keep class com.tencent..** { *; } -keep class com.tencent..** #zxing -keep class com.google.zxing.** { *; } -keep class com.google.zxing.** -dontwarn java.lang.invoke** -dontwarn org.apache.lang.** -dontwarn org.apache.commons.** -dontwarn com.com.nostra13.** -dontwarn com.github.** -dontwarn com.squareup.** #retrofit # Platform calls Class.forName on types which do not exist on Android to determine platform. -dontnote retrofit2.Platform # Platform used when running on RoboVM on iOS. Will not be used at runtime. -dontnote retrofit2.Platform$IOS$MainThreadExecutor # Platform used when running on Java 8 VMs. Will not be used at runtime. -dontwarn retrofit2.Platform$Java8 # Retain generic type information for use by reflection by converters and adapters. -keepattributes Signature # Retain declared checked exceptions for use by a Proxy instance. -keepattributes Exceptions -keep class com.life.me.entity.postentity{*;} -keep class com.life.me.entity.resultentity{*;} -dontwarn retrofit. -keep class retrofit. { *; } -dontwarn retrofit2.** -keep class retrofit2.** { *; } #butterknife -keep class butterknife.** { *; } -dontwarn butterknife.internal.** -keep class **$$ViewBinder { *; } -keepclasseswithmembernames class * { @butterknife.* <fields>; } -keepclasseswithmembernames class * { @butterknife.* <methods>; } #rx -dontwarn sun.misc.** -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { long producerIndex; long consumerIndex; } -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { rx.internal.util.atomic.LinkedQueueNode producerNode; } -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { rx.internal.util.atomic.LinkedQueueNode consumerNode; } #okhttp -dontwarn com.squareup.okhttp3.** -keep class com.squareup.okhttp3.** { *;} -dontwarn okhttp3.logging.** -keep class okhttp3.internal.**{*;} -dontwarn okio.**

DexGuard

对于更高的安全需求,Proguard可能有些力不从心了。而DexGuard就能提供更安全的保护,关于它的资料可以点这里

参考资料:http://blog.csdn.net/guolin_blog/article/details/50451259