Theme Preview

Android工程由第三方jar包引起的混淆打包失败

由 李晓岚 在 2013年09月22日发表

Android应用在发布时一般都会使用ProGuard来优化和混淆程序。今天遇到一个问题就与ProGuard有关。应用在开发阶段,模拟器与手机都能够正常运行。当准备打包发布测试并开启ProGuard优化后,ProGuard优化失败了。是应用的问题,还是ProGuard配置的问题,抑或是ProGuard本身的问题。深入调查后,发现原来是第三方jar包引起的,但最终根源是Android的开发环境。

ProGuard优化失败,给出的主要错误信息是

Warning: com.example.A: can't find referenced class javax.xxx.xxx

引用缺失类的源头来自第三方jar包。虽然可以使用ProGuard的-dontwarn参数来忽略这个警告,但总归不够优雅,也不安全。

既然程序会引用不存在的类,为何在不使用ProGuard的开发阶段没有问题,正常编译通过,且运行正常?对能够编译通过这个问题,解释起来有点复杂,就先来说说为什么正常运行吧。很简单,引用缺失类的代码压根就没有运行到,所以只是表面上看起来正常,实质埋藏着一个定时炸弹,不知什么时候就会引爆,让你的程序崩溃。

再来看编译通过的问题。要解释这个问题,我是这么推测的:编译器的引用关系检查只是针对源代码的,对jar包中的类是不做检查的。当某个源文件引用另一个类时,编译器发现被引用的类来自于某个jar包,于是引用检查就停止了。默认jar包中引用的类都存在。而当运行时,VM就不能简简单单认为某个类是存在就行了,VM必须加载实实在在的代码来执行,所以必须见到类的真面目。其实在运行时已经没有jar包的概念了。

前面遇到的问题在于,jar包的编译环境是JDK,而使用环境是Android的Java Runtime,两者是存在差别的。要在编译Android应用期间发现这个问题,就必须对引用的jar中的类包再进行一次引用关系检查,带来的副作用是增加编译时间,所以编译期间不做检查。但ProGuard的优化阶段做了全面检查,能够发现这样的问题。

由此可见,不是在网上找到一个什么jar包,就能用在Android开发上。自从有了Android,如果Java库的开发人员想要开发和维护能够被JDK和Android都能使用的库,就需要付出额外的代价,只能使用两者Runtime的交集。看来,Android这个机器人的是本事还真不小,不但成功杀入了智能手机市场,而且还附带破坏了编程语言Java的血统。

从此以后,ProGuard又多了这样一个新功能,就是程序的Runtime兼容性检查。

标签:AndroidProGuard

comments powered by Disqus