添加WebChromeClient,复写onJsAlert、onJsConfirm、onJsPrompt方法后,弹框异常退出问题
项目经理说,Android没有处理弹框,点击按钮没有反应,iOS就可以。于是就复写了onJsAlert、onJsConfirm、onJsPrompt三个方法,来处理页面上的弹框。写完后满心喜悦的以为可以了,没想到项目经理说,点击按钮异常退出;然后自己查看日志:
08-06 10:41:53.023 29277-29339/com.medicine E/chromium: [ERROR:child_thread_impl.cc(762)] Request for unknown Channel-associated interface: ui::mojom::GpuMain
08-06 10:41:53.036 29277-29338/com.medicine E/libEGL: cache file failed CRC check
然并卵,这样的日志并不能查找出问题,还好红米手机有捕捉异常的功能,详细异常如下:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Xiaomi/hennessy/hennessy:5.0.2/LRX22G/V9.6.1.0.LHNCNFD:user/release-keys'
Revision: '0'
ABI: 'arm64'
pid: 27850, tid: 27850, name: medicine >>> com.medicine <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: '[FATAL:jni_android.cc(243)] Please include Java exception stack in crash report
'
x0 0000000000000000 x1 0000000000006cca x2 0000000000000006 x3 0000007fae06a0f0
x4 0000007fae06a0f0 x5 0000000000000005 x6 0000000000000001 x7 0000000000000020
x8 0000000000000083 x9 0000007fd82d9043 x10 0000007fd82d8ff8 x11 0000000000000001
x12 0000000000000001 x13 0000000000000054 x14 0000007f9d9dd7c8 x15 0000007fae035bc0
x16 0000007fae02d7e0 x17 0000007fadff258c x18 0000000000000000 x19 0000007fae06a0f0
x20 0000007fae06a3a8 x21 0000007fae033000 x22 000000000000000b x23 0000000000000006
x24 0000007fd82d98f0 x25 0000007fd82d9ab8 x26 0000000061100021 x27 000000007a90001d
x28 00000055bc8f0a60 x29 0000007fd82d9320 x30 0000007fadfaeb6c
sp 0000007fd82d9320 pc 0000007fadff2594 pstate 0000000060000000
backtrace:
#00 pc 0000000000061594 /system/lib64/libc.so (tgkill+8)
#01 pc 000000000001db68 /system/lib64/libc.so (pthread_kill+160)
#02 pc 000000000001f09c /system/lib64/libc.so (raise+28)
#03 pc 0000000000018abc /system/lib64/libc.so (abort+60)
#04 pc 0000000000771f20 /system/app/WebViewGoogle/lib/arm64/libwebviewchromium.so
虽然获取到了更多的信息,我还是想哭,还是没有一点用处,都是底层框架的错误信息,对于查找错误还是云里雾里,只好去排查代码。既然是复写onJsAlert、onJsConfirm、onJsPrompt三个方法后,报错就查看具体复写的代码,一下是复写代码详情:
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
new AlertDialog.Builder(view.getContext())
.setTitle("对话框")
.setMessage(message)
.setPositiveButton("确定", (dialog, which) -> {
result.confirm();
dialog.dismiss();
})
.setCancelable(false)
.show();
return true;
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
new AlertDialog.Builder(view.getContext())
.setTitle("对话框")
.setMessage(message)
.setPositiveButton("确定", ((dialog, i) -> {
result.confirm();
dialog.dismiss();
}))
.setNegativeButton("取消", (dialogInterface, i) -> result.cancel())
.setOnCancelListener(dialogInterface -> result.cancel())
.show();
return true;
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
final EditText et = new EditText(view.getContext());
et.setSingleLine();
et.setText(defaultValue);
new AlertDialog.Builder(view.getContext())
.setTitle("对话框")
.setMessage(message)
.setView(et)
.setPositiveButton("确定", ((dialog, i) -> {
result.confirm(et.getText().toString());
dialog.dismiss();
}))
.setNegativeButton("取消", (dialogInterface, i) -> result.cancel())
.setOnCancelListener(dialogInterface -> result.cancel())
.show();
return true;
}
查看代码的时候,发现new AlerDialog
的时候用的是view.getContext()
,然后发现new WebView()
的时候用的是getApplicationContext()
;我们知道AlertDialog的Context只能是Activity,所以发现问题;把getApplicationContext()改为当前Activity后,问题就解决了。
移动端日历控件ICalendar.js在Android息屏后,不能选择时间,时间只能是当前时间
测试人员说,Android端在选择时间的时候失败,只可以选择当前时间。于是自己测试,第一次进入可以选择时间,没有问题;但是当锁屏后,再次进入页面后,可以弹出日期选择框,滚动日期的时候,明显发现日期滚动不顺畅,并且预期的时间并没有出现,而是默认的当前时间。
找到问题所在,然后查找问题根源在哪里:既然是在锁屏后出现问题,会不会是onPause()和onResume()方法里面的问题呢;心中有了这样的想法后就把onPause()和onResume()注释了,再次运行,发现日期选择正常了;如此看来,的确是onPause()和onResume()方法里面出现问题了。这两个方法是从网上找来的,具体代码如下:
@Override
protected void onResume() {
super.onResume();
if (mWebView != null) {
mWebView.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (mWebView != null) {
mWebView.onPause();
mWebView.pauseTimers();
}
}
copy的代码也没有深究,但是发现有个方法没有成对出现mWebView.pauseTimers()
,然后查看源代码,文档解释为:
Pauses all layout, parsing, and JavaScript timers for all WebViews. This is a global requests, not restricted to just this WebView. This can be useful if the application has been paused.
机器翻译为:暂停所有WebView的所有布局,解析和JavaScript计时器。此是全局请求,不仅限于此WebView。如果应用程序已暂停,这可能很有用。
然后再WebView源码中发现pauseTimers()
方法下面就是resumeTimers()
方法,喜出望外,文档解释为:
Resumes all layout, parsing, and JavaScript timers for all WebViews. This will resume dispatching all timers.
机器翻译为:恢复所有WebView的所有布局,解析和JavaScript计时器。 这将继续调度所有计时器。
于是,恢复注释的代码,在Activity的onResume()方法中加上mWebView.resumeTimers()
,运行项目,发现问题解决。因此,具体问题是在Activity息屏后调用webview的pauseTimers()方法,把js功能暂停;但是在onResume()没有恢复运行,所以造成这个问题。