前言
本地开发的时候运行正常,开启了混淆之后编译通过运行失败
描述
项目中遇到了一个问题,module中有一个方法,改方法会抛Exception,
public Map encryptParams(Map params) throws Exception {
return params;
}
在主工程中有一个改类的子类复写类该方法,做了一些其他的逻辑,开发的时候为类方便把混淆关了直接关联工程开发。调试完毕之后开了混淆准备打包然后就build 失败。
根据提示判断是因为父类中的encryptParams()方法未抛Exception,所以子类也不能抛。看代码确定是有throw Exception的,于是Module打出来的jar反编译下看看到底有没有。
JD-GUI可以很方便的反编译jar包。使用AndroidStudio更方便直接把jar拖到libs下面,然后sync。
可以看到混淆后的代码
来一张对比的
对比发现混淆后的jar是没有throw Exception的,这里的gradle版本是1.5.0,仔细观察发现map的泛型也没有。
再来一张gradle 2.3.3 版本的(因为我Studio版本是2.3.3的),有泛型没有throw Exception
最后放上三个对比的
// 混淆后 gradle 1.5.0
// public Map encryptParams(Map var1) {
// return var1;
// }
// 混淆后 gradle 2.3.3
// public MapencryptParams(Mapvar1) {
// return var1;
// }
//混淆前
public Map encryptParams(Map params) throws Exception {
return params;
}
Demo地址
结论
gradle 1.5.0版本 在开启混淆生成jar的时候会把泛型和throw Exception去掉,gradle 2.3.3版本开启有泛型无throw Exception。原因暂未查到,有清楚的欢迎讨论。
补充
后期发现泛型是因为没有在混淆配置中添加忽略,添加以下内容就可以保留混淆。
# 避免混淆泛型
-keepattributes Signature
最终解决方案
今天突然想起来,EventBus在注册了两次之后会抛异常,就去看下EventBus怎么处理的。直接看代码
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
...
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
...
抛了异常但方法上没有throws ,跟进去EventBusException
public class EventBusException extends RuntimeException { ... }
原来如此。
方法来了,只需要把我们之前的Exception 换成 RuntimeException或者自定义一个他的子类就可以解决库中抛的异常不会打进jar中的问题了,然后在需要的地方处理catch到的异常。
Exception:在程序中必须使用try…catch进行处理。
RuntimeException:可以不使用try…catch进行处理,但是如果有异常产生,则异常将由JVM进行处理。
所以,为了保证程序再出错后依然可以执行,在开发代码时最好使用try…catch的异常处理机制进行处理。