为了防止自己的APP被轻易反编译,我们需要对APK进行混淆,或者特殊加密处理。可以使用“爱加密”提供的加密服务,反编译后只能看到几行代码和.so的库文件。本文将介绍如何在Android中配置混淆。
关于如何反编译Android APK,可以参考我另外一篇文章:win/mac下反编译Android安装包-APK文件,http://blog.csdn.net/dzsw0117/article/details/51429683。
一、何为混淆?
简单来说,混淆就是将原本正常的项目文件中的类、方法、字段等重新命名,使用字母a、b、c、d、e、f等来达到混淆代码的目的。这样在反编译时,代码结构会变得混乱,不易阅读。
二、官方默认的混淆配置
首先,查看官方的proguard-android.txt文件,该文件位于/tools/proguard目录下。如果不知道如何编写混淆配置,可以将该文件作为模板,复制一份到自己的工程中,并根据项目需求修改相应的混淆规则。以下是该文件的内容:
```
# 保留所有类不进行混淆
-keep public class * {
public protected *;
}
# 保留所有实现某接口的类不进行混淆
-keep class * implements com.example.MyInterface {
public protected *;
}
# 保留所有继承自某类的类不进行混淆
-keep class * extends com.example.MyClass {
public protected *;
}
# 保留所有带有某注解的类不进行混淆
-keep @com.example.MyAnnotation class * {
public protected *;
}
```
```pro
This configuration file is for ProGuard. Refer to the following link for more information: http://proguard.sourceforge.net/index.html#manual/usage.html
# Optimization turned off by default. Dex does not like code that has been run through the ProGuard optimize and preverify steps (and performs some of these optimizations on its own).
-dontoptimize
-dontpreverify
Note that if you want to enable optimization, you cannot simply 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*
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
For native methods, refer to the following link: http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * { native <methods>; }
To keep setters in Views so that animations can still work, see the following link: http://proguard.sourceforge.net/manual/examples.html#beans
-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:
-keepclassmembers class * extends android.app.Activity { public void *(android.view.View); }
For enumeration classes, refer to the following link: http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }
If an application implements `android.os.Parcelable`, keep `CREATOR` and other related fields:
-keepclassmembers class ** implements android.os.Parcelable { public static final android.os.Parcelable$Creator CREATOR; }
Don't warn about references to newer platform versions in the support library, unless this app is linking against an older platform version as we know about them and they are safe:
-dontwarn android.support.**
Understand the @Keep annotation:
-keep class android.support.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
-keepclasseswithmembers class * { @android.support.annotation.Keep
-keepclasseswithmembers class * { @android.support.annotation.Keep
-keepclasseswithmembers class * { @android.support.annotation.Keep
```
混淆是Android开发中常用的一种代码保护手段,可以有效防止反编译和代码泄露。以下是关于Android混淆的一些建议和配置:
1. 了解混淆规则
在进行混淆之前,需要了解一些通用的混淆规则,例如:view、activity、Parcelable、注解、R文件、枚举等这类的东西都不会被混淆,我们也不能混淆这些,否则release版本会报错。
2. 在Android Studio中开启混淆配置
要开启混淆,只需将minifyEnabled设置为true即可。在buildTypes中,将debug模式下的minifyEnabled设置为false,而将release模式下的minifyEnabled设置为true。示例如下:
```java
buildTypes {
release {
minifyEnabled true // true表示开启混淆配置,false表示关闭
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.duqian_android_keystore
}
debug { // 省略
}
}
```
3. Android混淆的通用规则
debug调试的apk是没有混淆的,所以无论你怎么反编译,都看到的是源码。要检验release包是否混淆,可以通过以下系统混淆配置来实现:
- dontusemixedcaseclassnames:混淆时不使用大小写混合类名
- dontskipnonpubliclibraryclasses:不跳过library中的非public的类
- verbose:打印混淆的详细信息
- dontoptimize:不进行优化,建议使用此选项
- dontpreverify:不进行预校验,Android不需要,可加快混淆速度
- ignorewarnings:忽略警告
- optimizationpasses 5:指定代码的压缩级别
4. 常用的一些混淆配置
根据项目需求,还可以使用其他一些混淆配置,例如:
- keepattributes *Annotation*:保留所有注解信息
-keepattributes Signature:保留签名信息
-keepattributes *Signature*:保留方法签名信息
-keepattributes *SourceFile*:保留源文件信息
-keepattributes *LineNumberTable*:保留行号表信息
-keepattributes *LocalVariable*:保留局部变量信息
-keepattributes *EnclosingMethod*:保留封闭方法信息
-keepattributes *Exceptions*:保留异常信息
-keepattributes *Synthetic*:保留合成字段信息(如同步块)
以下是重构后的内容:
-keepattributes Signature #范型 #native方法不混淆
-keepclasseswithmembernames class * { native <methods>; } #v4包不混淆
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class sun.misc.Unsafe { *; }
-keep class com.idea.fifaalarmclock.entity.***
-keep class com.google.gson.** { *; } #Gson混淆配置
-keepclassmembers public class cn.net.duqian.bean.** { void set*(***); *** get*(); } #JavaBean
-keep class com.xx.duqian_cloud.JavaScriptInterface { *; } #webview js
#忽略 libiary 混淆
-keep class io.vov.vitamio.** { *; } #butterknife不混淆
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; } #butterknife不混淆,看具体情况决定是否混淆。用了反射的肯定不能混淆。
Android混淆的方法和通配符对照表
1. -keepclassmembers class * { public <init> (org.json.JSONObject); } #okhttp -dontwarn okhttp3.** -keep class okhttp3.**{*;} -keep interface okhttp3.**{*;}
2. -dontwarn okio.** -keep class okio.**{*;} -keep interface okio.**{*;}
3. -dontwarn retrofit2.** -keep class retrofit2.** { *; } -keepattributes Signature -keepattributes Exceptions
4. -dontwarn rx.** -keep class rx.**{*;}
五,Android混淆的方法和通配符对照表
引用的图片,未必准确:
六,Android混淆的总结
Java的反射,为什么不能混淆呢?因为代码混淆,类名、方法名、属性名都改变了,而反射它还是按照原来的名字去反射,结果只射出一个程序崩溃,Crash,一脸的懵逼。注解用了反射,所以不能混淆。不混淆任何包含native方法的类的类名以及native方法名,否则找不到本地方法。Activity更不能混淆,因为AndroidManifest.xml文件中是完整的名字,混淆后怎么找?自定义view也是带了包名写在xml布局中,给我换成a,怎么破?R文件混淆了,id没了,界面崩溃那时自然咯。本文没有指定混淆某个类中的某个方法。
如何反编译apk,见我另外一篇文章:win/mac下反编译Android安装包-APK文件。欢迎交流,Dusan,杜乾,291902259。