首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android中的Proguard介绍

Android中的Proguard介绍

作者头像
None_Ling
发布2018-10-29 16:53:20
6280
发布2018-10-29 16:53:20
举报
文章被收录于专栏:Android相关Android相关

介绍

ProGuard是一个Java Class文件的Shrinker,optimizer,obfuscator以及Preverifier。

  • Shrinking步骤:检测,并且删除无用的classes,fields,methods,以及attributes
  • Optimization步骤:分析,并且优化bytecode中的methods
  • Obfuscation步骤:将剩下的classes,field,methods使用无意义的短的字符串重命名

这些步骤主要是为了让代码变得更精简,更高效,变得对逆向更难。而最后一个步骤:preverification,该步骤会在classes中添加预验证信息,而预验证的信息是在Java 6以上的版本所需要的。

这几个步骤每一个都是可选的,例如,ProGuard可以用来列出Dead Code,也可以在Java6中更高效的预验证class文件。

ProGuard

ProGuard只读取jars,wars,zips,ears等文件格式的文件。然后对它们进行shrinks,optimizes,obfuscates,preverifies。也可以传入多个文件,它们会一个一个被Shrink。ProGuard会把处理的结果写到一个或者多个Jar包中。如果输入的文件包含了资源文件,那么它们的名字和内容都会被obfuscated类名所影响。

ProGuard会指定Library Jar作为输入,而这些输入文件也是我们需要编译代码所需要的。ProGaurd使用它们来重建正确处理所需的类依赖关系,Library它们本身会保持不变,你可以把他们放到最终应用的Class Path中。

入口(Entry Points)

为了决定哪些代码应该被保留,而哪些代码应该被丢弃或者混淆的,你可以指定一个或者多个代码入口。这些入口可以是有main函数的class文件等等。

  • Shrinking:ProGuard会从这些入口出发,并且递归决定哪些classes以及class members会需要用到。而其他的classes和class members就会被丢弃
  • Optimization:ProGuard进一步优化代码。经过之前的优化,非入口的Classes和Methods都可以变成privatestaticfinal,而没用的参数也会被移除,一些函数会被内联
  • Obfuscation:ProGuard会重命名非入口的Class和Class Members。在整个过程中,会保持入口函数原有的名字来保证这些函数仍然可以呗访问
  • Preverification:这一步是唯一一步不需要知道入口的

反射(Reflection)

反射和自检(introspection)是代码自动处理中特殊的问题。

在ProGuard中,Classes和Class Member都可以创建或者通过名字动态调用,这种方式也是一个特殊的入口。

例如,Class.forName()可能会在Runtime引用很多的Class。而这种方式的类,我们无法预见哪些类必须使用原始名称来保留,例如Class的名称是从配置文件中读取的。

因此,我们需要在ProGuard的配置文件中进行配置。而最简单的配置则是通过-keep选项。然而,ProGuard已经检测并且处理了以下这些Case:

  • Class.forName("SomeClass")
  • SomeClass.class
  • SomeClass.class.getField("someField")
  • SomeClass.class.getDeclaredField("someField")
  • SomeClass.class.getMethod("someMethod", new Class[] {})
  • SomeClass.class.getMethod("someMethod", new Class[] { A.class })
  • SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[]{})
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] {A.class, B.class })
  • AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")
  • AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")
  • AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")

被引用的Class和Class Member会在Shrinking阶段被保存,并且String参数也会在Obfuscating阶段正确的更新

更多的,ProGuard对于Keep一些必须出现的Class或者Class Members有一些建议: 例如,ProGuard会关注到(SomeClass)Class.forName(variable).newInstance()。这种我们需要指定类或者SomeClass接口、实现类应该被保留。

混淆很多反射的代码需要反复测试,尤其是不需要内部构建的代码。

使用(Usages)

如果想要执行ProGuard,只需:

java -jar proguard.jar options ...

你可以在ProGuard安装的lib目录下找到proguard的Jar包。或者,把bin目录包含到命令行脚本中去。

一般我们都会把大多数的Options添加到一个配置文件中,如myconfig.pro,然后调用:

java -jar proguard.jar @myconfig.pro

你也可以在命令行参数后再添加其他的参数,例如:

java -jar proguard.jar @myconfig.pro -verbose

在配置文件中,我们可以通过##字符来进行注释。例如: ##This is Comment##

如果特殊的文件名带有空格,则需要使用单引号或者双引号。

Options可以通过命令行参数以及配置文件中任意组合。也就意味着,你可以引用任意的命令行参数,来避免Shell被特殊的字符扩张。

Options的顺序是无关的。

参考资料

Proguard官方文档

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.10.24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 入口(Entry Points)
  • 反射(Reflection)
    • 使用(Usages)
    • 参考资料
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档