WebView使用詳解(三)——WebChromeClient與LoadData補充

前言:
我不會忘了我
忘了我曾說過一定會得到的夢想 ——《老大》小柯

相關文章

1、《WebView使用詳解(一)——Native與JS相互調用(附JadX反編譯)》
2、《WebView使用詳解(二)——WebViewClient與常用事件監聽》

一、WebChromeClient

1、概述

(1)、 與WebViewClient的區別

很多同學一看到這裏有Chrome,立馬就會想到google 的Chrome瀏覽器;這裏並不是指Chrome瀏覽器的意思,而是泛指瀏覽器,WebView的內部實現並不是完全使用Chrome的內核,而是部分使用Chome內核,其它都是與Chrome不相同的;
我們再來對比下WebViewClient:

  • WebViewClient:在影響View的事件到來時,會通過WebViewClient中的方法回調通知用戶
  • WebChromeClient:當影響瀏覽器的事件到來時,就會通過WebChromeClient中的方法回調通知用法。

通過上面的對比,我們發現WebViewClient和WebChromeClient都是針對不同事件的回調,而google將這些回調進行分類集合,就產生了WebViewClient、WebChromeClient這兩個大類,其中管理着針對不同類型的回調而已。

(2)、爲什麼叫WebChromeClient?

因爲WebChromeClient中集合了影響瀏覽器的事件到來時的回調方法,所以這裏更需要突出瀏覽器的概念,而Chrome則是google自家的瀏覽器名稱,所以使用WebChromeClient來做爲名稱吧,純屬臆想……

(3)、WebChromeClient的常用函數

我們先來看一下,在WebChromeClient中我們將要講解的函數,其實WebChromeClient裏的函數是非常多的,可以監控到瀏覽器的很多方面,這裏我們就不再一個個來講了,只講解常用的幾個函數,而且隨着ReactNative和Hybird的普及,WebView的使用場景會越來越少,指不定哪一天就被廢棄了

/**
 * 當網頁調用alert()來彈出alert彈出框前回調,用以攔截alert()函數
 */
public boolean onJsAlert(WebView view, String url, String message,JsResult result)
/**
 * 當網頁調用confirm()來彈出confirm彈出框前回調,用以攔截confirm()函數
 */
public boolean onJsConfirm(WebView view, String url, String message,JsResult result)
/**
 * 當網頁調用prompt()來彈出prompt彈出框前回調,用以攔截prompt()函數
 */
 public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result) 
 /**
 * 打印 console 信息
 */
 public boolean onConsoleMessage(ConsoleMessage consoleMessage)
 /**
 * 通知程序當前頁面加載進度
 */
 public void onProgressChanged(WebView view, int newProgress)

2、WebChromeClient之onJsAlert、onJsConfirm、onJsPrompt

這一小節我們把這三個函數一起看,因爲他們都是爲了處理彈出框。

(1)、爲何JS中的alert()、confirm()、prompt()無效

首先,我們來舉個例子,在網頁中加上按鈕,在點擊時分別調用alert()、confirm()、prompt()來彈出不同的對話框
web.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 id="h">歡迎光臨啓艦的blog</h1>
    <button onclick="confirm('傻叉')">confirm</button>
    <button onclick="alert('傻叉')">alert</button>
    <button onclick="prompt('傻叉')">prompt</button>
</body>
</html>

然後是Java處理代碼:(MyActivity.java)

public class MyActivity extends Activity {
    private WebView mWebView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView)findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

效果圖如下:
這裏寫圖片描述
從效果圖中,雖然啓用了JavaScript但是在網頁中的confrim()、alert()、prompt()卻是沒有效果!
這是因爲我們需要設置WebChromClient!
在程序中,我們只需要加上mWebView.setWebChromeClient(new WebChromeClient());就可以實現confrim()、alert()、prompt()的彈出效果了
html代碼不變,我們來看一下JAVA代碼:

public class MyActivity extends Activity {
    private WebView mWebView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView)findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.setWebChromeClient(new WebChromeClient());

        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

相比上面,只多了一句:mWebView.setWebChromeClient(new WebChromeClient());
現在再來看下效果圖:
這裏寫圖片描述
至於爲什麼會這樣,我也不知道,也沒仔細去研究它的源碼,記住就好了。

(2)、使用onJsAlert攔截alert()函數概述

我們先來看一下在程序中如何來做的:

public class MyActivity extends Activity {
    private WebView mWebView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView)findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Toast.makeText(MyActivity.this,"xxx",Toast.LENGTH_SHORT).show();
                result.confirm();
                return true;
            }
        });

        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

效果圖如下:
我們在重寫onJsAlert中,在onJsAlert代碼中寫了三句話:

Toast.makeText(MyActivity.this,"xxx",Toast.LENGTH_SHORT).show();
result.confirm();
return true;

這三句話,句句非常重要:
第一句:

Toast.makeText(MyActivity.this,"xxx",Toast.LENGTH_SHORT).show();

表示我們攔截html中alert函數之後,我們自己的操作,這裏是彈出一行toast
第二句:

result.confirm();

這句話非常重要,它表示向WebView通知操作結果,JsResult有兩個函數:JsResult.confirm()和JsResult.cancel(),JsResult.confirm()表示點擊了彈出框的確定按鈕,JsResult.cancel()則表示點擊了彈出框的取消按鈕。
如果沒有使用JsResult來告訴WebView處理結果,則WebView就會認爲這個彈出框還一直彈在那裏,你再點擊alert按鈕,將會無效;
第三句:

return true;

表示告訴WebView我們已經攔截了alert()函數,不需要再彈出網頁中的alert彈出框了,如果我們return false,那麼WebView就會認爲我們沒有攔截alert()函數,會繼續彈出alert對話框。

(3)、如果onJsAlert沒有使用JsResult確認結果

如果我們把result.confirm()去掉,來看一下,是不是真的像我們說的那樣再次點擊alert按鈕會失效

public class MyActivity extends Activity {
    private WebView mWebView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView)findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Toast.makeText(MyActivity.this,"xxx",Toast.LENGTH_SHORT).show();
//                result.confirm();
                return true;
            }
        });

        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

我們把上面代碼中的 result.confirm()給注掉一下,看下效果:
這裏寫圖片描述
從效果圖中可以看到,在去掉 result.confirm()以後,只有第一次有效果,後面再點擊alert按鈕就無效了(動畫中看不出來點擊效果,其實我一直在點……)。

(4)、如果onJsAlert中return false會怎樣

前面我們也講到,如果在onJsAlert中return true,則表示告訴WebView我們已經攔截了alert函數,系統不需要再彈出alert對話框了,如果return false,則表示告訴WebView我們沒有攔截alert函數,使用系統的默認處理,從WebChromeClient的源碼中可以看到onJsAlert默認是return false的。

public boolean onJsAlert(WebView view, String url, String message,JsResult result) {
    return false;
}

下面我們就來看看如何我們在彈出toast以後return false,系統是不是真的還會彈出alert對話框

public class MyActivity extends Activity {
    private WebView mWebView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView)findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Toast.makeText(MyActivity.this,"xxx",Toast.LENGTH_SHORT).show();
                result.confirm();
                return false;
            }
        });

        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

效果圖如下:
這裏寫圖片描述
從效果圖中也明顯看出了我們的結論是正確的,當return false時,不管我們前面做了什麼,依然會彈出對話框。

好了,有關onJsAlert我們總結一下:

  • 如果需要使網頁中的confrim()、alert()、prompt()函數生效,需要設置WebChromeClient!
  • 在使用onJsAlert來攔截alert對話框時,如果不需要再彈出alert對話框,一定要return true;在return false以後,會依然調用系統的默認處理來彈出對話框的
  • 如果我們return true,則需要在處理完成以後調用JsResult.confirm()或者JsResult.cancel()來告訴WebView我們點中哪個按鈕來取消程序對話框。否則再次點擊按鈕將會失敗

可能有些同學不知道confrim(),prompt()的對話框效果,下面就整體給大家演示一下html中原生的效果。
這裏寫圖片描述
有關confrim()和prompt()的攔截,我們就不再講了,與攔截alert()一樣!

3、WebChromeClient之onConsoleMessage

當html中調用console相關輸出的時候,就會通過onConsoleMessage進行通知

public boolean onConsoleMessage(ConsoleMessage consoleMessage)

參數意義:

  • ConsoleMessage consoleMessage:保存着當前消息的類型和消息內容
  • 返回值:如果返回true時,就表示攔截了console輸出,系統就不再通過console輸出出來了,如果返回false則表示沒有攔截console輸出,調用系統默認處理。

我們來看下正常情況下,console輸出的內容及用法
先來看html內容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 id="h">歡迎光臨啓艦的blog</h1>
    <button onclick="confirm('傻叉')">confirm</button>
    <button onclick="alert('傻叉')">alert</button>
    <button onclick="prompt('傻叉')">prompt</button>
    <button onclick="log()">log</button>
</body>
<script type="text/javascript">
function log(){
  console.log("console.log");
  console.warn("warnning");
  console.error("error");
}
</script>
</html>

對應的java代碼如下:

public class MyActivity extends Activity {
    private WebView mWebView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView)findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());

        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

除了alert,prompt,confirm以外,其它時候都不需要強制設置WebChromeClient
當點擊log按鈕時,會調用console的函數把log輸出出來
效果圖如下:
這裏寫圖片描述
在我們logcat中也可以看到如下日誌:
這裏寫圖片描述

示例:攔截Console,彈出消息

下面我們就重寫WebChromeClient的onConsoleMessage方法,把console消息攔截掉,然後把消息利用toast彈出來:

mWebView.setWebChromeClient(new WebChromeClient(){
    @Override
    public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
        Toast.makeText(MyActivity.this,consoleMessage.message(),Toast.LENGTH_SHORT).show();
        return  true;
    }

});

效果圖如下:
這裏寫圖片描述
由於我們return true,控制檯將不會再看到我們的消息日誌了。

4、WebChromeClient之onProgressChanged

表示當前頁面的加載速度,函數聲明如下:

public void onProgressChanged(WebView view, int newProgress)
  • WebView view:當前WebView實例
  • int newProgress:當前的加載進度,值從0到100

比如我們加載“http://blog.csdn.net/harvic880925
然後把加載進度用日誌打出來:

public class MyActivity extends Activity {
    private WebView mWebView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView)findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                Log.e("qijian","progress:"+newProgress);
                super.onProgressChanged(view, newProgress);
            }
        });

        mWebView.loadUrl("http://blog.csdn.net/harvic880925");
    }
}

日誌如下:
這裏寫圖片描述
大家一定要注意,底層實現時,是利用handler來定時輪循當前進度的,每隔一定時間查詢一次,所以每次拿到的進度數據是不一樣的,也就是說如果頁面較簡單,可能會直接返回100,而跳過中間的各個數據。也就是說,除了100,其它任何一個數值不是一定返回的,所以大家如果要用到進度除了數值100可以用等號來判斷,其它一定要用大於號或小於號,如果用了等號,可能永遠也不會執行到!

5、WebChromeClient之其它函數

WebChromeClient除了上面幾個常用函數以後,還有其它一些函數,下面就簡單列舉一下,就不再一一舉例了

/*
* 通知頁面標題變化
*/
nReceivedTitle(WebView view, String title)

/*
* 通知當前頁面網站新圖標
*/
onReceivedIcon(WebView view, Bitmap icon)

/*
* 通知主程序圖標按鈕URL
*/
onReceivedTouchIconUrl(WebView view, String url, boolean precomposed)

/*
* 通知主程序當前頁面將要顯示指定方向的View,該方法用來全屏播放視頻。
*/
public interface CustomViewCallback {
       // 通知當前頁面自定義的View被關閉
       public void onCustomViewHidden();
   }
onShowCustomView(View view, CustomViewCallback callback)

/*
* 與onShowCustomView對應,通知主程序當前頁面將要關閉Custom View
*/
onHideCustomView()

/**
 * 請求主程序創建一個新的Window,如果主程序接收請求,返回true並創建一個新的WebView來裝載Window,然後添加到View中,發送帶有創建的WebView作爲參數的resultMsg的給Target。如果主程序拒絕接收請求,則方法返回false。默認不做任何處理,返回false
 */
onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg)

/*
* 顯示當前WebView,爲當前WebView獲取焦點。
*/
onRequestFocus(WebView view)

/*
* 通知主程序關閉WebView,並從View中移除,WebCore停止任何的進行中的加載和JS功能。
*/
onCloseWindow(WebView window)

/**
 * 告訴客戶端顯示離開當前頁面的導航提示框。如果返回true,由客戶端處理確認提示框,調用合適的JsResult方法。如果返回false,則返回默認值true給javascript接受離開當前頁面的導航。默認:false。JsResult設置false,當前頁面取消導航提示,否則離開當前頁面。
 */
onJsBeforeUnload(WebView view, String url, String message, JsResult result)

/**
 *通知主程序web內容嘗試使用定位API,但是沒有相關的權限。主程序需要調用調用指定的定位權限申請的回調。更多說明查看GeolocationPermissions相關API。
 */
onGeolocationPermissionsShowPrompt(String origin,GeolocationPermissions.Callback callback)

/*
 * 通知程序有定位權限請求。如果onGeolocationPermissionsShowPrompt權限申請操作被取消,則隱藏相關的UI界面。
 */
onGeolocationPermissionsHidePrompt()

/**
*通知主程序web內容嘗試申請指定資源的權限(權限沒有授權或已拒絕),主程序必須調用PermissionRequest#grant(String[])或PermissionRequest#deny()。如果沒有覆寫該方法,默認拒絕。
*/
onPermissionRequest(PermissionRequest request)

/**
* 通知主程序相關權限被取消。任何相關UI都應該隱藏掉。
*/
onPermissionRequestCanceled(PermissionRequest request)

/**
* 通知主程序 執行的Js操作超時。客戶端決定是否中斷JavaScript繼續執行。如果客戶端返回true,JavaScript中斷執行。如果客戶端返回false,則執行繼續。注意:如果繼續執行,重置JavaScript超時計時器。如果Js下一次檢查點仍沒有結束,則再次提示。
*/
onJsTimeout()

/**
*當停止播放,Video顯示爲一張圖片。默認圖片可以通過HTML的Video的poster屬性標籤來指定。如果poster屬性不存在,則使用默認的poster。該方法允許ChromeClient提供默認圖片。
*/
getDefaultVideoPoster()

/**
* 當用戶重放視頻,在渲染第一幀前需要花費時間去緩衝足夠的數據。在緩衝期間,ChromeClient可以提供一個顯示的View。如:可以顯示一個加載動畫。
*/
getVideoLoadingProgressView()

/**
* 獲取訪問歷史Item,用於鏈接顏色。
*/
getVisitedHistory(ValueCallback callback)

/**
* 通知客戶端顯示文件選擇器。用來處理file類型的HTML標籤,響應用戶點擊選擇文件的按鈕操作。調用filePathCallback.onReceiveValue(null)並返回true取消請求操作。
* FileChooserParams參數的枚舉列表:
MODE_OPEN 打開
MODE_OPEN_MULTIPLE 選中多個文件打開
MODE_OPEN_FOLDER 打開文件夾(暫不支持)
MODE_SAVE 保存
*/
onShowFileChooser(WebView webView, ValueCallback filePathCallback,FileChooserParams fileChooserParams)

/**
* 解析文件選擇Activity返回的結果。需要和createIntent一起使用。
*/
parseResult(int resultCode, Intent data)

/**
* 創建Intent對象來啓動文件選擇器。Intent支持可訪問的簡單類型文件資源。不支持高級文件資源如live media capture媒體快照。如果需要訪問這些資源或其他高級文件類型資源可以自己創建Intent對象。
*/
createIntent()

/**
* 返回文件選擇模式
*/
getMode()

/**
* 返回可訪問MIME類型數組,如audio/*,如果沒有指定可訪問類型,數組返回爲null
*/
getAcceptTypes()

/**
* 返回優先的媒體快照類型值如Camera、Microphone。true:允許快照。false,禁止快照。使用getAcceptTypes方法確定合適的capture設備。
*/
isCaptureEnabled()

/**
* 返回文件選擇器的標題。如果爲null,使用默認名稱。
*/
getTitle()

/**
*指定默認選中的文件名或爲null
*/
getFilenameHint()

二、LoadData()與loadDataWithBaseURL()

在第一篇中,我們就已經講了通過loadUrl()來加載本地頁面和在線地址的方式,這裏給大家再補充兩個方法LoadData()與loadDataWithBaseURL(),它們不是用來加載整個頁面文件的,而是用來加載一段代碼片的。這兩個函數平時用的比較少,這裏只講基本用法,就不再深入了。
聲明方式爲:

public void loadData(String data, String mimeType, String encoding)
public void loadDataWithBaseURL(String baseUrl, String data,String mimeType, String encoding, String historyUrl)

這裏每個參數的具體意義後面再詳細講解,這裏涉及到MIME類型,我以前有篇文章講過,大家可以參考下:《 ContentProvider數據庫共享之——MIME類型與getType()》
簡單來講,MIME的類型格式是跟文件的後綴相關聯的,比如下面的幾個關聯方式:

文件後綴 MIME類型
html text/html
jpg image/jpeg
bmp image/bmp
png image/png

這裏僅涉及到網頁和圖片的類型,還有其它的文件後綴和對應的MIME類型,這裏就不再一一列舉了,有關MIME類型的具體意義大家可以參考上面的文章。

1、loadData

示例1:簡單使用

我們先來看看loadData是如何使用的,它的聲明如下:

public void loadData(String data, String mimeType, String encoding)
  • String data:代碼片段內容
  • String mimeType:代碼片段所對應的MIME類型,如果傳null,則默認爲text/html
  • String encoding:代碼片段的編碼方式

我們先舉個例子來看下:

public class MyActivity extends Activity {
    private WebView mWebView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setDefaultTextEncodingName("utf-8");


        String summary = "<html><body>You scored <b>192</b> points.</body></html>";
        mWebView.loadData(summary, "text/html", "utf-8");

    }
}

效果圖爲:
這裏寫圖片描述
這段代碼很簡單,就不再講了。

示例2:loadData的正確使用方式

在使用loadData時,在數據裏面不能出現英文字符:’#’, ‘%’, ‘\’ , ‘?’ 這四個字符,如果有的話可以用 %23, %25, %27, %3f,這些字符來替換,在平時測試時,你的數據時,你的數據裏含有這些字符,但不會出問題,當出問題時,你可以替換下。
直接使用這四個字符會造成的問題如下:

  • %:會報找不到頁面錯誤,頁面全是亂碼。
  • #,會讓你的goBack失效,但canGoBAck是可以使用的。於是就會產生返回按鈕生效,但不能返回的情況。
  • \ 和? 我在轉換時,會報錯,因爲它會把\當作轉義符來使用,如果用兩級轉義,也不生效,我是對它無語了。

我們雖然可以把代碼中的字符逐個讀取,然後給轉換掉,但運行速度上會大打折扣,因爲webview.loadData()是運行在主線程的,所以如果你的代碼段很長,那就會卡死主線程!所以Android給我們提供了一個專門用來轉碼的函數:URLEncoder.encode(String s, String charsetName) ,它能將衝突的字符進行轉義,然後再傳給webview,這樣webview在加載時就不會有衝突了,encode函數的聲明如下:

public static String encode(String s, String charsetName);
  • String s:代碼段
  • String charsetName:編碼類型

下面我們來看使用這個encode函數的例子:

public class MyActivity extends Activity {
    private WebView mWebView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setDefaultTextEncodingName("utf-8");


        try {
            String summary = "<html><body>You scored <b>192</b> points.</body></html>";
            mWebView.loadData(URLEncoder.encode(summary, "utf-8"), "text/html", "utf-8");
        } catch (Exception e) {
            Log.e("qijian", e.getMessage());
        }
    }
}

data中,有人會遇到中文亂碼問題,解決辦法:參數傳”utf-8”,頁面的編碼格式也必須是utf-8,這樣編碼統一就不會亂了。別的編碼我也沒有試過。

注意:
1、loadData()應該是不能加載圖片的,反正我是加載不出來,加載圖片的內容我們後面會使用loadDataWithBaseURL來實現。
2、爲了防止字符衝突,在傳遞loadData的數據時,必須使用URLEncoder.encode()函數來轉義
3、頁面的編碼格式必須與代碼中傳參的編碼格式一致,不然會導致亂碼

2、loadDataWithBaseURL

相比loadData,這個函數更常用,因爲loadData能實現的功能,它都能實現,而且也不會出現字符衝突。其函數聲明如下:

public void loadDataWithBaseURL(String baseUrl, String data,String mimeType, String encoding, String historyUrl)

參數意義如下:

  • String baseUrl:基準URL,不需要可以傳null,它的意思是,如果data中的url是相對地址,則就會加上基準url來拼接出完整的地址,比如baseUrl是http://img6.ph.126.net,data中有個Img標籤,它的內容是:<img src='hBiG96B8egigBULxUWcOpA==/109212290980771276.jpg'>,很明顯src的地址不是本地地址也不是在線地址,那它就是一個相對地址,所以加上baseUrl以後纔是它的完整地址:http://img6.ph.126.net/hBiG96B8egigBULxUWcOpA==/109212290980771276.jpg
  • String mimeType:MIME類型
  • String encoding:編碼方式
  • String historyUrl:當前的歷史記錄所要存儲的值。如果不需要可以傳Null,loadDataWithBaseURL它本身並不會向歷史記錄中存儲數據,要想實現歷史記錄,需要我們自己來實現;有關歷史記錄的實現方式是比較複雜的,歷史記錄是以Key/value的方式存儲在一個historyList裏的,當前進後退時,會用Key來取出對應的value值來加載進webview中。而Key就是這裏的baseUrl,Value就是這裏的historyUrl;history所指向的必須是一個頁面,並且頁面存在於SD卡中或程序中(assets);

下面我們舉個例子來看下baseUrl的概念:

示例1:baseUrl的用法

public class MyActivity extends Activity {
    private WebView mWebView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setDefaultTextEncodingName("utf-8");


        String baseURL = "http://img6.ph.126.net";
        String data = "漂亮MM <img src='hBiG96B8egigBULxUWcOpA==/109212290980771276.jpg'>";
        mWebView.loadDataWithBaseURL(baseURL, data, "text/html", "utf-8", null);
    }
}

效果圖如下:
這裏寫圖片描述

示例2:三種地址加載情況

我們再進階一下,看如果網頁地址是絕對地址,本地文件地址也是絕對地址,而另外一個是相對地址的情況下,看baseUrl是如何操作的

public class MyActivity extends Activity {
    private WebView mWebView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setDefaultTextEncodingName("utf-8");


        String baseURL = "http://img6.ph.126.net";
        String data = "絕對網頁地址:" +
                "<img src='http://img3.3lian.com/2013/v8/72/d/61.jpg'>" +
                "本地地址:" +
                "<img src='file:///android_asset/s07.jpg'>" +
                "相對地址:" +
                "<img src='hBiG96B8egigBULxUWcOpA==/109212290980771276.jpg'>";

        mWebView.loadDataWithBaseURL(baseURL, data, "text/html", "utf-8", null);

    }
}

效果圖如下:
這裏寫圖片描述
在代碼中有三種地址:第一個是絕對的http地址,第二個是通過file指定的本地地址,對於這兩類的絕對地址,baseUrl是不起作用的,而對於第三個相對地址,是會啓用baseUrl的來拼接完整地址的。

總結:

  • 面這兩種方法,我建議使用後者,雖然loadData的歷史記錄不需要我們自己來實現,但在使用時,這就兩個加載上後者比前者快一到兩倍。
  • 另外loadData不能加載圖片,而loadDataWithBaseURL是可以加載圖片的

好了,這篇就到這裏了,有關WebView系列就先到這了,下篇繼續寫自定義控件……
源碼在文章底部給出

如果本文有幫到你,記得加關注哦

源碼下載地址:http://download.csdn.net/detail/harvic880925/9540930
請大家尊重原創者版權,轉載請標明出處:http://blog.csdn.net/harvic880925/article/details/51583253 謝謝

如果你喜歡我的文章,那麼你將會更喜歡我的微信公衆號,將定期推送博主最新文章與收集乾貨分享給大家(一週一次)
這裏寫圖片描述

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