總結
參考:https://www.jianshu.com/p/fd61e8f4049e
內核版本比較:https://www.cnblogs.com/gcczhongduan/p/4237959.html
x5 和 原生 比較:https://www.jianshu.com/p/d27f3379a4b7
使用心得
https://www.jianshu.com/p/3c94ae673e2a
https://www.jianshu.com/p/52ec85259ccc
1.WebView 中網頁的前進 / 後退
webView.goBack();//跳到上個頁面
webView.goForward();//跳到下個頁面
webView.canGoBack();//是否可以跳到上一頁(如果返回false,說明已經是第一頁)
webView.canGoForward();//是否可以跳到下一頁(如果返回false,說明已經是最後一頁)
- 常見用法:Back 鍵控制網頁後退
問題:在不做任何處理前提下 ,瀏覽網頁時點擊系統的「 Back 」鍵,整個 Browser 會調用 finish()而結束自身
目標:點擊返回後,是網頁回退而不是推出瀏覽器
解決方案:在當前 Activity 中處理並消費掉該 Back 事件
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
2.webView 緩存設置
//優先使用緩存:
webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
//緩存模式如下:
//LOAD_CACHE_ONLY: 不使用網絡,只讀取本地緩存數據
//LOAD_DEFAULT: (默認)根據cache-control決定是否從網絡上取數據。
//LOAD_NO_CACHE: 不使用緩存,只從網絡獲取數據.
//LOAD_CACHE_ELSE_NETWORK,只要本地有,無論是否過期,或者no-cache,都使用緩存中的數據。
//不使用緩存:
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
3.webView 清除緩存
//清除網頁訪問留下的緩存
//由於內核緩存是全局的因此這個方法不僅僅針對webview而是針對整個應用程序.
webView.clearCache(true);
//清除當前webview訪問的歷史記錄
//只會webview訪問歷史記錄裏的所有記錄除了當前訪問記錄
webView.clearHistory();
//這個api僅僅清除自動完成填充的表單數據,並不會清除WebView存儲到本地的數據
webView.clearFormData();
另外一種方式:
//刪除緩存文件夾
File file = CacheManager.getCacheFileBaseDir();
if (file != null && file.exists() && file.isDirectory()) {
for (File item : file.listFiles()) {
item.delete();
}
file.delete();
}
//刪除緩存數據庫
context.deleteDatabase("webview.db");
context.deleteDatabase("webviewCache.db");
4.cookies 設置,獲取和清除
- Cookie 設置
代碼
CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
String cookie = "name=xxx;age=18";
cookieManager.setCookie(URL, cookie);
CookieSyncManager.getInstance().sync();
- 獲取 Cookie
code:
CookieManager cookieManager = CookieManager.getInstance();
String cookie = cookieManager.getCookie(URL);
- 清除 Cookie
code
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
CookieSyncManager.getInstance().sync();
5.webview 和 js 交互
- JavaScript 調用 Android
code
WebSettings settings = mWebView.getSettings();
settings.setJavaScriptEnabled(true);//開啓JavaScript
mWebView.loadUrl("file:///android_asset/keithxiaoy.html");//加載本地網頁
mWebView.setWebChromeClient(new WebChromeClient());//此行代碼可以保證JavaScript的Alert彈窗正常彈出
//核心方法, 用於處理JavaScript被執行後的回調
mWebView.addJavascriptInterface(new JsCallback() {
@JavascriptInterface//注意:此處一定要加該註解,否則在4.1+系統上運行失敗
@Override
public void onJsCallback() {
System.out.println("JavaScript調用Android啦");
}
}, "keithxiaoy");//參1是回調接口的實現;參2是JavaScript回調對象的名稱
//定義回調接口
public interface JsCallback {
public void onJsCallback();
}
- Android 調用 JavaScript
code
//直接使用webview加載js就可以了
mWebView.loadUrl("javascript:wave()");
- 附上 keithxiaoy.html 源碼
code
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<script language="javascript">
/* This function is invoked by the activity */
function wave() {
alert("Android調用JavaScript");
}
</script>
<body>
<!-- JavaScript調用Android代碼 -->
<a onClick="window.demo.onJsCallback()"><div style="width:80px;
margin:0px auto;
padding:10px;
text-align:center;
border:2px solid #202020;" >
![](android_normal.png)<br>
Click me!
</div></a>
</body>
</html>
面試題
1.WebView的內存泄露。
(1)微信和qq的做法:
就是 當你要用webview的時候,記得最好 另外單獨開一個進程 去使用webview 並且當這個 進程結束時,請手動調用System.exit(0)。
這是目前對於webview 內存泄露 最好的解決方案。使用此方法 所有因爲webview引發的 資源無法釋放等問題 全部可以解決。
(2)還有一種方法:
動態添加webview,對傳入webview中使用的Context使用弱引用,動態添加webview意思在佈局創建個viewGroup用來放置webview,Activity創建時add進來,在Activity停止時remove掉
2.WebView中使用setBuiltInZoomControls進行縮放並destroy webview時崩潰
問題描述:webview使用settings.setBuiltInZoomControls(true);進行控制縮放。由於某些原因需要在該activity的onDestroy方法裏面調用webView.destroy()。當進入該webview並且進行縮放操作時,退出該activity程序崩潰。
settings代碼如下:
settings = previewWebview.getSettings();
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
settings.setBuiltInZoomControls(true);
settings.setDefaultTextEncodingName("gbk");
啓用後,用戶一旦觸摸屏幕,就會出現縮放控制圖標。這個圖標過上幾秒會自動消失,但在3.X系統上,如果圖標自動消失前退出當前Activity的話,就會報異常。
最終解決方法:
在Activity的onDestroy裏面加上這麼一句:web.setVisibility(View.GONE);把WebView設置爲GONE就可以了
3.後臺無法釋放js 導致耗電
這個可能很少有人知道,你如果webview加載的html裏 有一些js 一直在執行比如動畫之類的東西,如果此刻webview 掛在了後臺
這些資源是不會被釋放,用戶也無法感知,導致一直佔有cpu 耗電特別快,所以大家記住了,如果遇到這種情況 請在onstop和onresume裏分別把setJavaScriptEnabled();
給設置成false和true
4.Android中如何直接調用JS中的函數?
1.html中有js的方法callJs()裏面去調用alert()方法
2.webview.setWebChromeClient()中的onJsAlert()去處理JS對話框
3.webview.loadUrl(“javascript:callJS()”)去直接調用
問:如何通過evaluateJavascript直接調用JS中的函數?
webview.evaluateJavascript(“javascript:callJS()”)去調用JS的方法,並且在ValueCallback中能獲取JS的返回值。
建議混合使用上面的兩種交互方法
1.API < 18, Android 4.4以下使用loadUrl
2.API >=18, 使用evaluateJavascript
5.JS調用Android有哪些方法?
- 通過WebView的addJavascriptInterface()進行對象映射
- 通過WebViewClient的shouldOverrideUrlLoading()方法回調攔截url
- 通過WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt()消息
問:addJavascriptInterface()對象映射是如何使用的?
- html中調用某對象的某個方法:如jsObject.hello(“js調用了android中的hello方法”);
- Android中實現一個自定義類,具有方法hello(),該方法使用註解@JavascriptInterface
- 進行映射webview.addJavascriptInterface(new 自定義類(), “jsObject”)
- 加載js代碼:webview.loadUrl(“file:///android_asset/jsCallAndroid.html”);
問:addJavascriptInterface()存在嚴重漏洞
- Android 4.2(17)版本開始通過@JavascriptInterface規避該漏洞
- 該漏洞會導致攻擊者能執行任意Java對象的方法。
問:WebViewClient 中對url攔截
- js中約定url協議
- Android中在 shouldOverrideUrlLoading進行解析攔截
問:JS中如何獲得Android方法執行的返回值?
- 只能採用特殊方法去處理
- js定義一個方法,如命名爲returnResult(result)
- android中通過mWebView.loadUrl(“javascript:returnResult(” + result + “)”);將方法返回值作爲參數傳入進去。
問:如何通過WebChromeClient的onJsAlert()\onJsConfirm()\onJsPrompt()方法回調攔截JS對話框alert()\confirm\prompt()消息
- Android中通過WebChromeClient的onJsAlert()\onJsConfirm()\onJsPrompt()方法回調分別攔截JS對話框。
- 本質是JS彈出對畫框,Android攔截了對話框,解析參數中的url等信息,去做事先約定好的任務。
總結
6.WebView初始化
問題描述:
1.當App首次打開時,默認是並不初始化瀏覽器內核的;只有當創建WebView實例的時候,纔會創建WebView的基礎框架。
所以與瀏覽器不同,App中打開WebView的第一步並不是建立連接,而是啓動瀏覽器內核。
2.在瀏覽器中,我們輸入地址時(甚至在之前),瀏覽器就可以開始加載頁面。而在客戶端中,客戶端需要先花費時間初始化WebView完成後,纔開始加載。
解決方法
方案1,全局WebView
在客戶端剛啓動時,就初始化一個全局的WebView待用,並隱藏;當用戶訪問了WebView時,直接使用這個WebView加載對應網頁,並展示。這種方法可以比較有效的減少WebView在App中的首次打開時間。當用戶訪問頁面時,不需要初始化WebView的時間。當然這也帶來了一些問題,包括:額外的內存消耗。頁面間跳轉需要清空上一個頁面的痕跡,更容易內存泄露。
方法2,客戶端代理數據請求
在客戶端初始化WebView的同時,直接由native開始網絡請求數據;當頁面初始化完成後,向native獲取其代理請求的數據。此方法雖然不能減小WebView初始化時間,但數據請求和WebView初始化可以並行進行,總體的頁面加載時間就縮短了;縮短總體的頁面加載時間:
還有其他各種優化的方式,不再一一列舉,總結起來都是圍繞兩點:
在使用前預先初始化好WebView,從而減小耗時。
在初始化的同時,通過Native來完成一些網絡請求等過程,使得WebView初始化不是完全的阻塞後續過程。
7.描述一下Webview的作用
WebView控件功能強大,除了具有一般View的屬性和設置外,還可以對url請求、頁面加載、渲染、頁面交互進行強大的處理。
8.WebView的內核是什麼
Android的Webview在低版本和高版本採用了不同的webkit版本內核,4.4後直接使用了Chrome。
9.描述一下WebView與js的交互方式
https://blog.csdn.net/carson_ho/article/details/64904691
10.描述一下WebView的緩存機制
https://www.jianshu.com/p/5e7075f4875f
11.關於WebView的優化你知道哪些
https://www.jianshu.com/p/95d4d73be3d1