在上一篇關於WebView的文章中,介紹了 WebView 的基本使用方法、WebView 頁面處理和歷史記錄以及和 JS 調用本地代碼的相關內容。今天就在上一篇文章的基礎上,補充一些 WebView 的更深刻的東西。html
主要從以下幾點來進行補充:前端
前一篇文章中說到使用 WebView 須要開啓 Internet 的權限,這個說法實際上是不許確的。開啓權限只是由於咱們使用 loadUrl() 方法來獲取 URL 的內容時須要聯網。當咱們選擇加載本地的 HTML 頁面(好比 assets 目錄下的 HTML 文件或者使用 loadData() 方法加載一段 HTML 代碼),並不須要網絡權限。android
加載 assets 目錄下的 HTML 文件的方式和加載網頁是一致的,都是使用 WebView 的 loadUrl() 方法。web
mWebView.loadUrl("file:///android_asset/index.html");複製代碼
上篇文章在介紹 WebView 的歷史記錄時,列舉了部分相關的方法並作了簡單的描述。這部分主要補充幾個 load 方法的介紹。瀏覽器
void loadData (String data, String mimeType, String encoding)緩存
加載指定的 data 數據,有時須要加載的不是一個完整的網頁,而是一個 HTML 片斷。安全
data 表示給定編碼的 String 類型 HTML 文本。mimeType 表示 data 的 MIMIE 類型,好比 「text/html」。encoding 表示 data 的編碼格式。bash
這個方法中有兩個地方須要注意:網絡
示例以下:異步
String htmlString = "<html><title>this is title</title><body>this is web content.</body></html>";
mWebView.loadData(htmlString, "text/html","utf-8");複製代碼
void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)
這個方法比上面那個方法只多了兩個參數,一個是 baseUrl,一個是 historyUrl。baseUrl 指定了 data 數據的基準地址。咱們知道,在 HTML 代碼中一般會有超連接或者圖片,而這些連接或者圖片地址一般使用的都是相對路徑,若是沒有一個基準,WebView 就沒法訪問到這些資源。
下面咱們在 assets 目錄下模擬網站資源的相對路徑,來幫助咱們更好地理解:
assets 目錄下建立了 web 目錄,裏面有一張圖片名爲 logo.png
String htmlStr = "this is our logo:<img src="/logo.png"/>"
mWebView.loadData(htmlStr, "text/html","utf-8");
mWebView.loadDataWithBaseUrl("file:///android_asset/web",htmlstr,"text/html","utf-8",null);複製代碼
使用 loadData() 方法沒法加載圖片,只有使用 loadDataWithBaseUrl() 方法才能加載。
void loadUrl(String url)
加載指定 URL 的內容。
void loadUrl(String url, Map additionalHttpHeaders)
加載指定的 URL 的內容,並攜帶 http header 數據。
void reload()
從新加載當前頁面。頁面中全部資源會從新加載。
WebSettings getSettings()
獲取對這個 WebView 進行設置的 WebSettings 對象。
WebSettings 是管理 WebView 設置狀態的類。當首次建立 WebView 時,它會得到一組默認設置。這些默認設置能夠經過 WebSettings 的任何 getter 方法調用返回。從 WebView.getSettings() 獲取的WebSettings 對象與 WebView 的使用壽命相關。若是 WebView 已被破壞,WebSettings 上的任何方法調用都將拋出一個 IllegalStateException 異常。
上一篇文章中提到 WebView 自己不支持 JavaScript,須要經過 WebSettings 來設置,即:
mWebView.getSettings().setJavaScriptEnabled(true);複製代碼
這裏介紹其餘幾個經常使用的 WebSettings 的 setter 方法,來對 WebView 進行設置。
setCacheMode(int mode)
設置是否支持緩存及緩存模式,默認值爲 LOAD_DEFAULT。
setDefaultFontSize(int size)
設置默認的字體大小。有效值在 1~72 之間,默認值爲 16。
setSupportZoom(boolean support)
設置是否支持縮放,默認支持。
setDisplayZoomControls(boolean enabled)
設置是否顯示縮放按鈕。默認值爲 true。
在上篇文章中介紹了經過覆蓋 WebViewClient 的shouldOverrideUrlLoading() 方法來使用當前應用展現頁面,而不是經過手機瀏覽器來打開。這裏就係統地講講 WebView 和 WebViewClient、WebChromeClient 的關係以及它們各自的做用。
WebView 在加載網頁時會產生各類事件,並回調給應用程序以便在網頁加載過程進行一些額外的處理。若是全部的工做都由 WebView 自己來完成,那麼它的工做量就太大了,所以 Android 中引入了WebVIewClient 和 WebChromeClient 類來幫助 WebView 分擔這些事件處理的回調。
WebView 負責加載網頁以及網頁渲染。
WebViewClient 的主要職責是幫助 WebView 處理各類通知、回調事件。
WebChromeClient 的做用是監聽網頁加載進度以及對網頁標題,網頁圖標、JS 對話框進行處理等等。
//網頁開始加載時的回調函數
void onPageStarted(WebView view, String url, Bitmap favicon)
//網頁加載結束時的回調函數
void onPageFinished(WebView view, String url)
//網頁加載出錯時的回調函數
void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
//選擇使用應用程序進行頁面展現時須要覆蓋該方法
boolean shouldOverrideUrlLoading(WebView view, String url)複製代碼
//接收到頁面 title 時回調,獲取到 title 能夠設置到應用的 ActionBar 上。
void onReceivedTitle(WebView view, String title)
//接收到頁面的圖標時回調
void onReceivedIcon(WebView view, Bitmap icon)
//當頁面加載進度發生變化時回調,能夠設置一個 ProgressBar 來顯示加載進度
void onProgressChanged(WebView view, int newProgress)
//當頁面彈出 Javascript 警報對話框時調用
//客戶端能夠設置是否對這個對話框進行處理
boolean onJsAlert(WebView view, String url, String message, JsResult result)
//當頁面彈出 Javascript 確認對話框時調用
//客戶端能夠設置是否對這個對話框進行處理
boolean onJsConfirm(WebView view, String url, String message, JsResult result)
//當頁面彈出 Javascript 提示對話框時調用
//客戶端能夠設置是否對這個對話框進行處理
boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)複製代碼
在瀏覽網頁時常常會遇到 404 錯誤,也就是訪問的頁面不存在,這裏就簡單介紹一下如何處理 WebView 中的 404 錯誤。對錯誤碼的處理須要覆蓋 WebViewClient 類中的 onReceiveError() 方法,對於 404 錯誤,有兩個經常使用的處理方法:
第一,加載一個 assets 目錄下的寫好的 404 頁面
class MyWebViewClient extends WebViewClient{
@Override
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
view.loadUrl("file:///android_asset/404.html");
}
}
mWebView.setWebViewClient(new MyWebViewClient());複製代碼
第二,使用 Android 中的 ImageView 或者 TextVIew 來顯示錯誤信息。
TextView tvError = (TextView) findViewById(R.id.tv_error);
class MyWebViewClient extends WebViewClient{
@Override
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
mWebView.setVisibility(View.GONE);
tvError.setVisibility(View.VISIBLE);
tvError.setText("something goes wrong");
}
}
mWebView.setWebViewClient(new MyWebViewClient());複製代碼
使用 WebView 進行文件下載一樣有兩種經常使用的方法,一種是使用隱式 Intent,調用系統瀏覽器進行下載任務;一種是獲取到下載文件的 URL,建立線程進行異步下載。
咱們這裏就簡單介紹一下使用隱式 Intent 的方法來下載文件,第二種方法將在後面一篇關於 HttpUrlConnection 的文章中進行介紹。
WebView 有一個 setDownloadListener() 方法,當 URL 的內容不能被 WebView 引擎渲染時(文件),應該被下載。須要新建一個 DownloadListener 的實現類。在該實現類的 onDownloadStart() 方法中,能夠獲取到當前下載文件的 URL。以後就能夠經過隱式 Intent 來調用系統瀏覽器進行下載。
class MyDownloadListener implements DownloadListener{
@Override
public void onDownloadStart(String url, String userAgent,
String contentDisposition,
String mimetype, long contentLength) {
if(url.endsWith(".apk")){
Uri uri = Uri.parse(url);
Intent i = new Intent(Intent.ACTION_VIEW, uri);
startActivity(i);
}
}
}
mWebView.loadUrl("http://www.wandoujia.com/");
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setDownloadListener(new MyDownloadListener());複製代碼
上述代碼實現了在豌豆莢網站中下載 apk 文件的效果。
上篇文章中講到了在 Android 4.2 版本以前使用 addJavascriptInterface() 方法會存在安全隱患,攻擊者能夠經過反射機制來對客戶端進行攻擊。那麼在 4.2 以前,這個漏洞有沒有什麼解決方案呢?
答案是有的,在網上看了一些資料,找到了對應的方案。在上面的 WebChromeClient 的方法介紹時提到了一個 onJsPrompt() 方法,這個方法在 JS 調用 prompt 方法時會在本地回調。經過這個方法,JS 能把信息(文本)傳遞到 Java,而 Java 也能把信息(文本)傳遞到 JS 中。客戶端和網頁前端的開發者之間協商好一個小型的協議,經過 onJsPrompt() 將遠程調用所需的信息按照協議封裝成文本發給客戶端,客戶端根據協議解析這段文本,提取出所需的信息,利用反射機制進行本地的方法調用,若是有返回值就將返回值經過onJsPrompt() 傳遞給 JS。就可以實現 JS 遠程調用 Java 代碼了。
這樣的解決方案我也只是只知其一;不知其二,因此只能介紹到這裏,在參考資料中會有更加詳細的介紹。
這篇文章結束後,對於 WebView 的一些常見的方法和這些方法背後的原理都略做介紹。因爲是在學習階段,不少知識和原理並不能作到多麼深刻,可是經過寫這兩篇關於 WebView 的文章,去看了不少的博客,研究了一番官方文檔,收穫仍是很是大的。接下來就要去學習 HttpUrlConnection 的相關用法,下篇文章見。
如下是在學習過程當中看的一些博客,不斷向這些做者學習,努力深刻知識點,而後寫出儘可能高質量的博客。
blog.csdn.net/leehong2005…
Android WebView 的 Js 對象注入漏洞解決方案
blog.csdn.net/typename/ar…
blog.csdn.net/typename/ar…
blog.csdn.net/typename/ar…
Android WebView 開發詳解(共3篇)
www.jianshu.com/p/93cea79a2…JS 與 WebView 交互存在的一些問題