Android ProGuard代码混淆

关于混淆

代码混淆(Obfuscated code)亦称花指令,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式的行为。代码混淆可以用于程序源代码,也可以用于程序编译而成的中间代码。执行代码混淆的程序被称作代码混淆器。目前已经存在许多种功能各异的代码混淆器。

众所周知,Java虽然是编译型的语言,但是由于Java编译后的字节码的抽象级别较高,因此它们较容易被反编译。为了防止我们的劳动成果被人窃取,我们通常会将Java程序混淆后打包,增大别人反编译时的难度。
当然,并不是混淆后,别人就无法反编译我们的程序了,否则这个混淆就可以改为加密了。代码混淆并不能真正阻止反向工程,只能增大其难度。因此,对于对安全性要求很高的场合,仅仅使用代码混淆并不能保证源代码的安全。混淆是将代码中的各种元素,如变量,函数,类的名字改写成无意义的名字,然后进行打包,加大别人反编译我们的程序后的理解难度。
另外,因为混淆过程中会精简被混淆的类的类、变量、函数的名字,丢弃无用类和资源,因此混淆也会在一定程度上压缩编译后的文件大小。
混淆也会给我们自己带来一些问题。首先是时间成本上的增加,虽然混淆很简单,短则一两个小时,多则一两天就可以搞定,但是这个时间成本依旧存在。更重要的是,混淆会给我们的调试带来很大的困难,精简后的类、函数、变量名,给我们定位出错带来了一定的难度。对于支持反射的Java,代码混淆有可能与反射发生冲突,因此在与反射相关的类需要避免混淆。
Android的代码混淆默认使用ProGuard工具,在Android Developer上有相关介绍。

混淆配置步骤

以Android Studio为例。

  • 首先,我们需要在Module中的build.gradle中进行混淆配置。通常,我们在混淆时,只对release版本进行混淆,debug版本混淆很明显除了给自己调试增加难度外,没任何用。配置示例如下:
apply plugin: 'com.android.application'

android {

    ...

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

minifyEnabled true即表示开启混淆。下一行proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'是指定多个混淆配置文件,getDefaultProguardFile('proguard-android.txt')表示使用默认配置文件proguard-android.txt,后面的proguard-rules.pro即为我们自己编写的混淆配置文件。

  • 在build.gradle指定的文件中,按照ProGuard语法编写混淆配置。
  • 签名打包。

ProGuard语法

#指定代码的压缩级别0-7
-optimizationpasses 5    
#是否使用大小写混合
-dontusemixedcaseclassnames    
#是否混淆第三方jar
-dontskipnonpubliclibraryclasses    
#混淆时是否做预校验
-dontpreverify   
#混淆时是否记录日志
-verbose   
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*     
#从给定的文件中读取配置参数
-include {filename}    
#指定基础目录为以后相对的档案名称
-basedirectory {directoryname}    
#指定要处理的应用程序jar,war,ear和目录
-injars {class_path}    
#指定处理完后要输出的jar,war,ear和目录的名称
-outjars {class_path}    
#指定要处理的应用程序jar,war,ear和目录所需要的程序库文件
-libraryjars {classpath}    
#指定不去忽略非公共的库类。
-dontskipnonpubliclibraryclasses   
#指定不去忽略包可见的库类的成员。
-dontskipnonpubliclibraryclassmembers    
## 保留选项
#保护指定的类文件和类的成员
-keep {Modifier} {class_specification}    
#保护指定类的成员,如果此类受到保护他们会保护的更好
-keepclassmembers {modifier} {class_specification}    
#保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。
-keepclasseswithmembers {class_specification}    
#保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)
-keepnames {class_specification}    
#保护指定的类的成员的名称(如果他们不会压缩步骤中删除)
-keepclassmembernames {class_specification}    
#保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)
-keepclasseswithmembernames {class_specification}    
#列出类和类的成员-keep选项的清单,标准输出到给定的文件
-printseeds {filename}    
## 压缩
#不压缩输入的类文件
-dontshrink    
-printusage {filename}
-whyareyoukeeping {class_specification}    
## 优化
#不优化输入的类文件
-dontoptimize    
#优化时假设指定的方法,没有任何副作用
-assumenosideeffects {class_specification}    
#优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification    
## 混淆
#不混淆输入的类文件
-dontobfuscate    
-printmapping {filename}
#重用映射增加混淆
-applymapping {filename}    
#使用给定文件中的关键字作为要混淆方法的名称
-obfuscationdictionary {filename}    
#混淆时应用侵入式重载
-overloadaggressively    
 #确定统一的混淆类的成员名称来增加混淆
-useuniqueclassmembernames   
#重新包装所有重命名的包并放在给定的单一包中
-flattenpackagehierarchy {package_name}    
#重新包装所有重命名的类文件中放在给定的单一包中
-repackageclass {package_name}    
#混淆时不会产生形形色色的类名
-dontusemixedcaseclassnames    
#保护给定的可选属性,例如LineNumberTable,LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-keepattributes {attribute_name,...}
#设置源文件中给定的字符串常量​    
-renamesourcefileattribute {string}    

混淆示例

# 指定代码的压缩级别
-optimizationpasses 5                                                          
-dontusemixedcaseclassnames    
# 是否混淆第三方jar                                                  
-dontskipnonpubliclibraryclasses                                               
-dontpreverify                                                                  
-keepattributes SourceFile,LineNumberTable                                         
-verbose                                                                        
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*        

-libraryjars libs/httpmime-4.1.3.jar
-libraryjars libs/libammsdk.jar
-libraryjars libs/fastjson-1.1.34.android.jar
-libraryjars libs/commons-lang.jar
-libraryjars libs/weibosdkcore.jar

# webview + js
# keep 使用 webview 的类
-keepclassmembers class com.goldnet.mobile.activity.InfoDetailActivity {
   public *;
}
# keep 使用 webview 的类的所有的内部类
-keepclassmembers   class com.goldnet.mobile.activity.InfoDetailActivity$*{
    *;
}

# 保持哪些类不被混淆
-keep class android.** {*; }
-keep public class * extends android.view  
-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.pm                                
-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             

-keepattributes *Annotation*

# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {                                        
    native <methods>;
}

# 保持自定义控件类不被混淆
-keepclasseswithmembers class * {                                               
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);     
}

-keepclasseswithmembers class * {
    void onClick*(...);
}
-keepclasseswithmembers class * {
    *** *Callback(...);
}

# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

# 保持枚举 enum 类不被混淆
-keepclassmembers enum * {                                                     
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# 保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {                             
  public static final android.os.Parcelable$Creator *;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

# http client
-keep class org.apache.http.** {*; }

# keep 泛型
-keepattributes Signature

# 新浪微博
-keep class com.sina.**{*;}

# volley
-dontwarn com.android.volley.jar.**
-keep class com.android.volley.**{*;}

# actionbarsherlock
-dontwarn com.actionbarsherlock.**
-keep class com.actionbarsherlock.**{*;}

-dontwarn com.cairh.app.sjkh.**
-keep class com.cairh.app.sjkh.**{*;}

混淆注意事项

根据代码混淆的原理(最主要的就是反射需要用到包名和类名方法名,而混淆会修改类名为其它无意义名字),Android代码在使用混淆使需要注意:

  1. Android系统组件应避免混淆。
  2. 被Jni调用的Java类要避免混淆。
  3. 所有的native方法不能被混淆
  4. 自定义View不应该被混淆。
  5. 枚举类不应该被混淆。
  6. 注解不应该被混淆
  7. 序列化的类(Parcelable)要避免混淆
  8. 利用GSON等解析工具解析Json的Bean类,不应该被混淆。
  9. 数据库驱动不应该被混淆。
  10. aidl文件不能被混淆
  11. Android建议不要混淆某些类,比如BackupAgent、ILicensingService等
  12. 在使用第三方工程的时候,一般会有说明混淆时候要注意哪些要避免混淆,按照其说明加入混淆配置中。

默认混淆

对于以上提到的注意事项,有些使用过混淆的朋友可能会觉得奇怪,我没有避免混淆Android系统组件,比如Activity,Service等等,为什么也没问题呢?这是因为在Android的默认配置中,已经做了相关配置,默认配置如下:

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
-dontusemixedcaseclassnames
-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).
-dontoptimize
-dontpreverify
# If you want to enable optimization, you should include the
# following:
# -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
# -optimizationpasses 5
# -allowaccessmodification
#
# Note that you cannot just include these flags in your own
# configuration file; if you are including this file, optimization
# will be turned off. You'll need to either edit this file, or
# duplicate the contents of this file and remove the include of this
# file from your project's proguard.config path property.
-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.app.backup.BackupAgent
-keep public class * extends android.preference.Preference
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment
-keep public class com.android.vending.licensing.ILicensingService
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
    native <methods>;
}
-keep public class * extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
-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.
-dontwarn android.support.**

欢迎转载,转载请保留文章出处。湖广午王的博客[http://blog.csdn.net/junzia/article/details/52879823]

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值