AS自带免费代码混淆工具ProGuard


前言

代码混淆的内容很多,下面仅介绍免费混淆工具:ProGuard。如果想了解更多关于混淆的知识,建议在实现代码混淆后再根据需求在网上找解决方案。


一、ProGuard是什么?

ProGuard是一款免费的混淆java字节码的工具,除了将包名、类名、方法名和属性等替换成abcd等无含义的字符,还可以通过收缩字节码来减小应用程序的大小。

二、ProGuard使用

1. 开启混淆

ProGuard已经集成在Android Studio中,可以直接使用。使用方法也十分简单,只需要在app目录下build.gradle中将混淆开关minifyEnabled设置为true。如下所示:

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

由于混淆的主要目的是防止他人通过反编译查看代码,所以一般只需要在正式打包release模式下设置为true,debug模式一般都是自己使用的,没有混淆的必要。
开启混淆前后对比,如下所示:(打包apk查看classes.dex)
混淆前
混淆后
可以看到混淆并没有将所有包名、类名等都换成无含义的数字和字母。这是因为ProGuard默认不会混淆4大组件和带有native关键字的方法。4大组件是安卓的基础混淆会导致报错;native是调用.so库方法时使用的关键字,由于java调用so库方法需要对应包名和类名,混淆后改变包名和类名会使其无法找到对应的方法,上图callJniMethod方法就是带有native关键字的。

对so库的知识不了解不影响阅读本文章,只需要知道并不是所有代码都适合混淆就可以了。

2. 混淆配置

在上面有提到存在不能混淆的代码,如何防止这部分代码混淆呢?在项目app目录下有个文件:proguard-rules.pro,这个就是混淆的配置文件(如果只混淆module,则在module下寻找proguard-rules.pro)。下面是我在网上找到的相关配置,可以用于参考,根据自己的需要配置。

保留类名

#一颗星表示只保持该包下的类名,而子包下的类名还是会被混淆(类中的成员都会被混淆)
-keep class com.habit.jnitest.*
#两颗星表示把本包和所含子包下的类名都保持
-keep class com.habit.jnitest.**

保留类名及类的成员

#保留 com.habit.jnitest包下的类及类的成员
-keep class com.habit.jnitest.*{*;}
#保留具体的某个类及类的成员
-keep class com.habit.jnitest.JniTest{*;}

如果不希望保留类的所有成员,可以使用:

<init>;     //匹配所有构造器
<fields>;   //匹配所有字段
<methods>;  //匹配所有方法
# 如保留方法
-keep class com.habit.jnitest.ProGuardTest{
	<methods>;
}
# 还可以在<init><fields><methods>前面加上private 、public等来进一步指定不被混淆的内容。
#如保留public方法
-keep class com.habit.jnitest.ProGuardTest{
	public <methods>;
}

保留指定类的所有子类(implement/extends)

# 保留Activity的所有子类
-keep public class * extends android.app.Activity

压缩(Shrink)

#关闭压缩,在压缩处理中,用于检测和删除没有使用的类,字段,方法和属性。
-dontshrink 

优化(Optimize)

#关闭优化,在优化处理中,对字节码进行优化,并且移除无用指令。
-dontoptimize  
#迭代优化,n表示proguard对代码进行迭代优化的次数,Android一般为5
-optimizationpasses n 

混淆(Obfuscate)

#关闭混淆,在混淆处理中,使用 a、b、c 等无意义的名称,对类,字段和方法进行重命名。
-dontobfuscate 

预检(Preveirfy)

#禁用预校验,在预检中,主要是在 Java 平台上对处理后的代码进行预检。
-dontpreverify 

3. 拓展了解

ProGuard的输出文件说明

混淆后,会在/build/outputs/mapping/release/目录下输出下方文件

dump.txt 说明 APK 中所有类文件的内部结构。
mapping.txt 提供原始与混淆过的类、方法和字段名称之间的转换。
seeds.txt 列出未进行混淆的类和成员。
usage.txt 列出从 APK 移除的代码。

如果仔细观察“1. 开启混淆”中混淆前后的图,还会发现JniTest类有两个方法不见了,或许你会认为staticMethodCalledByJni和methodCalledByJni方法并没有消失,只是被混淆后,放在了混淆后的包名目录下。它们所在位置可以通过ProGuard的输出文件mapping.txt查询。

如下图所示,并没有找到staticMethodCalledByJni和methodCalledByJni方法。
在这里插入图片描述在这里插入图片描述
如果这两个方法在java代码中并没有被调用,在混淆过程中将它们视为多余的方法会被删除,减少无用代码占用空间。但实际上,它们被so库调用了,混淆后会导致so库找不到这两个方法而报错。为防止这种状况,在混淆配置中保留这部分代码不被混淆。

#保留具体的某个类及类的成员
-keep class com.habit.jnitest.JniTest{*;}

ProGuard对代码的压缩

像上面提到的没有被java代码调用的方法会被删除,但没想到的是即使被java代码调用了也是会被删除的(注:ProGuard只是删除了方法的壳,方法的内容被集成到最终调用它的类中)。混淆效果大致如下:

混淆前,在MainActivity中调用ProGuardTest类的publicMethod方法。

public class ProGuardTest {  

    public void publicMethod() {
        Log.d("test","publicMethod");
    }
    
}
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ProGuardTest proGuardTest = new ProGuardTest(); 
        proGuardTest.publicMethod();
    }
}

混淆后,ProGuardTest类被删除,publicMethod()方法的内容被直接搬到了MainActivity中

public class MainActivity extends h {
	public void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    
    Log.d("test", "publicMethod");
  }
}

参考

Java 混淆工具 - ProGuard
Android混淆(ProGuard)从0到1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值