webview最全面總結(二)全面介紹webview用法
簡單介紹
為了方便開發者實現在app內展示網頁並與網頁互動的需求,Android SDK提供了WebView元件
它有如下功能:
- 顯示和渲染Web頁面
- 直接使用html檔案(網路上或本地assets中)作佈局
- 可和JavaScript互動呼叫
- WebView控制元件功能強大,除了具有一般View的屬性和設定外,還可以對url請求、頁面載入、渲染、頁面互動進行強大的處理。
基本使用
下面簡單介紹下WebView的基本使用:
首先新建一個工程,在layout檔案裡放入一個WebView控制元件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<WebView
android:id="@+id/webview1"
android:layout_width="match_parent"
android:layout_height="match_parent">
</WebView>
</RelativeLayout>
然後在Activity初始化方法裡寫入如下程式碼:
String url = "https://www.kkj.cn";
WebView webView = (WebView) findViewById(R.id.web_view);
webView.loadUrl(url);
WebSettings webSettings = webview.getSettings();
webSettings.setJavaScriptEnabled (true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
不要忘了在AndroidManifest宣告訪問網路的許可權:
<uses-permission android:name="android.permission.INTERNET"/>
然後bingo執行,我們會發現,納尼,居然在外部的預設瀏覽器中打開了這個連結。
因為預設情況下,一個WebView提供的是不像瀏覽器的控制元件,沒有開啟JavaScript並且忽略網頁錯誤。如果你的目的是僅僅顯示一些HTML作為你的UI的一部分,那顯示可能是沒有問題的(顯示正常),使用者僅僅閱讀網頁而不需要與之互動,並且網頁也不需要和使用者互動。
如果你想要在webview內部開啟,則需要自定義WebChromeClient 方法。
一般我們重寫最多的就是shouldOverrideUrlLoading()、onPageStarted()、onPageFinished()問題。
webview.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
//webview頁面載入開始時就會執行此方法、一般用作重定向時的初始化工作
//該方法在WebView開始載入頁面且僅在Main frame loading(即整頁載入)時回撥,一次Main frame的載入只會回撥該方法一次。我們可以在這個方法裡設定開啟一個載入的動畫,告訴使用者程式在等待網路的響應。
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//該方法只在WebView完成一個頁面載入時呼叫一次(同樣也只在Main frame loading時呼叫),我們可以可以在此時關閉載入動畫,進行其他操作。
}
});
這樣重寫之後,我們就能在webview裡面開啟我們想要開啟的頁面了。然而,我們發現,當我們在我們開啟頁面的頁面中繼續跳轉時候,再按系統返回鍵,會發現,直接關閉了webview,這顯然不是我們想要的結果。
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//這是一個監聽用的按鍵的方法,keyCode 監聽使用者的動作,如果是按了返回鍵,同時Webview要返回的話,WebView執行回退操作,因為mWebView.canGoBack()返回的是一個Boolean型別,所以我們把它返回為true
if(keyCode==KeyEvent.KEYCODE_BACK&&webview.canGoBack()){
webview.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
重寫返回鍵之後就能實現,在網頁中返回上一步。
詳細看一下webview的各個知識點。
載入方式
1、loadUrl(String url)
用的最多的載入方式,
des:Load the given url.
as: webView.loadUrl(“http://www.kkj.cn/“); //載入網路網頁
webView.loadUrl(“file:///android_asset/html/index.html”); //載入本地assert目錄下網頁
webView.loadUrl(“content://com.Android.htmlfileprovider/sdcard/kris.html”); // 載入SD卡html
2、loadData(String data, String mimeType, String encoding)
des:Load the given data into the WebView.
as:
String summary = “You scored 192 points.”;
webview.loadData(summary, “text/html”, null);
如果後臺給的資料是包含html的字串,則需要用這種方式進行載入,這種方式省流量,速度快,但是需要注意編碼問題。
loadData()中的html data不能包含’#’,’%’,’\’,’?’四種特殊字元
3、loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)
des:Load the given data into the WebView, use the provided URL as the base URL for the content.
webview的設定
WebSettings webSettings = webview.getSettings();
//支援js事件
webSettings.setJavaScriptEnabled(true);
/* 設定為true表示支援使用js開啟新的視窗 */
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
/* 設定為使用webview推薦的視窗 */
webSettings.setUseWideViewPort(true);
/* 設定網頁自適應螢幕大小 ---這個屬性應該是跟上面一個屬性一起用 */
webSettings.setLoadWithOverviewMode(true);
/* 設定是否允許webview使用縮放的功能,我這裡設為false,不允許 */
webSettings.setBuiltInZoomControls(false);
webSettings.setBuiltInZoomControls(true); //顯示或不顯示縮放按鈕(wap網頁不支援)。
webSettings.setSupportMultipleWindows(true);//設定WebView是否支援多視窗。
webSettings.setAppCacheEnabled(true); //啟用或禁用應用快取。
webSettings.setAppCachePath("");//設定應用快取路徑,這個路徑必須是可以讓app寫入檔案的。該方法應該只被呼叫一次,重複呼叫會被無視~
webSettings.setCacheMode(LOAD_DEFAULT);//用來設定WebView的快取模式。當我們載入頁面或從上一個頁面返回的時候,會按照設定的快取模式去檢查並使用(或不使用)快取。
篇幅限制,僅列了一些最常用的設定,webview還可以設定更多內容,儲存,預設字型大小,預設字元編碼等等,
具體可以參考,史上最全的WebSettings說明
對於webview也有
webView.setHorizontalScrollBarEnabled(false);//水平不顯示
webView.setVerticalScrollBarEnabled(false); //垂直不顯示
webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);// 隱藏滾動條
webView.requestFocus(); 設定是否獲取焦點
webView.requestFocusFromTouch();
WebViewClient
主要幫助WebView處理各種通知、請求事件(例如,點選連結時候如何顯示介面,頁面開始載入,載入完畢之後
webview.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
//webview頁面載入開始時就會執行此方法、一般用作重定向時的初始化工作
//該方法在WebView開始載入頁面且僅在Main frame loading(即整頁載入)時回撥,一次Main frame的載入只會回撥該方法一次。我們可以在這個方法裡設定開啟一個載入的動畫,告訴使用者程式在等待網路的響應。
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//該方法只在WebView完成一個頁面載入時呼叫一次(同樣也只在Main frame loading時呼叫),我們可以可以在此時關閉載入動畫,進行其他操作。
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
// 這裡進行無網路或錯誤處理,具體可以根據errorCode的值進行判斷,
}
shouldOverrideUrlLoading()方法分析
從實踐中我們知道,當我們沒有給WebView提供WebViewClient時,WebView如果要載入一個url會向ActivityManager尋求一個適合的處理者來載入該url(比如系統自帶的瀏覽器),這通常是我們不想看到的。於是我們需要給WebView提供一個WebViewClient,並重寫該方法返回true來告知WebView url的載入就在app中進行。這時便可以實現在app內訪問網頁
簡單來說就是:
1、若沒有設定 WebViewClient 則在點選連結之後由系統處理該 url,通常是使用瀏覽器開啟或彈出瀏覽器選擇對話方塊。
2、若設定 WebViewClient 且該方法返回 true ,則說明由應用的程式碼處理該 url,WebView 不處理。
3、若設定 WebViewClient 且該方法返回 false,則說明由 WebView 處理該 url,即用 WebView 載入該 url。
WebChromeClient
輔助WebView處理Javascript的對話方塊、網站圖示、網站Title、載入進度等
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
// 獲得網頁的載入進度 newProgress為當前載入百分比
super.onProgressChanged(view, newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
// 獲取網頁的title,客戶端可以在這裡動態修改頁面的title
// 另外,當載入錯誤時title為“找不到該網頁”
super.onReceivedTitle(view, title);
}
});
js的互動
webView.addJavascriptInterface()
通過addJavascriptInterface(Object, String)方法注入Java物件到WebView。這個方法允許你注入一個Java物件到網頁的JavaScript 的上下文,以便通過頁面中的JavaScript呼叫。
簡單粗暴時候可以這樣寫:
myWebView.addJavascriptInterface(new JSInterface(){
@JavascriptInterface
public String methodA(){
return ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId();
}
@JavascriptInterface
public void methodB(String webMessage) { }
}, "Android");
方法可能會很多,所以我們要學會優雅一些;
mWebView.addJavascriptInterface(new JSInterface(), "Android"); //model是自定義的,隨便起。
JSInterface物件:
public class JSInterface {
@JavascriptInterface
public void methodA() { }
@JavascriptInterface
public void methodB(String webMessage) { }
}
ps:SDK>=17(Android4.2)以上,必須新增@JavascriptInterface宣告,為避免因使用者訪問不安全網頁導致js漏洞盜竊使用者資訊等不安全行為。
js調java:
Java物件到WebView之後,我們要在js裡面呼叫 java方法。
所有呼叫的方法都要寫在class JSInterface{ }中。
funtion a{
winow.Android.methodA(); //可帶引數
}
java調js:
在webview裡面呼叫js方法:
webview.loadUrl("javascript:alert()");
前進後退重新整理
webview是否可以返回到上一頁面 webView.canGoBack()
webview返回到上一頁面 webView.goBack();
webview是否可以前進 webView.canGoForward()
webview前進 webView.goForward();
webview.reload(); 重新整理
舉個回退的簡單例子簡單說明
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
判斷Webview是否滑動到頂部或底部
if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {
// 處於底端
}
if(webView.getScrollY() == 0){
//處於頂部
}
getScrollY() //方法返回的是當前可見區域的頂端距整個頁面頂端的距離,也就是當前內容滾動的距離.
getHeight()或者getBottom() //方法都返回當前WebView這個容器的高度
getContentHeight()返回的是整個html的高度,但並不等同於當前整個頁面的高度,因為WebView有縮放功能,所以當前整個頁面的高度實際上應該是原始html的高度再乘上縮放比例
webView的狀態
//當應用程式(存在webview)被切換到後臺時,這個方法不僅僅針對當前的webview而是全域性的全應用程式的webview
//它會暫停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
@Override
protected void onPause() {
webview.onPause();
webview.pauseTimers();
super.onPause();
}
@Override
protected void onResume() {
webview.onResume();//重新啟用WebView為活躍狀態,響應網頁
webview.resumeTimers();//恢復pauseTimers狀態
super.onResume();
//當頁面被失去焦點被切換到後臺不可見狀態,需要執行onPause
//通過onPause動作通知核心暫停所有的動作,比如DOM的解析、plugin的執行、JavaScript執行。
}
//銷燬Webview
//在關閉了Activity時,如果Webview的音樂或視訊,還在播放。就必須銷燬Webview
//但是注意:webview呼叫destory時,webview仍繫結在Activity上
//這是由於自定義webview構建時傳入了該Activity的context物件
//因此需要先從父容器中移除webview,然後再銷燬webview:
rootLayout.removeView(webView);
webView.destroy();
@Override
public void onDestroy() {
if (mWebView != null) {
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}
webview快取
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,都使用快取中的資料。
快取運用:
if (NetStatusUtil.isConnected(getApplicationContext())) {
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//根據cache-control決定是否從網路上取資料。
} else {
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//沒網,則從本地獲取,即離線載入
}
//使用快取需要開啟這些webview的設定,並且設定快取路徑
webSettings.setDomStorageEnabled(true); // 開啟 DOM storage API 功能
webSettings.setDatabaseEnabled(true); //開啟 database storage API 功能
webSettings.setAppCacheEnabled(true);//開啟 Application Caches 功能
String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
webSettings.setAppCachePath(cacheDirPath); //設定 Application Caches 快取目錄
清除快取:
clearCache(true); //清除網頁訪問留下的快取,由於核心快取是全域性的因此這個方法不僅僅針對webview而是針對整個應用程式.
clearHistory () //清除當前webview訪問的歷史記錄,只會webview訪問歷史記錄裡的所有記錄除了當前訪問記錄.
clearFormData () //這個api僅僅清除自動完成填充的表單資料,並不會清除WebView儲存到本地的資料。