性能优化总结4:组件化混淆需要注意的地方

本文详细介绍了ProGuard在Android开发中的应用,包括混淆的好处、混淆的操作流程、如何在build文件中打开混淆,以及基本的混淆设置。同时,文章列举了不能被混淆的特殊情况,如反射中使用的元素、四大组件、自定义View等,以及如何使用@Keep注解来保护特定的类不被混淆。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、混淆的好处
android studio 使用ProGuard来进行混淆,ProGuard是一个压缩、优化和混淆java字节码文件的工具,可以删除无用的类,字段,方法和属性,还可以删除无用额注释,最大限度的优化字节码文件,规避64K方法数的问题,并且还可以使用剪短而且无意义的名字来重命名已经存在的类、字段、方法和属性,增加逆向工程的难度。混淆可以减少APK文件的大小。
2、混淆包含:压缩,优化,混淆,预校验四个操作。
压缩Shringking : 检测和删除无用的类,方法,字段和属性
优化Optimize : 优化字节码文件,删除无用指令
混淆Obfuscation :使用无意义的名字来对类,字段,方法和属性进行重命名
预校验Preverification:对处理后的代码进行校验

proguard原理介绍可以看看proguard的官网
proguard
proguard流程:

3、build文件打开混淆

    buildTypes {
        release {
            minifyEnabled true		//打开混淆
            shrinkResources true	//打开资源压缩
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//设置混淆文件的路径,第一部分为系统已经预先设置的混淆文件,第二部分是我们自己的混淆文件
        }
    }

当我们新建module的时候,是默认已经关闭混淆了的,要打开混淆只要设置minifyEnabled = true就可以

proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro

proguard-android.txt为系统已经预先设置的混淆文件,proguard-rules.pro是我们自己的混淆文件

基本的混淆设置:

指定压缩级别,0-7之间,默认为5

-optimizationpasses 5

不使用大小写混合类名,注意,windows用户必须为ProGuard指定该选项,因为windows对文件的大小写是不敏感的,也就是比如a.java和A.java会认为是同一个文件。如果不这样做并且你的项目中有超过26个类的话,那么ProGuard就会默认混用大小写文件名,导致class文件相互覆盖。

-dontusemixedcaseclassnames

不跳过非公共的库类

-dontskipnonpubliclibraryclasses

不跳过非公共的库类的成员

-dontskipnonpubliclibraryclassmembers

指定不执行预检,预校验作用在Java平台,android平台不需要,所以去掉预校验可以加快混淆速度

-dontpreverify

把所有信息都输出,而不仅仅是输出出错信息

-verbose

输出类名->混淆后类名的映射关系

-printmapping proguardMapping.txt

混淆时采用的算法

-optimizations !code/simplification/cast,!field/,!class/merging/

不混淆Annotation

-keepattributes Annotation,InnerClasses

不混淆泛型

-keepattributes Signature

保留行号

-keepattributes SourceFile,LineNumberTable
以下情况不能被混淆:
1.
反射中使用的元素,需要保证类名,方法名,属性名不变,否则混淆后会反射不了
最好不要混淆bean对象
四大组件不建议混淆,自定义的Application不能被混淆,混淆以后类名会变,,而混淆后的类名没有在manifest中注册,所以不符合四大组件的注册机制
外部程序可能使用组件的字符串类名,如果类名混淆,可能导致出现异常
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
2.自定义view和自定义控件不能被混淆
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
3.枚举类的values和valuesOf方法不能被混淆,因为这两个方法是静态添加到代码中运行,也会被反射使用,所以不能混淆这两个方法
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
4.R类下面的资源不能被混淆
-keep class **.R$* {*;}
5.JNI调用java方法不能被混淆,需要通过类名和方法名构成的地址形成
6.webview中的js方法不能混淆
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
   public *;
}
-keepclassmembers class * extends android.webkit.webViewClient {
    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
    public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.webViewClient {
    public void *(android.webkit.webView, jav.lang.String);
}
7.Java调用Native方法,Native方法是C/C++编写的,方法是无法一同混淆的
-keepclasseswithmembernames class * {
    native <methods>;
}

8. 第三方库建议使用其自身的混淆规则
9. Parcelable的子类和Creator的静态成员变量不能混淆,否则序列化会出异常
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
10.保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
11.JS调用原生的方法不能被混淆
-keepattributes *JavascriptInterface*

以上是一些基本的不能被混淆的情况。
是不是有一种头晕目眩的感觉呢?其实混淆不复杂,我们只需要记住一点:

混淆改变了Java路径名,需要保持路径名不变的不可以被混淆

只要牢记这个原则来添加自己不需要被混淆的类就可以啦。
另外support-annotation中提供了@Keep注解,可以保持类不被混淆,哪里不想被混淆就"keep"那里
proguard keep
要使用@Keep需要在proguard文件里加入:

-dontskipnonpubliclibraryclassmembers
-printconfiguration
-keep,allowobfuscation @interface android.support.annotation.Keep

-keep @android.support.annotation.Keep class *
-keepclassmembers class * {
    @android.support.annotation.Keep *;
}
那么是否有更深层次的混淆呢?

ProGuard只能混淆java文件,实际上我们还可以混淆资源文件的文件路径,其实质也是资源名的混淆。
这里要提到AndResGuard混淆插件
github地址:
AndResGuard/README.zh-cn.md at master · shwenzhang/AndResGuard · GitHub
https://github.com/shwenzhang/AndResGuard/blob/master/README.zh-cn.md

它会重新修改apk的resource.arsc文件,不依赖源码和编译过程,可以使用zip压缩。
具体的使用,大家可以参考官方git。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值