在Android开发完成即将发布给用户使用时,还有最后重要的一步:代码混淆,这时候,Proguard就派上用场了,大家谁也不想辛辛苦苦写的代码太容易被别人反编译过来,而Proguard就是帮我们实现这一目的的工具。关于Proguard是什么,有什么特点,可以在这个链接了解:http://proguard.sourceforge.net/,简单来说,Proguard有如下几大功能:

  •   Shink :  扫描并移除代码中无用的类、属性字段、方法                         (第一步)
  • Optomize :  对字节码进行优化,移除无用的指令                                        (第二步)
  • Obfuscate:  使用简短、无意义的字母替换类名、属性字段名等,达到混淆目的    (第三步)
  • Preverify  :  上面三步完成后,对其进行预校验                                           (第四步)

  流程如下图所示:

  

  从刚刚网站链接可以看到,Proguard可以对Java代码进行混淆从而达到基本的反编译、逆向工程保护目的,另外还有一个针对Android的商业扩展版工具: DexGuard,对于APP开发来说,可以进一步对代码进行保护,例如:加密字符串、资源文件、本地库等,而这些是Proguard缺少的。这里首先介绍Android Studio内置支持的Proguard。

  示例代码GitHub上:https://github.com/linjk/TestProguard.git

  新建一个Android工程后,Android Studio默认帮我们新建了一个混淆文件,在release配置里默认没使能混淆,如下图所示:

  

  在未进行混淆前,先生成一个发布版本的app,用于和混淆后的app进行对比,命名为:TestProguard-unproguard.apk

  下面开始进行代码混淆:

  1. 修改app/build.gradle文件下buildTypes的release使用混淆功能,即:"minifyEnabled true"

  2. 编辑proguard-rules.pro文件,编写混淆规则:

    2.1 通用混淆规则

 #代码的压缩级别, ~7之间,默认为5
-optimizationpasses
#包名不混合大小写,混淆后的类名为小写(主要针对windows用户的配置)
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#不去忽略非公共的库的类的成员
-dontskipnonpubliclibraryclassmembers
#优化 不优化输入的类文件
-dontoptimize
#不做预校验(Android不需要此步骤,跳过可加快混淆速度)
-dontpreverify
#混淆后生成映射文件-->(包含有类名->混淆后类名的映射关系)
-verbose
#指定映射文件的名称
-printmapping proguardMapping.txt
#-applymapping proguardMapping.txt #混淆时所采用的算法,谷歌推荐,一般不改变
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护代码中的Annotation不被混淆,在使用如fastJSON时的实体映射
-keepattributes *Annotation*
#避免混淆泛型,在使用如fastJSON时的实体映射
-keepattributes Signature
#抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
#忽略警告 ----- 不推荐全部忽略警告,如果确认哪些类和app无关,可以使用 -dontwarn org.apache.http.**来忽略
-ignorewarning
#记录生成的日志数据,gradle build时在本项目根目录输出
#apk 包内所有 class 的内部结构
-dump class_files.txt
#未混淆的类和成员
-printseeds seeds.txt
#列出从 apk 中删除的代码
-printusage unused.txt ################# Android默认的常用类保留不混淆 ######################
#保留所有的本地native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#保持哪些类不被混淆
-keep public class * extends android.app.Fragment
#所有Activity子类不被混淆
-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 * extends android.view.View
52
-keep public class com.android.vending.licensing.ILicensingService
#如果有引用v4包,添加下面这行
-keep public class * extends android.support.v4.app.Fragment.** {*;}
#保留在Activity中的方法参数是view的方法,从而在layout里编写的onClick不会被影响
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
#枚举类不能被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#保留自定义控件(继承自view)不被混淆
-keep public class * extends android.view.View{
** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util,AttributeSet);
public <init>(android.content.Context, android.util,AttributeSet, int);
} #保留Parcelable序列化的类不被混淆
-keep class * implements android.os.Parcelable{
public static final android.os.Parcelable$Creator *;
} #保留Serialable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable{
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistenFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
} #对于R(资源)下的所有类机器方法不能被混淆
-keep class **.R$* {
*;
} #对于带有回调函数onXXEvent的方法不能被混淆
-keepclassmembers class * {
void *(**On*Event);
}

      这部分是所有APP项目都通用的混淆规则,可以直接Ctrl+c, Ctrl+v来使用。

    2.2 针对特定APP的混淆规则

      每个APP工程都会按模块来分包开发,现在用来测试的工程只有一个默认的Activivy类,就会简单很多,但是还是有很通用的模块混淆规则的,如下:

      

 #. 保护实体类和成员
-keep public class cn.linjk.testproguard.beans.** {
public void set*(***);
public *** get*();
public *** is*();
} #. 很重要,内嵌类要保留(建议内嵌类单独文件处理,以免忘记导致后面调试查找麻烦)
-keep class cn.linjk.testproguard.activity.IndicatorActivity$*{
*;
}
-keep public class * extends android.support.v7.app.AppCompatActivity #. 数据库驱动不被混淆
#-keep class cn.linjk.testproguard.database.** {*;} #. 对webView的处理
-keepclassmembers class * extends anroid.webkit.webViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
} -keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.webView, java.lang.String);
} # . 网络请求包不被混淆
-keep class cn.linjk.testproguard.networkservice.** {*;} # . adapter不被混淆
-keep class cn.linjk.testproguard.adapter.** {*;} #. 第三方SDK的混淆处理(第三方SDK包一般都是经过混淆了,这里是避免这些SDK的类和方法在该app中被混淆,在sdk官网都会列出混淆规则,复制粘贴就行了,*.so文件不必理会)
# butterknife
-keep class butterknife.** {*;}
-keep public class cn.jpush.** {*;}
-keep public class com.google.** {*;}
-keep public class com.readystatesoftware.viewbadger.** {*;} -keep public class com.alipay.** {*;}
-dontwarn com.alipay.android.app.** -keep public class com.mob.commons.** {*;}
-keep public class com.mob.tools.** {*;} #. layout资源目录下自定义view不被混淆
-keep public class cn.linjk.testproguard.view.** {*;} #8. JavaScript调用的java原生方法不被混淆
-keepclassmembers class cn.linjk.testproguard$JSCallInterfaces {
<methods>;
}
#9. 反射类处理,如*.class.getField()/getMethod()等方法

  这两部分规则复制到proguard-rules.pro,然后发布即可进行混淆。

  经过混淆后生成的apk,命名为:TestProguard-proguard.apk,两个apk文件对比如下:

  

  可以发现,经过混淆后的apk包体积更小。

  现在来看看混淆后反编译后的文件:

  

  因为这个测试工程没有什么类,用的另外一个项目的app来进行反编译。可以看到,这里的类用了a、b、c等字母来替代了类名和方法,进一步可以在smali文件看到:

  

  这样,别人就算反编译了,也不知调用的是什么方法,那我们如何知道呢,在生成发布包后,在app/build/output/release/mapping生成了输出文件,包括哪些类哪些方法被混淆了,哪些类哪些方法被留下了,都有对应说明,我们在查看线上bug时,就要靠它们来找到对应的应用奔溃地方来进行bug修复了。生成文件如下图:

  

  最后,要补充几点重要的:

  1. 混淆后的app必须要进行monkey测试,保证每个页面都路由到,看是否会产生奔溃,然后,在进行重要功能测试,如:推送、支付、扫描、定位等。

  2. 多模块的工程,在库模块也需要进行混淆,然后在app主工程保留库的类和方法。

  

How To Use Proguard in Android APP的更多相关文章

  1. Android App 性能优化实践

    本文记录了Android App优化需要用到的工具和以及在实践中的Tips.也算对我这半年来部分工作的总结. 工具 Hierarchy Viewer 是 Android SDK 自带的 Layout ...

  2. 携程Android App插件化和动态加载实践

    携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...

  3. apk反编译(6)ProGuard 工具 android studio版官方教程[作用,配置,解混淆,优化示例]

    ProGuard In this document Enabling ProGuard (Gradle Builds) Configuring ProGuard Examples Decoding O ...

  4. 【转】can't find referenced method 'android.app.RemoteInput[] getRemoteInputs()' in class android.app.Notification$Action

    原文网址:http://stackoverflow.com/questions/25508735/cant-find-referenced-method-android-app-remoteinput ...

  5. Android APP 性能优化的一些思考

    说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了很多文件,然后用手机管家 APP 不断地进行清理优化 ,才 ...

  6. 携程Android App的插件化和动态加载框架

    携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...

  7. 包建强的培训课程(6):Android App瘦身优化

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  8. Android app 性能优化的思考--性能卡顿不好的原因在哪?

    说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了很多文件,然后用手机管家 APP 不断地进行清理优化 ,才 ...

  9. android app性能优化大汇总

    这里根据网络上各位大神已经总结的知识内容做一个大汇总,作为记录,方便后续“温故知新”. 性能指标: (1)使用流畅度:  图片处理器每秒刷新的帧数(FPS),可用来指示页面是否平滑的渲染.高的帧率可以 ...

随机推荐

  1. 网页兼容浏览器测试工具Multibrowser

    网页兼容性测试工具(MultiBrowser),有firefox,chrome,IE 下载

  2. CSS3实现背景颜色渐变 摘抄

    一. Webkit浏览器 (1) 第一种写法: background:-webkit-gradient(linear ,10% 10%,100% 100%, color-stop(0.14,rgb(2 ...

  3. 【转载】javaAgent 参数

    -javaagent 这个JVM参数是JDK 5引进的. java -help的帮助里面写道: -javaagent:<jarpath>[=<options>] load Ja ...

  4. 爆料喽!!!开源日志库Logger的剖析分析

    导读 Logger类提供了多种方法来处理日志活动.上一篇介绍了开源日志库Logger的使用,今天我主要来分析Logger实现的原理. 库的整体架构图 详细剖析 我们从使用的角度来对Logger库抽茧剥 ...

  5. Android学习笔记(十四)——自定义广播

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 我们除了可以通过广播接收器来接收系统广播, 还可以在应用程序中发送自定义的广播.下面我们来分别试一试发送自定义 ...

  6. 数据流图DFD画法

    数据流图(DFD- Data Flow Diagram)让系统分析者弄清楚"做什么"的问题,其重要性就不言而喻了.那么我们怎么画数据流图呢?数据流图与系统流程图又有什么区别呢? 步 ...

  7. POJ 1390 Block

    Description 给你一堆块,每个块有颜色,每次可以消去相邻颜色块,并获得块大小平方的分数,求最高得分. Sol DP/记忆化搜索. \(f[i][j][k]\) 表示 \((i,j)\) 这个 ...

  8. 11 AlarmHandler定时处理类——Live555源码阅读(一)基本组件类

    这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...

  9. Linux nohup 程序后台运行

    &方式: Unix/Linux下一般想让某个程序在后台运行,很多都是使用 & 在程序结尾来让程序自动运行.比如我们要运行mysql在后台:          /usr/local/my ...

  10. 【实例】html5-canvas中实现背景图片的移动

    本例来自于<HTML5 Canvas核心技术 图形.动画与游戏开发> 在线演示 (图有点多,请多刷新几次) 本例还有一点代码不理解,我用注释和问号标注出来了,有大神看到求解答,谢谢 本例子 ...