天天看点

Android Progurad 代码混淆

Android Progurad 代码混淆

ref:

ProGuard基础语法和打包配置.md

https://github.com/D-clock/Doc/blob/master/Android/Gradle/3_ProGuard%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95%E5%92%8C%E6%89%93%E5%8C%85%E9%85%8D%E7%BD%AE.md

AndroidStudio下ProGuard混淆打包

https://github.com/D-clock/Doc/blob/master/Android/Gradle/4_AndroidStudio%E4%B8%8BProGuard%E6%B7%B7%E6%B7%86%E6%89%93%E5%8C%85.md

proguard-rules.pro 模板

https://github.com/AnyLifeZLB/AndroidAppFrameWork/blob/master/main/proguard-rules.pro

Proguard官方使用手册:

https://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/usage.html

代码压缩通过 ProGuard 提供,ProGuard 会检测和移除封装应用中未使用的类、字段、方法和属性,包括自带代码库中的未使用项(这使其成为以变通方式解决 64k 引用限制的有用工具)。ProGuard 还可优化字节码,移除未使用的代码指令,以及用短名称混淆其余的类、字段和方法。混淆过的代码可令您的 APK 难以被逆向工程,这在应用使用许可验证等安全敏感性功能时特别有用。

要启用资源压缩,请在 ​

​build.gradle​

​ 文件中将 ​

​shrinkResources​

​ 属性设置为 ​

​true​

​(在用于代码压缩的 ​

​minifyEnabled​

​ 旁边)。例如:

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

如果您尚未使用代码压缩用途的 ​

​minifyEnabled​

​ 构建应用,请先尝试使用它,然后再启用 ​

​shrinkResources​

​,因为您可能需要编辑 ​

​proguard-rules.pro​

​文件以保留动态创建或调用的类或方法,然后再开始移除资源。

8. 混淆技巧

混淆能让反编译的代码可读性变的很差,而且还能显著的减少APK包的大小。

1). 第一个技巧

相信很多朋友对混淆都觉得麻烦,甚至说,非常乱。因为添加混淆规则需要查询官方说明文档,甚至有的官方文档还没说明。当你引用了太多库后,添加混淆规则将使一场噩梦。

这里介绍一个技巧,不用查官方文档,不用逐个库考虑添加规则。

首先,除了默认的混淆配置(android-sdk/tools/proguard/proguard-android.txt), 自己的代码肯定是要自己配置的:

## 位于module下的proguard-rules.pro
#####################################
######### 主程序不能混淆的代码 #########
#####################################

-dontwarn xxx.model.**
-keep class xxx.model.** { *; }

## 等等,自己的代码自己清楚

#####################################
########### 不优化泛型和反射 ##########
#####################################

-keepattributes Signature      

接下来是麻烦的第三方库,一般来说,如果是极光推的话,它的包名是cn.jpush, 添加如下代码即可:

-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }      

其他的第三库也是如此,一个一个添加,太累!其实可以用第三方反编译工具(比如jadx:​​https://github.com/skylot/jadx​​ ),打开apk后,一眼就能看到引用的所有第三方库的包名,把所有不想混淆或者不确定能不能混淆的,直接都添加又有何不可:

#####################################
######### 第三方库或者jar包 ###########
#####################################

-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }

-dontwarn com.squareup.**
-keep class com.squareup.** { *; }

-dontwarn com.octo.**
-keep class com.octo.** { *; }

-dontwarn de.**
-keep class de.** { *; }

-dontwarn javax.**
-keep class javax.** { *; }

-dontwarn org.**
-keep class org.** { *; }

-dontwarn u.aly.**
-keep class u.aly.** { *; }

-dontwarn uk.**
-keep class uk.** { *; }

-dontwarn com.baidu.**
-keep class com.baidu.** { *; }

-dontwarn com.facebook.**
-keep class com.facebook.** { *; }

-dontwarn com.google.**
-keep class com.google.** { *; }

## ... ...      

2). 第二个技巧

一般release版本混淆之后,像友盟这样的统计系统如果有崩溃异常,会记录如下:

java.lang.NullPointerException: java.lang.NullPointerException
    at com.xxx.TabMessageFragment$7.run(Unknown Source)      

这个Unknown Source是很要命的,排除错误无法定位到具体行了,大大降低调试效率。

当然,友盟支持上传Mapping文件,可帮助定位,mapping文件的位置在:

project > module
        > build > outputs > {flavor name} > {build type} > mapping.txt      

如果版本一多,mapping.txt每次都要重新生成,还要上传,终归还是麻烦。

其实,在proguard-rules.pro中添加如下代码即可:

-keepattributes SourceFile,LineNumberTable      

当然apk包会大那么一点点(我这里6M的包,大个200k吧),但是再也不用mapping.txt也能定位到行了,为了这种解脱,这个代价我个人觉得是值的,而且超值!