本文已授权微信公众号:鸿洋【hongyangAndroid】独家发布
2018年第一篇,新年快乐!
一、混淆的目的
一款发布到市场的软件原则上都应该做代码混淆。可能有人会说,谁有功夫破解你的烂代码呢?但实际上,即使没有恶意攻击者,混淆也有助于保护自己的知识产权和商业机密。因此,在发布软件之前,开启代码混淆是一个值得考虑的安全措施。
二、开启混淆
要开启Android Studio中的代码混淆功能,请按照以下步骤操作:
1. 在app module的build.gradle文件中添加以下代码:
```groovy
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
```
2. 在release构建类型中,将minifyEnabled设置为true,并启用shrinkResources选项。这样可以确保在发布时对资源文件进行压缩。
三、编写混淆配置文件
要使用混淆配置文件来设置混淆规则,请按照以下步骤操作:
1. 在app module的build.gradle文件中添加以下代码:
```groovy
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
```
这将告诉ProGuard在处理项目时使用默认的混淆配置文件(proguard-android.txt)以及自定义的混淆规则文件(proguard-rules.pro)。
2. 在项目的根目录下创建一个名为proguard-rules.pro的文件,并在其中添加自定义的混淆规则。例如:
```java
# 保留所有类名不被修改
-keep class * { public protected *; }
# 保留所有实现了某接口的类不被移除或修改
-keep class * implements com.example.MyInterface { *; }
# 保留所有继承了某类的类不被移除或修改
-keep class * extends com.example.MyBaseClass { *; }
```
以上示例展示了如何保留某些类和接口不被混淆。你可以根据自己的需求编写更多的混淆规则。
## ProGuard配置文件重构示例
以下是一个ProGuard配置文件的重构示例:
```plaintext
# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
# 混淆时不使用大小写混合类名
-dontusemixedcaseclassnames
# 不跳过库中非public的类,以打印混淆的详细信息并保留注解中的参数
-dontskipnonpubliclibraryclasses -verbose -keepattributes *Annotation*
# 关闭优化(原因见上面的原英文注释)
-dontoptimize -dontpreverify
# 不混淆包含native方法的类的类名以及native方法名
-keepclasseswithmembernames class * { native <methods>; }
# 不混淆View中的setXxx()和getXxx()方法,以保证属性动画正常工作
-keepclassmembers public class * extends android.view.View { void set*(***); ** get*(); }
# 不混淆Activity中参数是View的方法,例如,一个控件通过android:onClick="clickMethodName"绑定点击事件,混淆后会导致点击事件失效
-keepclassmembers class * extends android.app.Activity { public void *(android.view.View); }
# 不混淆枚举类中的values()和valueOf()方法
-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }
# 不混淆Parcelable实现类中的CREATOR字段,以保证Parcelable机制正常工作
-keepclassmembers class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator CREATOR; }
# 不混淆R文件中的所有静态字段,以保证正确找到每个资源的id
-keepclassmembers class **.R$* { public static <fields>; }
# 对android.support包下的代码不警告(如果我们打包的版本低于support包下某些类的使用版本,会出现警告的问题)
-dontwarn android.support.**
# 不混淆Keep类和使用了注解的类、类成员、字段和构造函数
-keep class android.support.annotation.Keep { *; **getters**; **setters**; *; **constructors**; **methods**; **fields**; @*} -keepattributes *Annotation*
```
以下是重构后的内容:
proguard-android.txt 文件:
```
-keep
关键字 含义
keep 保留类和类成员,防止被混淆或移除
keepnames 保留类和类成员,防止被混淆,但没有被引用的类成员会被移除
keepclassmembers 只保留类成员,防止被混淆或移除
keepclassmembernames 只保留类成员,防止被混淆,但没有被引用的成员会被移除
keepclasseswithmembers 保留类和类成员,防止被混淆或移除,如果指定的类成员不存在还是会被混淆
keepclasseswithmembernames 保留类和类成员,防止被混淆,如果指定的类成员不存在还是会被混淆,没有被引用的类成员会被移除
相关通配符:
```
示例:
```
.com.othershe.test.Person
com.othershe.test.*
com.othershe.*.com.othershe.test.*****
getName(***) String getName(String) void setName(...) void setName(String firstName, String secondName)
```
app module 下的 proguard-rules.pro 文件:
```
AndroidManifest.xml
android.support.v4.app.Fragment
# 不混淆 Fragment 的子类类名以及 onCreate()、onCreateView() 方法名
-keep public class * extends android.support.v4.app.Fragment {
public void onCreate(android.os.Bundle);
public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
}
不混淆某个特定的类和类中所有成员
-keep class com.othershe.test.utils.CommonUtil { *; }
```
请根据提供的内容完成内容重构,并保持段落结构:
```
# com.othershe.test.model代表数据bean所在的全包名目录 -keep class com.othershe.test.model.** { *; }
Gson
Field field = service.getField("BASE_URL");
BASE_URL
保留泛型
-keepattributes Signature
保留用于调试堆栈跟踪的行号信息(为了后期调试方便,建议配置)
-keepattributes SourceFile,LineNumberTable
如果使用了上一行配置,还需要添加如下配置将源文件重命名为
SourceFile
,以便通过鼠标点击直达源文件:
-renamesourcefileattribute SourceFile
WebViewJS
-keepclassmembers class fqcn.of.javascript.interface.for.webview { public *; }
library
```
在Android项目中,为了避免编译器警告,我们需要使用`-dontwarn`和`-keep`选项来控制。以下是针对OkHttp、Retrofit、RxJava、Gson、ButterKnife和EventBus等库的配置:
```xml
# OkHttp
```
四、查看混淆结果在Android Studio中,可以通过以下步骤查看混淆结果:
1. 打开app module的build文件夹下的outputs文件夹;
2. 选择release文件夹;
3. 在release文件夹下,可以找到以下文件:dump.txt、apkmapping.txt、resources.txt、seeds.txt和usage.txt。这些文件分别用于查看APK的混淆信息、类映射关系、资源文件、种子文件和使用情况。
然而,这样只能看到一个类的成员变量和方法的结构。如果想要查看一个类的具体内容,就需要对APK进行反编译。具体操作可参考Android APK反编译及重新打包流程。希望一切顺利!
五、追溯Crash堆栈信息
代码混淆后,也会导致Crash堆栈信息被混淆,难以阅读,增加定位问题位置的难度。一个混淆后的Crash堆栈信息类似这样,核心的信息都没了:
```
\tools\proguard\bin
app module/build/outputs/mapping/releasemapping.txt
```
如下图中间部分就是追溯到的原Crash堆栈信息:
```
apk
```