WebView相关知识整理
WebView使用总结
前言:
最近,修改了项目中网页中点击图片跳转查看大图页面的需求,激发了我归纳总结WebView的想法,今天再次整理一下。
包含:使用过程,关键类,js交互,注意事项,以及几个常见的需求解决思路等。
献上一张框架图
基本简介
内核
在4.4以前的版本是WebKit的内核,4.4以后才换成chromium的内核
可使用第三方WebView组件Crosswalk和TBS服务,具体区别后面再整理
作用
- 显示和渲染web页面
- 直接加载Html文件(网络或者本地asserts)
- 与js互调
状态
激活WebView为活跃状态,能正常执行网页的响应
当页面被失去焦点被切换到后台不可见状态,需要执行onPause,通过onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。
Webview后台耗电的问题
当应用程序(存在webview)被切换到后台时,需要暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
可以调用此方法
恢复pauseTimers状态
注意:
由于pauseTimers和resumeTimers是全局生效的, 并不只影响单个WebView, resumeTimers注意不要遗漏, 否则遗漏的WebView会出现异常. 最好在重写的WebView
- rootLayout.removeView(webView);
- webView.destroy();
销毁Webview,在关闭了Activity时,如果Webview的音乐或视频,还在播放。就必须销毁Webview
但是注意:webview调用destory时,webview仍绑定在Activity上
这是由于自定义webview构建时传入了该Activity的context对象
因此需要先从父容器中移除webview,然后再销毁webview:
前进回退网页
是否可以后退
后退网页
是否可以前进
前进网页
- Webview.goBackOrForward(intsteps)
以当前的index为起始点前进或者后退到历史记录中指定的steps
如果steps为负数则为后退,正数则为前进
常见用法:
在不做任何处理前提下 ,浏览网页时点击系统的“Back”键,整个 Browser 会调用 finish()而结束自身
点击返回后,是网页回退而不是推出浏览器
在当前Activity中处理并消费掉该 Back 事件
1 2 3 4 5 6 7
| public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) { mWebView.goBack(); return true; } return super.onKeyDown(keyCode, event); }
|
常用类
WebSettings
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setPluginsEnabled(true);
webSettings.setUseWideViewPort(true); webSettings.setLoadWithOverviewMode(true);
webSettings.setSupportZoom(true); webSettings.setBuiltInZoomControls(true); webSettings.setDisplayZoomControls(false);
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); webSettings.setAllowFileAccess(true); webSettings.setJavaScriptCanOpenWindowsAutomatically(true); webSettings.setLoadsImagesAutomatically(true); webSettings.setDefaultTextEncodingName("utf-8");
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
|
常见缓存用法
1 2 3 4 5 6 7 8 9 10 11 12
| if (NetStatusUtil.isConnected(getApplicationContext())) { webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); } else { webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); }
webSettings.setDomStorageEnabled(true); webSettings.setDatabaseEnabled(true); webSettings.setAppCacheEnabled(true);
String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME; webSettings.setAppCachePath(cacheDirPath);
|
每个 Application 只调用一次 WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()
WebViewClient
主要辅助WebView处理各种通知、请求事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| new WebViewClient(){
@Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { return super.shouldOverrideUrlLoading(view, request); }
@Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); }
@Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); }
@Override public void onLoadResource(WebView view, String url) { super.onLoadResource(view, url); }
@Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { super.onReceivedError(view, request, error); }
@Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed(); } };
|
WebChromClient
辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。
1 2 3 4 5 6 7 8 9 10
| webview.setWebChromeClient(new WebChromeClient(){
@Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress < 100) { String progress = newProgress + "%"; progress.setText(progress); } else { } });
|
1 2 3 4 5 6
| webview.setWebChromeClient(new WebChromeClient(){
@Override public void onReceivedTitle(WebView view, String title) { titleview.setText(title); }
|
JS交互
原文
Android调Js
使用建议
两种方法混合使用,即Android 4.4以下使用方法1,Android 4.4以上方法2
1 2 3 4 5 6 7 8 9 10 11 12 13
| final int version = Build.VERSION.SDK_INT;
if (version < 18) { mWebView.loadUrl("javascript:callJS()"); } else { mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { } }); }
|
通过loadUrl方式调用js
Html代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| // 文本名:javascript <!DOCTYPE html> <html>
<head> <meta charset="utf-8"> <title>Carson_Ho</title>
// JS代码 <script>
function callJS(){ alert("Android调用了JS的callJS方法"); } </script>
</head>
</html>
|
Android代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| webSettings.setJavaScriptEnabled(true); webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
mWebView.loadUrl("file:///android_asset/javascript.html");
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mWebView.post(new Runnable() { @Override public void run() {
mWebView.loadUrl("javascript:callJS()"); } });
} });
mWebView.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this); b.setTitle("Alert"); b.setMessage(message); b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }); b.setCancelable(false); b.create().show(); return true; }
});
}
|
特别注意:JS代码调用一定要在 onPageFinished() 回调之后才能调用,否则不会调用。
onPageFinished()
属于WebViewClient类的方法,主要在页面加载结束时调用
所以一般等onPageFnished回调之后,我们才显示H5的页面,加载未完全的时候,则显示loading页面
通过evaluateJavascript调用js
优点
该方法比第一种方法效率更高、使用更简洁。
- 因为该方法的执行不会使页面刷新,而第一种方法(loadUrl )的执行则会。
- Android 4.4 后才可使用
1 2 3 4 5 6 7 8
| mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { } }); }
|
Js调Android
缓存问题
原文
参考链接
Carson_Ho