關於Android H5混合開發遇到的問題

添加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::GpuMain08-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 0000000060000000backtrace:
    #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三個方法後,報錯就查看具體複寫的代碼,一下是複寫代碼詳情:

@Overridepublic 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;
}@Overridepublic 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;
}@Overridepublic 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()方法裏面出現問題了。這兩個方法是從網上找來的,具體代碼如下:

@Overrideprotected void onResume() {	super.onResume();	if (mWebView != null) {
		mWebView.onResume();
	}
}@Overrideprotected 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()沒有恢復運行,所以造成這個問題


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章