这个看似简单的问题困扰了我好久了,我已经google了很多相关的信息了,但是在我看来总觉得他们说得不够全面,包括官方的文档(ps:可能是我的英语了解能力不够好^_^),好吧在这里我就来个比较全面、严密一点的分析吧,希望能帮到遇到同样问题的你,献丑了:
1. 问题的产生原因
"类1 can't find referenced class 类2" 字面上的意思就是类1找不到类2的引用;接着再看下去"You may need to specify additional library jars (using '-libraryjars').";
噢,原来这么简单呀,他说我需要使用-libraryjars加上项目中使用到的第三方库就OK了。好!马上把"-libraryjars ./libs/xx.jar"这段代码加入到proguard.cfg配置文件里面去,
再export一次!一分钟过后,靠!同样的错误提示又来了:
Warning: com.xxx.bbbb.F.H$3: can't find referenced class com.xxx.bbbb..F.H$com.xxx.bbbb.F.H$_B Warning: there were 1 unresolved references to classes or interfaces. You may need to specify additional library jars (using '-libraryjars'). java.io.IOException: Please correct the above warnings first. at proguard.Initializer.execute(Initializer.java:321) at proguard.ProGuard.initialize(ProGuard.java:211) at proguard.ProGuard.execute(ProGuard.java:86) at proguard.ProGuard.main(ProGuard.java:492)
这不是坑爹吗?还报错!我以为是顺序不对,把-libraryjars ./libs/xx.jar这句话放到最开头,或者在keep...语句的开头,结果很悲催,也不行。马上看看官方文档的Troubleshooting,发现有说到这个问题后,大喜!我们一起去瞧瞧他怎么说的:
Warning: can't find superclass or interface Warning: can't find referenced class If there are unresolved references to classes or interfaces, you most likely forgot to specify an essential library. For proper processing, all libraries that are referenced by your code must be specified, including the Java run-time library. For specifying libraries, use the -libraryjars option. For example, if ProGuard complains that it can't find a javax.crypto class, you probably still have to specify jce.jar, next to the more common rt.jar. If you're missing a library and you're absolutely sure it isn't used anyway, you can try your luck with the -ignorewarnings option, or even the -dontwarn option. Only use these options if you really know what you're doing though. For example, if you're developing for Android, and ProGuard complains that it can't find a java.awt class, then some library that you are using is referring to java.awt. This is a bit shady, since Android doesn't have this package at all, but if your application works anyway, you can let ProGuard accept it with "-dontwarn java.awt.**".
2.官方对于这个问题的解释:
如果存在未解决的类或者接口的引用的话,你很有可能忘记指定一些必要的库了。正确的处理方法是在你代码里引用到的所有库都必须要在配置文件中指定,包括Java运行库,使用-libraryjars选项来指定这些库。
看到这里,你明白了刚刚为什么提示You may need to specify additional library jars (using '-libraryjars').了吧,目的就是在配置文件里面加上项目中所使用到的第三方库。可是,你这是坑爹呀,我明明给所有库都加上-libraryjars参数指定了,结果还是报Warning: com.xxx.bbbb.F.H$3: can't find referenced class com.xxx.bbbb..F.H$com.xxx.bbbb.F.H$_B这个错啊,打包不了!
好,我们再看下去...
接着他给我们举个例子:如果ProGuard说它找不到javax.crypto class这个类,你可能还需要指定jce.jar包,紧接着还要指定更常用的rt.jar包。换句话说,javax.crypto class这个类里面所引用到的类不但在jce.jar包里面,还在rt.jar包里面。
可是我项目中用到的所有第三方包都使用-libraryjars指定了呀!这个方法解决不了我的问题,不知道解决得了你的问题不?
解决不了的话,再看下去...
如果你缺少了某个库,而且你绝对肯定自己没有用到这个库里面的类的话,你可以试试你的运气,使用-ignorewarnings或者-dontwarn选项!-dontwarn我试过了,加上
-dontwarn com.xxx.bbbb.**之后确实没有报错,可以打包出来了!呵呵,别高兴得太早,你拿你这样打包好了的包去运行一下试试看?如果运气好的话,程序没有执行到找不到的类那里就不会报错,如果运气不好的话执行到那里了就会抛ClassNotFoundException!哼哼,怕了没?
我们身为备受瞩目的程序猿,肯定要有职业道德的,总不能编译出来的程序要使用到用户的运气+人品才能保证不出错吧!!^_^
其实,我明白他说的意思的,就是说你要绝对确保这个类没有被你的程序中使用到才可以使用-ignorewarnings或者-dontwarn选项,接着,他又举了个例子了: 比如你开发的是Android项目,但是打包时ProGuard抱怨找不到java.awt里面的某些类,可能是因为你使用的某些库要用到java.awt包里面的类,众所周知,Android压根就没有java.awt这个包,它是J2SE里面的包,我们Android程序当然不需要这个包也能很好的运行了,此时,你可以用-dontwarn java.awt.**来屏蔽掉所有关于java.awt的警告他举这个例子是为了说明一个理论:当你绝对确定自己的代码没有用到报错的这个类后,可以使用-dontwarn com.xx.bbb**来屏蔽警告信息
3.总结出官方对于
Warning: can't find superclass or interface Warning: can't find referenced class 这两个问题的解决方法:
1.要把你项目中所引入的第三方jar包使用"-libraryjars 包路径"指定好。
2.还是报错的话,确保报错的类没有在你的项目中使用到,使用"-dontwarn 类名正则表达式"屏蔽警告。
完了?可是我还想问:第一步做完后还是报错,而且这个类在我项目中真的有用到,不能使用"-dontwarn .."屏蔽警告啊??
4.说了这么久,终于开始说解决方案了:
其实找不到引用的这个类是第三方包里面的,而且很多时候我们只需要打乱自己的代码就行了,第三方包的代码就是否要打乱就不要管了。嘻嘻,这叫做"只扫自己门前雪,甭管他人瓦上霜",
我们可以使用
-dontwarn com.xx.bbb.**
-keep class com.xx.bbb.** { *;}
参数来保持第三方库中的类而不乱,-dontwarn和-keep 结合使用,意思是保持com.xx.bbb.**这个包里面的所有类和所有方法而不混淆,接着还叫ProGuard不要警告找不到com.xx.bbb.**这个包里面的类的相关引用。
配置好后,重新打包,一切OK!而且程序能正确运行
//---------------------
出现can't find referenced class的警告时,可以在proguard.cfg中添加-ignorewarnings来解决。
另外,对于有的第三方jar,可能已经进行过代码混淆了,在这里就要保持,例如百度的地图包jar。保持jar,避免混淆的代码如下:
-keep class com.baidu.mapapi.** {*;}
不混淆com.baidu.mapapi包中的所有代码,类名、方法、变量等。