为了防止自己的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。