Android Studio系列之代码混淆proguardFiles

前言:

android代码编译成apk后如果没有进行任何防护措施是很容易被反编译的,并且反编译的结果甚至就是简单的源码,带来的损失可大可小。幸好,AndroidStudio提供编译代码加密,即ProGuard。

简介

ProGuard 能够对 Java 类中的代码进行压缩(Shrink),优化(Optimize),混淆(Obfuscate),预检(Preveirfy)。

压缩(Shrink):检测和删除没有使用的类,字段,方法和属性。

优化(Optimize):对字节码进行优化,并且移除无用指令。

混淆(Obfuscate):使用 a,b,c 等无意义的名称,对类,字段和方法进行重命名。

预检(Preveirfy):主要是在 Java 平台上对处理后的代码进行预检。

配置:

这里写图片描述

简单看下,

  1. release表示正式版本,对应的是debug,一般debug是不需要进行代码加密的
  2. minifyEnabled true表示进行代码加密,false表示不加密
  3. proguardFiles 代码加密原则 有两个文件对,getDefaultProguardFile(‘proguard-android.txt’)表示默认文件,这个文件是sdk自带的,有一些通用的配置;但是如果apk需要更加严格的加密,我们可以在’proguard-rules.pro’文件中进行更加详尽的配置。

proguard-android.txt

来看下这个文件中的内容(可以Double Shift快速搜索改文件)

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html

# 包名不混合大小写
-dontusemixedcaseclassnames
# 不忽略非公共的库类
-dontskipnonpubliclibraryclasses
# 输出混淆日志
-verbose

# Optimization is turned off by default. Dex does not like code 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 just
# 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, see http://proguard.sourceforge.net/manual/examples.html#native
# 不混淆native的方法
-keepclasseswithmembernames class * {
    native <methods>;
}

# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
# 不混淆继承View的所有类的set和get方法
-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
# 不混淆继承Activity的所有类的中的参数类型为View的方法
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
# 不混淆枚举类型的values和valueOf方法
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# 不混淆继承Parcelable的所有类的CREATOR
-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}

# 不混淆R类中所有static字段
-keepclassmembers class **.R$* {
    public static <fields>;
}

# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
# 忽略兼容库的所有警告
-dontwarn android.support.**

# Understand the @Keep support annotation.
# 不混淆指定的类及其类成员
-keep class android.support.annotation.Keep

# 不混淆使用注解的类及其类成员
-keep @android.support.annotation.Keep class * {*;}

# 不混淆所有类及其类成员中的使用注解的方法
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <methods>;
}

# 不混淆所有类及其类成员中的使用注解的字段
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <fields>;
}

# 不混淆所有类及其类成员中的使用注解的初始化方法
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <init>(...);
}

从上面的解析可以看出,proguard-android.txt 中只提供了基本的内容,在实际使用 ProGuard 时通常需要配置大量的规则。例如,引用的第三方库的混淆配置,不混淆自定义控件,不混淆反射的类等。

首先我们来看下上述内容的语法:

基础语法:

-include {filename}    从给定的文件中读取配置参数   
-basedirectory {directoryname}    指定基础目录为以后相对的档案名称   
-injars {class_path}    指定要处理的应用程序jar,war,ear和目录   
-outjars {class_path}    指定处理完后要输出的jar,war,ear和目录的名称   
-libraryjars {classpath}    指定要处理的应用程序jar,war,ear和目录所需要的程序库文件   
-dontskipnonpubliclibraryclasses    指定不去忽略非公共的库类。   
-dontskipnonpubliclibraryclassmembers    指定不去忽略包可见的库类的成员。  

保留选项   
-keep {Modifier} {class_specification}    保护指定的类文件和类的成员   
-keepclassmembers {modifier} {class_specification}    保护指定类的成员,如果此类受到保护他们会保护的更好  
-keepclasseswithmembers {class_specification}    保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。   
-keepnames {class_specification}    保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)   
-keepclassmembernames {class_specification}    保护指定的类的成员的名称(如果他们不会压缩步骤中删除)   
-keepclasseswithmembernames {class_specification}    保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)   
-printseeds {filename}    列出类和类的成员-keep选项的清单,标准输出到给定的文件   

压缩   
-dontshrink    不压缩输入的类文件   
-printusage {filename}   
-whyareyoukeeping {class_specification}       

优化   
-dontoptimize    不优化输入的类文件   
-assumenosideeffects {class_specification}    优化时假设指定的方法,没有任何副作用   
-allowaccessmodification    优化时允许访问并修改有修饰符的类和类的成员   

混淆   
-dontobfuscate    不混淆输入的类文件   
-printmapping {filename}   
-applymapping {filename}    重用映射增加混淆   
-obfuscationdictionary {filename}    使用给定文件中的关键字作为要混淆方法的名称   
-overloadaggressively    混淆时应用侵入式重载   
-useuniqueclassmembernames    确定统一的混淆类的成员名称来增加混淆   
-flattenpackagehierarchy {package_name}    重新包装所有重命名的包并放在给定的单一包中   
-repackageclass {package_name}    重新包装所有重命名的类文件中放在给定的单一包中   
-dontusemixedcaseclassnames    混淆时不会产生形形色色的类名   
-keepattributes {attribute_name,...}    保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and   

InnerClasses.   
-renamesourcefileattribute {string}    设置源文件中给定的字符串常量  

关键字包括:

  • keep 保留类和类中的成员,防止它们被混淆或者移除
  • keepnames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除
  • keepclassmembers 只保留类中的成员,防止它们被混淆或者移除
  • keepclassmembernames 只保留类中的成员,防止它们被混淆,但当成员没有被引用时会被移除
  • keepclasswithmembers 保留类和类中的成员,防止它们被混淆或者移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆
  • keepclasswithmembernames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆

通配符包括:

  • field 匹配类中的所有字段
  • method 匹配类中的所有方法
  • init 匹配类中的所有的构造函数
  • * 匹配任意长度字符,但不含包名分隔符(.),比如说我们的完整类名是com.example.test.MainActivtiy,使用com.*,或者com.example.*,都是无法匹配的,因为*无法匹配包名中的分隔符,正确的匹配方式是com.example.*.*,或者是com.example.test.*,这些都是可以的。但如果你不写任何其他内容,只有一个*,那就表示匹配所有的东西
  • **匹配任意长度字符,并且含包名分隔符(.),比如android.support.**就可以匹配android.support包下所有的内容,包括任意长度的子包.
  • ***匹配任意参数类型,比如void set(***)就能匹配任意传入的参数类型,*** get*()就能匹配任意返回值的类型
  • … 匹配任意长度的任意参数类型,比如void set(…)就能匹配任意的void set(String a)或者是void set(String a,int b)等方法

注意点:

  • Java的反射不能混淆。因为代码混淆,类名、方法名、属性名都改变了,而反射它还是按照原来的名字去反射。
  • 注解用了反射,所以不能混淆。
  • 不混淆任何包含native方法的类的类名以及native方法名,否则找不到本地方法。
  • Activity更不能混淆,因为AndroidManifest.xml文件中是完整的名字,混淆后怎么找?
  • 自定义view也是带了包名写在xml布局中,给我换成a,怎么破? R文件混淆了,id没了,界面崩溃那时自然咯。
  • 一般在使用第三方框架,sdk时主要其给出的混淆方案。github第三方混淆方案

每次构建时 ProGuard 都会输出下列文件:

  1. dump.txt 说明 APK 中所有类文件的内部结构。
  2. mapping.txt 提供原始与混淆过的类、方法和字段名称之间的转换。
  3. seeds.txt 列出未进行混淆的类和成员。
  4. usage.txt 列出从 APK 移除的代码。
    这些文件保存在 modulename/build/outputs/mapping/release/ 中。
### Android Studio中实现代码混淆的配置 在Android Studio中,代码混淆可以通过ProGuard或R8工具来实现。以下是详细的配置方法和注意事项: #### 1. 配置启用代码混淆 在`app/build.gradle`文件中,需要对`buildTypes`进行配置以启用代码混淆。具体配置如下: ```gradle android { buildTypes { release { // 启用代码混淆 minifyEnabled true // 启用资源压缩 shrinkResources true // 指定混淆规则文件 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } ``` 上述配置中,`minifyEnabled true`用于启用代码混淆功能[^2]。`shrinkResources true`则用于移除无用的资源文件[^2]。同时,通过`proguardFiles`指定了默认的混淆规则文件以及自定义的混淆规则文件`proguard-rules.pro`。 #### 2. ProGuard与R8的区别 ProGuard和R8是两种常用的代码混淆工具。从Android Gradle Plugin 3.4.0开始,默认使用R8作为代码混淆工具[^1]。虽然R8取代了ProGuard,但它仍然兼容ProGuard的规则文件[^2]。因此,在大多数情况下,开发者无需修改现有的ProGuard规则即可直接使用R8。 #### 3. 自定义混淆规则 为了保护应用中的关键代码或第三方库,通常需要在`proguard-rules.pro`文件中添加自定义规则。以下是一些常见的混淆规则示例: - **保留特定类不被混淆**: ```pro -keep public class com.example.MyClass { *; } ``` 上述规则表示`com.example.MyClass`类及其所有成员不会被混淆[^4]。 - **保留注解类**: ```pro -keepattributes *Annotation* ``` 该规则确保注解信息不会被移除[^4]。 - **保留接口**: ```pro -keep public interface com.example.MyInterface { *; } ``` - **保留JSON序列化类**: 如果使用Gson等库进行JSON序列化,需要确保相关类的字段名称不被混淆: ```pro -keepclassmembers class * { @com.google.gson.annotations.SerializedName <fields>; } ``` #### 4. 测试混淆效果 完成混淆配置后,可以通过生成签名APK并使用反编译工具(如JD-GUI)检查混淆效果。如果发现某些代码未按预期混淆,可能需要调整`proguard-rules.pro`文件中的规则。 #### 5. 注意事项 - **调试模式下的混淆**:默认情况下,`debug`构建类型不会启用混淆。如果需要测试混淆效果,可以在`debug`构建类型中临时启用混淆- **混淆可能导致的问题**:混淆可能会导致某些功能失效,尤其是在涉及反射或动态加载的情况下。此时需要根据具体情况调整混淆规则[^3]。 ### 示例代码 以下是一个完整的`app/build.gradle`文件示例: ```gradle android { buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } ``` 同时,`proguard-rules.pro`文件可以包含以下内容: ```pro -keep public class com.example.MyClass { *; } -keepattributes *Annotation* -keep public interface com.example.MyInterface { *; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值