1. 程式人生 > >android webview一篇文章全面瞭解(基本使用,url攔截,js跟java互動)

android webview一篇文章全面瞭解(基本使用,url攔截,js跟java互動)

1.前言

最近幾年混合應用越來越流行,及一部分功能用原生程式碼開發,一部分功能用html5實現。那什麼時候用原生什麼時候用網頁呢?很多人第一反應就是經常變化的頁面用網頁開發,避免經常發包,不全對。其實因為網頁使用體驗遠遠不及原生開發,所以一般有以下兩種情況建議使用網頁代替原生:
1.試水功能
2.類似雙11主會場,這類只在固定時間內使用的功能。

2.基本使用方法

1)xml佈局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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" android:orientation="vertical">
<TextView android:id="@+id/title_name" android:layout_width="match_parent" android:layout_height="44dp"
android:gravity="center" android:background="#987654" android:text="title"/>
<ProgressBar android:id="@+id/webview_progressbar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="fill_parent" android:layout_height="2dp"
/>
<WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent"></WebView> </LinearLayout>

2)利用WebSettings設定一些頁面屬性,比如,頁面字型的大小,是否支援js,支援縮小放大,支援本地儲存,支援快取等。

public static void initWebSettings( WebView webView) {
        WebSettings webSettings = webView.getSettings();
        webSettings.setDefaultTextEncodingName("UTF-8");//設定預設為utf-8
        webSettings.setTextZoom(100);//設定WebView中載入頁面字型變焦百分比,預設100
        //屬性可以讓webview只顯示一列,也就是自適應頁面大小,不能左右滑動
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
        } else {
            webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
        }

        //設定此屬性,可任意比例縮放
        webSettings.setUseWideViewPort(false);
        webSettings.setLoadWithOverviewMode(true);

        //頁面支援縮放
        webSettings.setBuiltInZoomControls(false);
        webSettings.setSupportZoom(false);
        webSettings.setDisplayZoomControls(false);
        //設定支援js
        webSettings.setJavaScriptEnabled(true);
        webSettings.setSavePassword(false);
        //設定 快取模式
        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        // 開啟 DOM storage API 功能
        webSettings.setDomStorageEnabled(true);

        webView.setVerticalScrollBarEnabled(false);
        webView.setVerticalScrollbarOverlay(false);
        webView.setHorizontalScrollBarEnabled(false);
        webView.setHorizontalScrollbarOverlay(false);

    }

3)載入內容
(1)載入assets目錄下的本地網頁
一般我們都是把html檔案放在assets目錄下, WebView呼叫assets目錄下的本地網頁和圖片等資源非常方便,如下程式碼所示:

webView.loadUrl("file:///android_asset/html/intermodulation.html");

(2)載入遠端網頁

webView.loadUrl("http://www.baidu.com/");

(3)使用 LoadData 或者 loadDataWithBaseURL方法載入內容
有時候我們的webview可能只是html片段,而不是一個完整的網頁,事實上絕大多數時候都是如此,完整的網頁無需做成應用,而直接在瀏覽器訪問。這種情況我們使用 LoadData 或者 loadDataWithBaseURL方法,後者用的最多:

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

loadDataWithBaseURL()比loadData()多兩個引數,可以指定HTML程式碼片段中相關資源的相對根路徑,也可以指定歷史Url,其餘三個引數相同。

這裡主要注意引數baseUrl,baseUrl指定了你的data引數中資料是以什麼地址為基準的,因為data中的資料可能會有超連結或者是image元素,而很多網站的地址都是用的相對路徑,如果沒有baseUrl,webview將訪問不到這些資源。如下所示:

String body ="示例:這裡有個img標籤,地址是相對路徑<img src='/uploads/allimg/130923/1FP02V7-0.png' />";
mWebView.loadDataWithBaseURL("http://baidu.com", body, "text/html", "utf-8",null);

如果baseUrl沒有指定為http://baidu.com,那麼這張圖片將顯示不出來。

到這裡,基本的webview功能已經可以使用了。

3.android應用中攔截js點選跳轉,替換成跳轉到原生介面。

實際專案中,可能會顯示網頁標題,需要展示載入進度,或者當點選網頁中一個按鈕或者一個商品,需要跳轉到原生介面,這個時候就需要用到兩個方法:
WebViewClient主要用來攔截網頁中的請求,開始,結束請求等操作。

webView.setWebViewClient(new WebViewClient() {

            //返回值:true 不會顯示網頁資源,需要等待你的處理,false 就認為系統沒有做處理,會顯示網頁資源
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //當url裡面包含webview欄位的時候,則跳轉到ShowActivity原生頁面,否則還是繼續顯示網頁
                //比如:在百度輸入框裡面輸入webview在點選搜尋,再點選任何有webview欄位的連結,
                //則不繼續顯示網頁,而是跳轉到自己定義的原生頁面
                if (!TextUtils.isEmpty(url)
                        && url.contains("webview")) {
                    Intent intent = new Intent(ClickInterceptionActivity.this, ShowActivity.class);
                    intent.putExtra("url", url);
                    startActivity(intent);
                    return true;
                }
                return false;
            }

            //在頁面開始載入時候做一些操作,比如展示進度條
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                webview_progressbar.setVisibility(View.VISIBLE);
                super.onPageStarted(view, url, favicon);
            }
            //在頁面載入完成的時候做一些操作,比如隱藏進度條
            @Override
            public void onPageFinished(WebView view, String url) {
                webview_progressbar.setVisibility(View.GONE);
                super.onPageFinished(view, url);
            }
        });

WebChromeClient主要輔助WebView處理JavaScript的對話方塊、網站圖示、網站title、載入進度等。

 webView.setWebChromeClient(new WebChromeClient(){
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                webview_progressbar.setProgress(newProgress);
                super.onProgressChanged(view, newProgress);
            }

            @Override
            public void onReceivedTitle(WebView view, String title) {
                title_name.setText(title);
                super.onReceivedTitle(view, title);
            }

            @Override
            public void onReceivedIcon(WebView view, Bitmap icon) {
                super.onReceivedIcon(view, icon);
            }

        });

效果如下所示:帶有載入進度和標題
這裡寫圖片描述
當在輸入框中webview,並點選【百度一下】,正常情況會進入搜尋結果網頁,由於我們重寫了shouldOverrideUrlLoading方法,對url實現了攔截,則跳轉到原生頁面。
這裡寫圖片描述
這裡寫圖片描述

4.js和Java的互動

除了上面的簡單展示,很多專案中還會有js跟java的雙向互動。

1)js呼叫android原生方法

1.addJavascriptInterface

webView.addJavascriptInterface(new clickOnJS(), "click");

2.在android中定義待呼叫方法:

 class clickOnJS {
        @JavascriptInterface
        public void OnClick() {
            Toast.makeText(IntermodulationActivity.this, "呼叫java成功", Toast.LENGTH_SHORT).show();
        }

    }

3.js定義方法去呼叫java方法。

$(function(){
      $('.payment').click(function(){
            window.click.OnClick();
        });

    });

效果如下圖所示:點選【js呼叫java】按鈕,則彈出toast,證明成功呼叫java原生方法。
這裡寫圖片描述

2)android呼叫js方法
當點選android頁面上某個按鈕的時候,改變js頁面的內容,其實就是android原生給js傳值。
1.點選標題,則呼叫js方法

title_name.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //呼叫js方法
                webView.loadUrl("javascript:setcontent(2)");
            }
        });

2.js程式碼實現,修改cr的值

function setcontent(content){
          $('.num ,.cr').text(content);
        }

效果如下圖所示:點選標題,則呼叫js的setcontent方法,【待修改點】變成【2】,則證明成功呼叫java原生方法。
這裡寫圖片描述
這裡寫圖片描述

5.部分原始碼

1)攔截js點選跳轉關鍵程式碼類:

public class ClickInterceptionActivity extends Activity {

    private TextView title_name;

    private ProgressBar webview_progressbar;

    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_click_interception);

        initView();
        initWebViewSettings();
    }


    /**
     * 初始化佈局元件
     */
    private void initView() {
        title_name = (TextView) findViewById(R.id.title_name);
        webview_progressbar = (ProgressBar) findViewById(R.id.webview_progressbar);
        webView = (WebView) findViewById(R.id.webview);

    }

    /**
     * 初始化webview配置
     */
    private void initWebViewSettings() {
        WebViewSettings.initWebSettings(webView);
        webView.setWebViewClient(new WebViewClient() {

            //返回值:true 不會顯示網頁資源,需要等待你的處理,false 就認為系統沒有做處理,會顯示網頁資源
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //當url裡面包含webview欄位的時候,則跳轉到ShowActivity原生頁面,否則還是繼續顯示網頁
                //比如:在百度輸入框裡面輸入webview在點選搜尋,再點選任何有webview欄位的連結,
                //則不繼續顯示網頁,而是跳轉到自己定義的原生頁面
                if (!TextUtils.isEmpty(url)
                        && url.contains("webview")) {
                    Intent intent = new Intent(ClickInterceptionActivity.this, ShowActivity.class);
                    intent.putExtra("url", url);
                    startActivity(intent);
                    finish();
                    return true;
                }
                return false;
            }

            //在頁面開始載入時候做一些操作,比如展示進度條
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                webview_progressbar.setVisibility(View.VISIBLE);
                super.onPageStarted(view, url, favicon);
            }
            //在頁面載入完成的時候做一些操作,比如隱藏進度條
            @Override
            public void onPageFinished(WebView view, String url) {
                webview_progressbar.setVisibility(View.GONE);
                super.onPageFinished(view, url);
            }
        });
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                webview_progressbar.setProgress(newProgress);
                super.onProgressChanged(view, newProgress);
            }

            @Override
            public void onReceivedTitle(WebView view, String title) {
                title_name.setText(title);
                super.onReceivedTitle(view, title);
            }

            @Override
            public void onReceivedIcon(WebView view, Bitmap icon) {
                super.onReceivedIcon(view, icon);
            }

        });
        webView.loadUrl("http://www.baidu.com/");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            webView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

2)js跟java互動關鍵類:

public class IntermodulationActivity extends Activity {

    private TextView title_name;

    private ProgressBar webview_progressbar;

    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.intermodulation);

        initView();
        initWebViewSettings();
    }


    /**
     * 初始化佈局元件
     */
    private void initView() {
        title_name = (TextView) findViewById(R.id.title_name);
        webview_progressbar = (ProgressBar) findViewById(R.id.webview_progressbar);
        webView = (WebView) findViewById(R.id.webview);

        title_name.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //呼叫js方法
                webView.loadUrl("javascript:setcontent(2)");
            }
        });
    }

    /**
     * 初始化webview配置
     */
    private void initWebViewSettings() {
        WebViewSettings.initWebSettings(webView);
        webView.addJavascriptInterface(new clickOnJS(), "click");
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (!TextUtils.isEmpty(url)
                        && url.contains("webview")) {
                    Intent intent = new Intent(IntermodulationActivity.this, ShowActivity.class);
                    intent.putExtra("url", url);
                    startActivity(intent);
                }
                return false;
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                webview_progressbar.setVisibility(View.VISIBLE);
                super.onPageStarted(view, url, favicon);
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                webview_progressbar.setVisibility(View.GONE);
            }
        });
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                webview_progressbar.setProgress(newProgress);
                super.onProgressChanged(view, newProgress);
            }

            @Override
            public void onReceivedTitle(WebView view, String title) {
                title_name.setText(title);
                super.onReceivedTitle(view, title);
            }

            @Override
            public void onReceivedIcon(WebView view, Bitmap icon) {
                super.onReceivedIcon(view, icon);
            }

        });
        webView.loadUrl("file:///android_asset/html/intermodulation.html");
    }

    class clickOnJS {
        @JavascriptInterface
        public void OnClick() {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Toast.makeText(IntermodulationActivity.this, "呼叫java成功", Toast.LENGTH_SHORT).show();
        }

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            webView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

3)js實現類:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;"
          name="viewport"/>
    <title>js和java互動(點選,點選)</title>
    <link href="images/styles.css" rel="stylesheet" type="text/css">
    <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
</head>

<body class="mbg1">

<div class="paybox pay2box">java修改js==============     <span class="cr">待修改點</span></div>

<span class="payment"><a href="#">js呼叫java</a></span>
<script>

    $(function(){
      $('.payment').click(function(){
            window.click.OnClick();
        });

    });
     function setcontent(content){
          $('.num ,.cr').text(content);
        }

</script>
</body>
</html>

6.demo下載地址: