ProGuard常见问题及解决套路
ProGuard是一个压缩、优化和混淆Java字节码的工具,非常好用。本篇文章总结一下许多人在使用ProGuard时经常遇到的问题。
我把在使用ProGuard时经常遇到的问题分为两类,分别是导致构建失败的编译时问题,以及构建通过但运行时崩溃或结果不正确的运行时问题。大多数人所遇到的大多数问题,都可以在下面的内容中找到对应的解决套路。
在开始讲这两类问题前,先明确一点:我们所说的添加混淆规则,不是指加入了才会混淆相关的类,相反,事实上,当你启用混淆之后,添加的一些诸如-keep xxxx
的规则才是起着不混淆的作用。
下面开始讲这两类问题。
编译时问题
问题
首先讲编译时的问题。导致编译不通过,最常见的情况是这样的:
在漫长的编译之后,我们等到的控制台上的这样一个输出结果:
...
Note: there were 8 references to unknown classes.
You should check your configuration for typos.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unknownclass)
Note: there were 272 unkept descriptor classes in kept class members.
You should consider explicitly keeping the mentioned classes
(using '-keep').
(http://proguard.sourceforge.net/manual/troubleshooting.html#descriptorclass)
Note: there were 75 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
Warning: there were 11 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
Warning: Exception while processing task java.io.IOException: Please correct the above warnings first.
原因及解决方法
有些小伙伴会自动忽略英文日志,即便它给出了明确的答案,这是个严重的不良习惯。如上,其实在这段日志中,已经表明了原因及解决方案了。注意Warning
开头的警告内容,最后一个警告是让你先解决第一个警告的内容,所以先忽略。我们看它前面的警告:
there were 11 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
这是什么意思呢?
第一句话是告诉你原因:有11个未解析的类或引用。
后面两句是解决方案。方案一:你可能需要添加丢失的库或更新它们的版本。方案二:如果你现在代码运行得好好的,也就是没有它们也没关系,那你可以使用-dontwarn
来禁止这样的警告。
那么如何知道有哪些未解析的类或引用呢?
遇到这样的问题,很简单,我们往上翻,最终肯定会找到Warning开头的日志内容:
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.OpenSSLProvider
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.OpenSSLProvider
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
它的句型是这样的:Warning: xxxx.xxx.ABC: can't find referenced class xxx.xxx.XYZ
意思就是第三方库里的ABC引用了XYZ这个类,但是我在类路径中找不到XYZ这个类。
这种情况很常见,比如一个Java库使用了另一个库的一些类来实现某个特性。如果你在使用这个库的时候需要这个特性,那么你就要把另一个库也加进来,也就是前面给出的方案一。而如果你不需要用到,如上面的例子,项目中实际上用不到org.conscrypt
包里的内容,那么我们在混淆规则的文件中添加上-dontwarn
规则就可以了。
如何添加?
规则很简单。
-dontwarn 类名
在上面的日志中,有引用的类,也有被引用的类,这两者都可以。也就是对于前面的句型,你既可以使用-dontwarn xxxx.xxx.ABC
,也可以使用-dontwarn xxx.xxx.XYZ
。
比如上面的例子,我们用
-dontwarn okhttp3.internal.platform.ConscryptPlatform
和用
-dontwarn org.conscrypt.OpenSSLProvider
-dontwarn org.conscrypt.Conscrypt
都可以解决问题。但从这里也可以看出疑惑来了。如果有多个类呢?是不是每一个类都要写上去呢?
当然不是。这里的类名是支持通配符的,比如上面,我们可以写为:
-dontwarn org.conscrypt.*
表示禁止org.conscrypt
包下的类的警告。但是这里的*
是不包含包分隔符的,也就是说它的子包里面的类是不会被禁止的。如果需要连它下面的包的类也一并禁止,可以使用包含包分隔符的**
,也就是如下:
-dontwarn org.conscrypt.**
关于过滤器的更多用法,可以参阅文档:https://www.guardsquare.com/en/products/proguard/manual/usage#filters
总结
这是最常见的一类问题,我们来总结一下这个套路:
- 编译报错,提示内容是
Warning: there were xxx unresolved references to classes or interfaces.
。 - 往上找带有
Warning:
的日志,句型结构为:Warning: xxxx.xxx.ABC: can't find referenced class xxx.xxx.XYZ
- 往混淆规则里添加
-dontwarn 类名
的规则。
运行时问题
我们再来看另一类问题。
当有人在讨论群里求助混淆相关的问题时,往往会有人说加-keep
。那么-keep
是作什么用呢?在什么情况下需要它呢?
在文章开头一句话介绍过,Proguard 是一个压缩、优化和混淆Java字节码文件的工具。也就是,它所做的不仅仅包括我们所知道的混淆,它会分析所有的类,找出没有用的类、字段、方法等把它们删除掉,从而达到对字节码的压缩及优化。而如果我们使用了反射去调用一些类或方法的话,它是不知道的,这样就会导致“误删”的情况。
所以当开启混淆之后,出现类找不到,方法找不到,属性找不到时,我们就要使用keep相关规则来把它们给留住啦。比如使用-keep class xxxx {*;}
保留指定的类名及其成员。
keep规则有三种(Android新增加的@keep
注解不谈,这里只讲规则文件的内容):
- -keep 保留指定的类名及其成员
- -keepclassmembers 只保留住成员,不能保留住类名
- -keepclasseswithmembers 根据成员找到满足条件的所有类,保留它们的类名和成员名
比如我们使用了事件总线,为使方法能保留,我们可以添加如下的规则:
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
表示保留所有类中的有@org.greenrobot.eventbus.Subscribe
注解的方法。<methods>
是指方法,如果要保留字段,则使用<fields>
。
反正就是找不到类或成员,你就keep住。这里的keep规则也是很灵活的,比如除了上面指定的类,你也可以指定为接口:
-keepclassmembernames,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
可以指定继承自某个类的所有类,如:
-keep public class * extends android.app.Service
可以指定实现某个接口的类,如:
-keep class * implements com.google.gson.TypeAdapterFactory
可以指定某个包下的所有类(包括子包)及所有成员,如:
-keep class com.tencent.stat.** {* ;}
除此之外,我们还可能会遇到其他问题,这里把其他常用的规则也快速过一下:
注解解析不到?
-keepattributes *Annotation*
泛型转换失败?
-keepattributes Signature
枚举?
-keepclassmembers enum * { *; }
掌握以上几条规则,通常可以解决绝大多数混淆以后运行出错的问题了。
本篇讲到这里,希望对被以上常见问题所困扰的同学有所帮助。这里需要注意一下,对于第一类问题,在编译的时候就能暴露出来,而第二类问题,只有在运行到相关代码时才会出现。所以如果一个项目以前是不使用混淆的话,在启用混淆之后一定要做好回归测试。
ProGuard常见问题及解决套路的更多相关文章
- NHibernate常见问题及解决方法
NHibernate常见问题及解决方法 曾经学过NHibernate的,但是自从工作到现在快一年了却从未用到过,近来要巩固一下却发现忘记了许多,一个"in expected: <end ...
- WebView加载本地html、js文件常见问题及解决办法
声明:基于android studio平台,php语言搭建服务器 目录: 一.JavaScript脚本语言没有反应 二.alert无法弹出 三.html页面之间不能跳转 四.屏幕缩放没有达到预期效果 ...
- 转:WebTest的常见问题与解决
WebTest的常见问题与解决录制好一个WebTest,加上各种规则,编辑后运行并不会像我们想象的那么顺利成功,往往会碰到很多问题,运行不成功的情况比较多,这样我们就遇到了如何解决这些问题的情形.1. ...
- WordPress源代码压缩优化及常见问题的解决
先来看看效果: 意思就是让你的源代码看起来都挤在一起,这样如果别人想看你的源代码的话就不容易看懂了,(当然如果别人实在想看的话也可以通过某些软件的整理代码的功能来实现,比如IDEA的Ctrl+alt+ ...
- FineUIMvc 常见问题及解决办法
Ø 简介 FineUIMvc 是基于 jQuery 的专业 ASP.NET MVC/Core 控件库,本文主要介绍 FineUIMvc 的常见问题及解决办法. 1. View 中无法调用 Htm ...
- rsync @ERROR: auth failed on module backup 解决思路及附录rsync常见问题及解决办法
昨晚小版本上线,使用rsync往服务器上传文件时,client报如下异常: @ERROR: auth failed on module backup rsync error: error starti ...
- fetch使用的常见问题及其解决办法
摘自: https://segmentfault.com/a/1190000008484070 fetch使用的常见问题及其解决办法 javascript wonyun 2月25日发布 | 0 收 ...
- C#用ado.net访问EXCEL的常见问题及解决方法
C#用ado.net访问EXCEL的常见问题及解决方法,除了像sql server,access常见的数据库,其实Excel文件也可以做为数据库访问. ado.net访问excel的实例: OleDb ...
- PHPmailer发送邮件时的常见问题及解决办法
来源:http://www.chinastor.com/a/jishu/mailserver/0G392262014.html 使用PHPmailer发送邮件时的常见问题总结: 一,没有定义发送邮箱$ ...
随机推荐
- [CodeForces]500B New Year Permutation
刷水题做几道入门贪心题预热... 找联通块里字典序最小的放到最前面即可.记得写传递闭包 #include <iostream> #include <cstdio> #inclu ...
- 当一个线程进入一个对象的一个synchronized方法后, 其它线程是否可进入此对象的其它方法?
分几种情况: 1.其他方法前是否加了synchronized关键字,如果没加,则能. 2.如果这个方法内部调用了wait,则可以进入其他synchronized方法. 3.如果其他个方法都加了sync ...
- ansible 主机清单 /etc/ansible/hosts
主机清单 [webservers] ansible01 ansible02 ansible03 ansible04 [root@ftp:/root] > ansible webservers - ...
- jQuery 文档操作
一.插入操作 1. 父元素.append(子元素) 追加某元素,在父元素中添加新的子元素, 子元素可以为: stirng / element (js对象) / jquery 元素 var oli = ...
- 小学生都能学会的python(<lamda匿名函数,sorted(),filter(),map(),递归函数>)
小学生都能学会的python(<<lamda匿名函数,sorted(),filter(),map(),递归函数,二分法>> 1. lambda 匿名函数 lambda 参数: ...
- [luogu] P4823 [TJOI2013]拯救小矮人(贪心)
P4823 [TJOI2013]拯救小矮人 题目描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以 ...
- docker mysql 数据持久化到本地、设置不区别表名大小写-清风柳絮-51CTO博客
原文:docker mysql 数据持久化到本地.设置不区别表名大小写-清风柳絮-51CTO博客 Docker MySQL 把数据存储在本地目录,很简单,只需要映射本地目录到容器即可 1.加上-v参数 ...
- Maven中的parent定义的dependency,其中继承者是可以直接使用parent中的Maven Dependencies的。
Maven中的parent定义的dependency,其中继承者是可以直接使用parent中的Maven Dependencies的. packagin要选择jar,parent project要选择 ...
- HDU 4314 Contest 2
可以知道,逃出的人中,最后一个应当是A+B最长的,这是很容易发现的.那么,最选逃出去的必定是A+B最短的.这符合最优. 于是,可以把各小矮人按A+B的和由大到小排序.定义DP[i][j]为i个人中逃出 ...
- 闭包(closure)与协程共用时要注意的事情
闭包是一种能够让你用非常舒服的方式来编程的小技巧,Go也支持闭包. 假设从来没有接触过闭包,想在一開始就弄懂什么是闭包(closure)是非常困难的,就像递归一样,直到你真正写过.用过它,你才干真正的 ...