Android Primer——WebView 與混合開發

微信,QQ等大量軟件都內嵌了H5,不得不說是一種趨勢。Android與H5互調可讓咱們的實現混合開發,一部分原生的功能改成Html 5來開發。使用H5實現的功能可以在不升級App的狀況下動態更新,並且能夠在Android或iOS的App上同時運行,節約了成本,提升了開發效率。而原理其實就是 Java代碼 和 JavaScript 之間的調用。要實現Android與H5互調,WebView是一個很重要的控件,WebView 能夠很好地幫助咱們展現 html頁面,因此有必要先了解一下 WebView(官方文檔)。javascript

1.WebView 基礎

1.簡單加載 WebView

WebView經常使用方法 說明
loadUrl 加載網絡資源 (注意要加上網絡權限)
setWebViewClient() 設置目標網頁在WebView中顯示,而不是打開系統瀏覽器
goBack() 後退,經過重寫 onKeyDown() 實現點擊返回鍵返回上一瀏覽頁面而非退出程序
goForward() 前進
ZoomIn() 放大網頁
zoomOut() 縮小網頁

咱們能夠簡單加載一個頁面:css

webView.getSettings().setJavaScriptEnabled(true); // 設置可使用js
webView.setWebViewClient(new WebViewClient());
if(url.indexOf("http")==-1){
    url="http://"+url;
}
// 加載網絡資源(注意要加上網絡權限)
webView.loadUrl("https://www.baidu.com");
// 加載assets目錄下的test.html文件
//webView.loadUrl("file:///android_asset/test.html");

2.WebSettings 配置

1.獲取WebSettings對象html

WebSettings webSettings = webView.getSettings();

2.WebSettings經常使用設置方法java

經常使用設置方法 說明
setJavaScriptEnabled(true) 支持js
setCacheMode(WebSettings.LOAD_NO_CACHE) 設置緩存方式(LOAD_CACHE_ONLY:不使用網絡,只讀取本地緩存數據;LOAD_DEFAULT:根據cache-control決定是否從網絡上取數據;LOAD_NO_CACHE:不使用緩存,只從網絡獲取數據;LOAD_CACHE_ELSE_NETWORK:只要本地有,不管是否過時,或者no-cache,都使用緩存中的數據。)
setDomStorageEnabled(true) 開啓DOM storage API功能
setDatabasePath(cacheDirPath) 設置數據庫緩存路徑
setAppCachePath(cacheDirPath) 設置Application Caches緩存目錄
setDefaultTextEncodingName("utf-8") 設置默認編碼
setUseWideViewPort(false) 將圖片調整到適合webview的大小
setSupportZoom(true) 支持縮放
setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN) 支持內容從新佈局
supportMultipleWindows() 多窗口
setAllowFileAccess(true) 設置能夠訪問文件
setNeedInitialFocus(true) 當webview調用requestFocus時爲webview設置節點
setBuiltInZoomControls(true); 設置支持縮放
setJavaScriptCanOpenWindowsAutomatically(true) 支持經過JS打開新窗口
setLoadWithOverviewMode(true) 縮放至屏幕的大小
setLoadsImagesAutomatically(true) 支持自動加載圖片

3.WebViewClient

WebViewClient主要用來輔助WebView處理各類通知、請求等事件,經過 setWebViewClient 方法設置。WebViewClient 的回調方法以下:android

回調方法 說明
doUpdateVisitedHistory() 更新歷史記錄。
onFormResubmission() 應用程序從新請求網頁數據。
onLoadResource() 在加載頁面資源時會調用,每個資源的加載都會調用一次。
onPageStarted() 開始載入頁面調用,一般咱們能夠在這設定一個 loading 條,告訴用戶程序在等待網絡響應。
onPageFinished() 在頁面加載結束時調用,關閉 loading 條,切換程序動做。
onReceivedError() 報告錯誤信息。
onReceivedHttpAuthRequest() 獲取返回信息受權請求。
onReceivedSslError() 重寫此方法可讓webview處理https請求。
onScaleChanged() WebView發生改變時調用。
onUnhandledKeyEvent() Key事件未被加載時調用。
shouldOverrideKeyEvent() 重寫此方法纔可以處理在瀏覽器中的按鍵事件。
shouldOverrideUrlLoading() 在網頁跳轉時調用,屏蔽某些特殊的URL而不作跳轉,進行預先定義的其餘操做,通常每跳轉一次只調用一次。
shouldInterceptRequest() 在加載某個網頁的資源的時屢次調用。

1.實現對網頁中超連接的攔截:

webView.setWebViewClient(new WebViewClient(){
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if("http://www.163.com/".equals(url)) {
            view.loadUrl("https://www.baidu.com/");
        }
        // return true: 點擊H5頁面中的超連接時不會再加載,全部處理都須要在WebView中操做。
        // return false: 點擊H5頁面中的超連接時會加載,默認return false。
        return true;
    }
});

2.加載網頁時替換某個資源:

webView.setWebViewClient(new WebViewClient(){
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        WebResourceResponse response = null;
        if (url.contains("logo")) {
            try {
                // 進行圖片替換
                InputStream logo = getAssets().open("logo.png");
                response = new WebResourceResponse("image/png", "UTF-8", logo);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return response;
    }
});

3.設置開始加載網頁、加載完成、加載錯誤時處理:

webView.setWebViewClient(new WebViewClient() {
    @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 onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        super.onReceivedError(view, request, error);
        // 加載錯誤
    }
});

4.處理https請求,WebView默認是不處理https請求的:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        handler.proceed(); // 接受信任全部網站的證書  
        // handler.cancel();  // 默認操做 不處理  
        // handler.handleMessage(null); // 可作其餘處理  
    }
});

5.加快 HTML 網頁加載完成速度

默認狀況 HTML 代碼下載到 WebView 後,webkit 開始解析網頁各個節點,發現有外部樣式文件或者外部腳本文件時,會異步發起網絡請求下載文件,但若是在這以前也有解析到 image 節點,也會發起網絡請求下載相應的圖片。在網絡狀況較差的狀況下,過多的網絡請求就會形成帶寬緊張,影響到css或js文件加載完成的時間,形成頁面空白 loading 太久。解決的方法就是告訴 WebView 先不要自動加載圖片,等頁面 finish 後再發起圖片加載。web

// 1.首先在WebView初始化時添加以下代碼
if(Build.VERSION.SDK_INT >= 19) {
    // 對系統API在19以上的版本做了兼容。由於44以上系統在onPageFinished時再恢復圖片加載時,
    // 若是存在多張圖片引用的是相同的src時,會只有一個image標籤獲得加載,於是對於這樣的系統咱們就先直接加載。
    webView.getSettings().setLoadsImagesAutomatically(true);
} else {
    webView.getSettings().setLoadsImagesAutomatically(false);
}
// 2.在WebView的WebViewClient子類中重寫onPageFinished()方法添加以下代碼
@Override
public void onPageFinished(WebView view, String url) {
    if(!webView.getSettings().getLoadsImagesAutomatically()) {
        webView.getSettings().setLoadsImagesAutomatically(true);
    }
}

4.WebChromeClient

WebChromeClient 主要用來輔助 WebView 處理 Javascript 的對話框、網站圖標、網站標題以及網頁加載進度等。經過 WebView 的 setWebChromeClient() 方法設置。WebChromeClient 的回調方法以下:chrome

回調方法 說明
onProgressChanged() 監聽網頁加載進度。
onReceivedTitle() 監聽網頁標題
onReceivedIcon() 監聽網頁圖標

1.顯示頁面加載進度

在WebChromeClient子類中重寫父類的onProgressChanged函數,progress表示當前頁面加載的進度,爲1至100的整數。數據庫

webView.setWebChromeClient(new WebChromeClient() {
    @Override
    public void onProgressChanged(WebView view, int progress) {
        setTitle("Loading..." + progress + "%");
        setProgress(progress * 100);
        if (progress == 100) {
            // 加載完成
        }
    }
});

5.DownloadListener

一般 WebView 渲染的界面中含有能夠下載文件的連接,點擊該連接後,應該開始執行下載的操做並保存文件到本地中。瀏覽器

建立 DownloadListener:緩存

class MyDownloadListenter implements DownloadListener {
    @Override
    public void onDownloadStart(String url, String userAgent, 
                                String contentDisposition, String mimetype, long contentLength) {
        // 下載任務...,主要有兩種方式:1.自定義下載任務;2.調用系統的download的模塊。
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
    }
}

而後就能夠給 WebView 設置下載監聽了:

webView.setDownloadListener(new MyDownloadListenter());

2.經過 WebView 加載 HTML 代碼

WebView webView = (WebView) findViewById(R.id.webview);
StringBuilder sb = new StringBuilder();
// 拼接一段HTML代碼
sb.append("<html>");
sb.append("<head>");
sb.append("<title> Test </title>");
sb.append("</head>");
sb.append("<body>");
sb.append("<h2> Test Page </h2>");
sb.append("</body>");
sb.append("</html>");
// 使用簡單的loadData方法會致使亂碼
// webView.loadData(sb.toString(), "text/html", "utf-8");
/**
 * 加載、並顯示HTML代碼
 * baseUrl:做爲網頁輸入的網址(通常null)
 * data:須要加載的HTML代碼
 * mimeType:指定HTML代碼的MIME類型,HTML可指定爲text/html
 * encoding:指定HTML代碼的字符編碼
 * historyUrl:歷史輸入的網址(通常null)
 */
webView.loadDataWithBaseURL(null, sb.toString(), "text/html", "utf-8", null);

3.混合開發 經過 WebView 和 Javascript 交互

Android 與 H5 互調可讓咱們的實現混合開發,一部分原生的功能改成 Html 5 來開發。使用 H5 實現的功能可以在不升級App的狀況下動態更新,並且能夠在Android或iOS的App上同時運行,節約了成本,提升了開發效率。而原理其實就是 Java代碼 和 JavaScript 之間的調用。Android 能夠經過 WebView 來實現和 Javascript 的交互,在程序中調用 Javascript 代碼,只須要將WebView控件的支持 Javascript 的屬性設置爲 true 便可。下面直接上乾貨:

1.Java 調 Javascript

咱們先定義一段 Javascript 代碼:

function javaCallJs(arg){
     document.getElementById("content").innerHTML =("Hello:"+arg);
}

而後是在 Java 中調用 Javascript 中的方法:

// Java 中調用 Javascript 是經過 loadUrl() 實現的,格式:mWebView.loadUrl("javascript:showFromHtml()");
// 而且需在UI線程運行
webView.loadUrl("javascript:javaCallJs("+"'"+name+"'"+")");

以上代碼就是調用了 Javascript 中一個叫 javaCallJs(arg) 的方法,並傳入了一個 name 參數。

2.Javascript 調 Java

配置 Javascript 接口:

webSettings.setJavaScriptEnabled(true);
// 添加接口函數,jsObj 爲橋連對象
webView.addJavascriptInterface(new JSInterface(), "jsObj");

實現 Javascript 接口類:

class JSInterface {
    @JavascriptInterface
    public void showLog(String log){
        Log.i("JAVA", log);
    }
}

Javascript 中調用 Java 代碼:

<input type="button" value="點擊Android被調用" onclick="window.Android.showLog('Javascript中傳來的參數')"/>

4.WebView 開發中遇到的一些坑

1.若是想要webView在產生OOM的時候不影響主進程,能夠另開一個進程,在androidmanifest.xml的activity標籤里加上Android:process屬性就能夠了。

3.及時銷燬對象,onDestory() 中應該先從 ViewGroup 中 remove 掉 WebView,再調用webView.removeAllViews(); webview.destory();

2.在Activity被殺死以後,依然保持webView的狀態,方便用戶下次打開的時候能夠回到以前的狀態。webview支持saveState(bundle)和restoreState(bundle)方法。

相關文章
相關標籤/搜索