Proguard导致的NoSuchMethodException问题排查
背景
之前项目的混淆配置一直没开启Proguard的优化选项
-dontoptimize
最近为了做安装包优化,把这行注释掉了
#-dontoptimize
问题
于是项目里的各种优化配置开始生效了,但是测试反馈了一个Bug:悬浮窗的搜索框点击之后没有反应了。
排查一番后发现了问题代码的位置:
......
try {
.....
if (params == null) {
floatWindowView = (View) floatWindowClass.getConstructor(Context.class).newInstance(AstApp.self());
} else {
floatWindowView = (View) floatWindowClass.getConstructor(Context.class, Bundle.class).newInstance(AstApp.self(), params);
}
......
} catch (Exception e) {
if (Global.ASSISTANT_DEBUG)e.printStackTrace();
Log.e(FloatWindowBigView.tag, "exc " + e.getMessage());
} catch (Throwable tr) {
Log.e(FloatWindowBigView.tag, "exc " + tr.getMessage());
}
对应的错误日志如下:
java.lang.NoSuchMethodException: <init> [class android.content.Context]
at java.lang.Class.getConstructor0(Class.java:2320)
at java.lang.Class.getConstructor(Class.java:1725)
at com.tencent.nucleus.manager.floatingwindow.manager.FloatingWindowManager.a(ProGuard:385)
at com.tencent.nucleus.manager.floatingwindow.view.FloatWindowBigView.onClick(ProGuard:10146)
at android.view.View.performClick(View.java:6266)
at android.view.View$PerformClick.run(View.java:24730)
at android.os.Handler.handleCallback(Handler.java:793)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:6701)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:249)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
exc <init> [class android.content.Context]
即 <init> 这个方法找不到了,于是看了Proguard的配置,发现其实是有配置相关的:
#<!-- 悬浮窗的view不混淆 -->
-keepclasseswithmembers class com.tencent.nucleus.manager.floatingwindow.view.* {public <init>(android.content.Context);}
-keepclasseswithmembers class com.tencent.nucleus.manager.floatingwindow.view.* {public <init>(android.content.Context,android.os.Bundle);}
-keepclasseswithmembers class com.tencent.assistant.manager.specialpermission.GuideFloatView {public <init>(android.content.Context);}
-keepclasseswithmembers class com.tencent.assistant.manager.specialpermission.GuideFloatView {public <init>(android.content.Context,android.os.Bundle);}
解决
那么为什么还是出了问题呢?原因就在于之前的开发同学把搜索框相关的类FloatWindowSearchView 和 FloatWindowSearchResultView 放在了 floatingwindow.manager 包下面,而不是 floatingwindow.view ,所以这个类的<init> 方法被优化掉了。那为什么之前没问题呢?
因为之前设置了 -dontoptimize 这个选项,所以不会针对 <init> 这个级别的方法做优化,只会针对工程代码混淆。
解决办法就是把搜索框相关的两个类也放在floatingwindow.view 包下面。
感觉这真是一个经典的前人挖坑后人踩的案例,也说明了按照项目规范组织文件的重要性~
(注意manager下面有两个自定义View)