您当前的位置: 首页 >  ar
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

性能优化专题五--Proguard混淆简单使用、以及混淆后的映射

沙漠一只雕得儿得儿 发布时间:2020-05-16 17:01:39 ,浏览量:0

Proguard是一个代码优化和混淆工具。能够提供对Java类文件的压缩、优化、混淆,和预校验。压缩的步骤是检测并移除未使用的类、字段、方法和属性。优化的步骤是分析和优化方法的字节码。混淆的步骤是使用短的毫无意义的名称重命名剩余的类、字段和方法。压缩、优化、混淆使得代码更小,更高效。

一、Proguard简单使用:

在build.gradle文件中默认的Proguard文件配置是false关闭的,我们可以在debug模式下打开,设置为true即可:

默认的getDefaultProguardFile(‘proguard-android.txt’) 会使用build/intermediates/下面的文件(可以println 查看),如果在这个目录下没有则可以通过运行gradle任务:生成。而后面的’proguard-rules.pro’则是一个相对路径,相对于这个build.gradle同级目录下的proguard-rules.pro

然后在项目的gradle task中双击extractProguardFiles任务,就可以看到生成了三个混淆文件:

我们可以将proguard-android文件拷贝到我们项目中,看下系统生成的keep规则使用

可以看到不需要混淆的情况有如下一些:

  1. native层代码;
  2. 所有继承自view的组件;
  3. activity里面的所有view;
  4. 枚举;
  5. Parcelable;
  6. 静态内部类;
  7. webkit接口;
  8. 所有support包、androidx下面的类;
  9. 所有使用了keep注解的类、方法、成员变量、构造方法

简单语法:

-keep 指定类和类成员(变量和方法)不被混淆。

(保护了类名)
    -keep class com.dongnao.proxy.guard.test.Bug
(保护了 public static void的没有参数的函数)
    -keep class com.dongnao.proxy.guard.test.Bug{
           public static void *();
    }
 (保护所有)
    -keep class com.dongnao.proxy.guard.test.Bug{
           *;
    }

-keepclassmembers 指定类成员不被混淆(就是-keep的缩小版,不管类名了)。

(都被混淆了)
-keepclassmembers class com.dongnao.proxy.guard.test.Bug

-keepclasseswithmembers 指定类和类成员不被混淆,前提是指定的类成员存在。

(保护类名,但是没指定成员,所以函数名被混淆)    
-keepclasseswithmembers class com.dongnao.proxy.guard.test.Bug
-keepclasseswithmembers class       com.dongnao.proxy.guard.test.Bug{
        native ;
  }

实验项目地址:https://github.com/buder-cp/base_component_learn/tree/master/performanceOPT/buderdn08

开启混淆后,我们新建的User类,如果没有使用到,那么就不会打包到dex文件中,可以看到并没有User类:

ProGuard 会移除所有(并且只会移除)未使用的代码。不过,ProGuard 难以对许多情况进行正确分析,可能会移除应用真正需要的代码。比如需要反射、动态加载所引用的类等情况,可能因为proguard移除或者混淆了这部分没使用的类,而导致错误。所以有时需要编写混淆优化配置文件。在gradle中的proguardFiles 能够让我们传递File文件或者文件路径交给proguard来执行。

当我们在MainActivity中使用这个User类后,

        User user = new User();
        user.age = 18;
        user.name = "buder";

并且添加混淆规则,不混淆User类里面的String字段:

-keep class com.test.buderdn08.User {
    java.lang.String *;
}

最终的结果,User类中String成员变量是name,并没有被混淆掉。

很多混淆命令可以多多尝试使用。

二、Proguard生成的混淆代码,如何对应原始代码

outputs/mapping/debug/mapping.txt文件中保存了混淆前后的对应关系,混淆后的代码错误栈恢复方法:

1.先配置  -keepattributes SourceFile,LineNumberTable

2.把错误信息保存到文件

3.使用工具 sdk/tools/groguard/bin/retrace.bat 再执行  retrace.bat  -verbose mappint文件  bug文件

我们在Activity中主动写一个bug,运行产生这样的日志:

这个日志有两个问题:

  1. 我们不知道是哪个类报告出的。
  2. 不知道这个类是哪一行报出的。

第一个问题很显然是由于我们的代码进行了混淆。

在开启混淆后,我们生成apk会产生

dump.txt:说明 APK 中所有类文件的内部结构。这个文件内容非常多,可读性也并不高

mapping.txt:提供原始与混淆过的类、方法和字段名称之间的转换。

seeds.txt:列出未进行混淆的类和成员。我们保护的zip没有被混淆

usage.txt:列出从 APK 移除的代码。可以在这个文件中查看是不是有我们不想被移除的类

最重要的当然就是我们的mapping文件了。通过这个文件我们就能定位到:

出现错误的函数是Bug类中的test函数。

我们现在比较简单,所以一下子就能定位到错误函数,如果函数层级较深,光靠自己比对来查找难度就比较大了。所以sdk中提供了一个工具在tools/proguard/bin中。

我们把logcat里面保存的错误堆栈复制到一个文件中:

然后执行retrace 脚本(在 Windows 上为 retrace.bat;在 Mac/Linux 上为 retrace.sh)

retrace.bat|retrace.sh [-verbose] mapping.txt []

现在错误日志一句mapping还原了。所以我们每次在发布版本之后都需要保留这个mapping文件。所以一般异常上报平台都会提供mapping上传然后帮助我们分析。

第一个问题解决的,第二个问题是行数显示的是Unknow Source

如果希望出现具体行数,我们需要在配置文件中加入

抛出异常时保留代码行号,在异常分析中可以方便定位

-keepattributes SourceFile,LineNumberTable

另外还可以配合-renamesourcefileattribute AAA

使用字符串"AAA"来替代真正的类,避免泄漏更多的信息

 

关注
打赏
1657159701
查看更多评论
立即登录/注册

微信扫码登录

0.0989s