WebView與JS的那些事:入門篇

webview應該是開發人員最常接觸的控件了,加載一個頁面的時候,webview.loadUrl(url)就完事了,我遇到這麼玩webview的一般都是在界面顯示一些應用說明或是版本信息的時候比較常見,但是,這樣根本發揮不了webview的潛能,接下來,我會出幾篇比較好玩的文章,帶大家爽一爽,今天這一篇或許對有些基礎的人並不感冒,但可以看看後面的文章,會給你們帶來驚喜的。


初探我會跟着官網的API來分析,讓大家瞭解瞭解這些是拿來幹什麼的。

Basic usage(基本用法)

對於打開一個url我們可能會有兩種方法,一個是通過外部瀏覽器去打開,另一種則是通過自己的應用的webview去打開,官網也給出了兩種用法。

通過外部瀏覽器打開

 Uri uri = Uri.parse("http://www.example.com");
 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
 startActivity(intent);

通過內部webview打開

 WebView webview = new WebView(this);
 setContentView(webview);
 webview.loadUrl("http://slashdot.org/");


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

customization points(定製)

對於上面的webview的基本用法我們已經知道了,接下來,我們看一些定製webview需要了解哪些東西。

(一)WebChromeClient

官網解釋:This class is called when something that might impact a browser UI happens,for instance, progress updates and JavaScript alerts are sent here
大概意思是,這個類能做一些對界面的渲染效果,比如加載webview的進度更新或是js的對話框

(二)WebViewClient

官網解釋:It will be called when things happen that impact the rendering of the content, eg, errors or form submissions. You can also intercept URL loading here
大概意思就是,當webview加載的時候,這個類有很多的方法會被回調,比如webview的開始加載,加載錯誤,加載完成等回調處理,關鍵看後面這一句,你也可以攔截url的加載,這句話很關鍵,後面會用上,這個攔截需要依賴這個類的一個方法—shouldOverrideUrlLoading()

(三)WebSettings

官網解釋:Modifying the WebSettings, such as enabling JavaScript with setJavaScriptEnabled()
這個類主要是對於webview進行一些設置,比如是否允許加載js等,這個也是我們比較常用的。

(四)addJavascriptInterface(Object, String)

官網解釋:Injecting Java objects into the WebView using the addJavascriptInterface(Object, String) method. This method allows you to inject Java objects into a page’s JavaScript context, so that they can be accessed by JavaScript in the page.
這個類是重中之重,他發揮了webview的特性,他就好比是網頁與原生溝通的一個橋樑,網頁中的js能調用android內的控件,android能通過js去處理網頁,就像官網的解釋那樣,這個方法允許你注入java對象實現js的上下文

使用

上面介紹的差不多了,接下來,我們要學會如何去使用他,我們先從上面的介紹一步一步的開始

WebChromeClient的使用

我們見過很多瀏覽器的效果,在加載網頁的時候,頭部有個進度條一直跟着顯示加載進度,該實現方式就是通過如下的代碼實現的,我們可以在webview的頭部添加一個progressbar控件的橫向樣式,設置max最大值爲100,因爲WebChromeClient的onProgressChanged方法回調的progress加載完成的時候也是100。

webview.setWebChromeClient(new WebChromeClient() {
            public void onProgressChanged(WebView view, int progress) {
                 progressBar.setProgress(progress);
                 Log.i(TAG,"--->"+progress);
            }
 });

如圖

這裏寫圖片描述

WebViewClient的使用

該方法就好比是webview的一個生命週期,有網頁加載開始回調,加載失敗回調,加載成功回調。然而,僅僅就這三個方法,卻可以幫我們完成很多很多的事情。

  webView.setWebViewClient(new WebViewClient() {

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {

                return true;
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                Log.i(TAG, "-------->網頁加載開始");
            }

            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { {

                Log.i(TAG, "-------->網頁加載錯誤");
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                  Log.i(TAG, "------>網頁加載完成");
            }
        });

根據方法名字我們就知道其中的意思了,我相信,在這樣的一個週期當中,很多開發者都有這樣的需求。
網頁加載失敗或是沒有網絡的時候,我們爲了不想讓用戶看到“找不到網頁”這樣的頁面,我們習慣自己定製加載失敗的頁面去告知用戶,然後點擊重新加載,繼續加載。這樣符合用戶的體驗,這時候,這個週期就非常的符合要求了。

注意:我們要知道一點的就是,無論webview加載成功還是加載失敗,最後一個觸發的都是加載完成的回調,所以,我們在處理加載失敗頁面的時候,需要在onReceivedError設置一個標誌位,告訴onPageFinished剛剛加載的是一個錯誤的頁面。

用法:我們可以在根佈局RelativeLayout下創建兩個佈局,設置加載失敗頁面爲gone,設置webview也爲gone,progressbar設置爲visible,我們在loadUrl加載頁面的時候,我們在onPageStarted去初始化狀態,比如,設置當前是否是錯誤頁面flag=false,設置webview爲gone,設置錯誤頁面爲gone,然後在onReceivedError裏面只需要設置當前頁面是錯誤頁面flag=true,最後,我們在onPageFinished加載完成的時候去做個判斷,如果flag爲false表示加載成功,這時候我們設置webview爲visible,如果flag爲ture表示加載錯誤,我們就設置錯誤頁面爲visible,webview爲gone,最後設置progressBar爲gone,然後給錯誤頁面設置一個點擊事件,點擊該按鈕就是重新加載,這樣,一個體驗不錯的小功能就出來了。

圖:該處我把上面的progressbar也設置了一下,在加載完成的時候設置爲gone,在開始加載的時候visible。我也把加載過程的生命週期也Toast出來了,方便查看

這裏寫圖片描述

對了,還有一個方法沒有說

public boolean shouldOverrideUrlLoading(WebView view, String url)

官網解釋:return true means the host application handles the url, while return false means the current WebView handles the url

這個方法還是很有意思,他可以做到對頁面的url攔截,現在方法內什麼都不寫,如果return返回了true,就交給手機的應用去處理這個url,親測的時候,當返回true的時候,頁面的鏈接點擊是沒有效果的,如果返回false,url直接在webview進行加載,
但是,我又遇到一個好玩的。我們在該方法內使用 view.loadUrl(url);繼續加載這個鏈接,這時候,無論是設置true還是false,頁面都會在webview進行加載,所以,感覺這個方法有點雞肋啊,怪不得這個方法現在加上了刪除線,不推薦使用了。

  @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url)   {
                view.loadUrl(url);
                return true;
            }

WebSettings

該類就是輔助webview的一些設置,比如有

         WebSettings seting = webView.getSettings();
        //設置加載網頁的js可用,這個設置對後面要講到的js與android交互的時候會使用到
        seting.setJavaScriptEnabled(true);
        // 設置允許JS彈窗
        seting.setJavaScriptCanOpenWindowsAutomatically(true);
        // 防止中文亂碼
        seting.setDefaultTextEncodingName("UTF-8");
        // 設置可以支持縮放
       seting.setSupportZoom(true);
        // 設置緩存是否可用
        seting.setAppCacheEnabled(true);
        //設置webview的緩存
        seting.setCacheMode(WebSettings.LOAD_NO_CACHE);
        // 設置出現縮放工具
        seting.setBuiltInZoomControls(false);
          // 自適應屏幕seting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);

addJavascriptInterface

該方法纔是webview最好玩的的地方,如下使用

seting.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JSObject(), “jsAndroid”);

該方法首先得設置能加載js才能使用,addJavascriptInterface有兩個方法,一個是對象,這個對象裏面設置了好多以@JavascriptInterface爲註解的方法,目的是爲js提供調用原生的入口,第二個參數就好比是new一個對象的變量,就相當於JSObject js=new JSObject(),第二個參數就好比是那個js對象 。我們來看看官網給我們的例子

class JsObject {
    @JavascriptInterface
    public String toString() { return "injectedObject"; }
 }
 webView.addJavascriptInterface(new JsObject(), "injectedObject");
 //添加網頁內容
 webView.loadData("", "text/html", null);
 //添加js代碼
 webView.loadUrl("javascript:alert(injectedObject.toString())");

上面的demo主要目的是通過js拿android的數據。

如圖:
這裏寫圖片描述

爲了更好的演示js與webview的交互,我還是寫個網頁出來。

Html頁面代碼

<!DOCTYPE html>
<html>
<head>

    <script type="text/javascript">
        function javaToJs() {
            document.getElementById("main").innerHTML = "<br\>java調用了js的無參函數";
        }
        function javaToJsValue(arg) {
            document.getElementById("main").innerHTML = ("<br\>java調用了js的有參數函數--->" + arg);
        }
    </script>
</head>
<body>
<h1 id="main">webview與js交互</h1>
<input type="button" value="調用java代碼 無參函數" onclick="window.jsAndroid.setValue()">
<input type="button" value="調用java代碼 帶參函數" onclick="window.jsAndroid.setValue('我是被js帶過來的')">
</body>
</html>

java代碼

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initWeb();
        initSetting();
         webView.addJavascriptInterface(new JSObject(), "jsAndroid");
        webView.loadUrl("http://192.168.7.248/web.html");
     }
 private void initWeb() {
        webView = (WebView) findViewById(R.id.webview);
     }
   private void initSetting() {
        seting = webView.getSettings();
        seting.setJavaScriptEnabled(true);
        // 設置允許JS彈窗
        seting.setJavaScriptCanOpenWindowsAutomatically(true);
        //防止中文亂碼
        seting.setDefaultTextEncodingName("UTF-8");
        //設置webview的緩存
        seting.setCacheMode(WebSettings.LOAD_NO_CACHE);
    }
 //button無參的點擊事件
    public void jstoAndroid(View v){
        webView.loadUrl("javascript:javaToJs()");
    }
    //button帶參的點擊事件
    public void jstoAndroidValue(View v){
        webView.loadUrl("javascript:javaToJsValue('hello')");
    }

  class JSObject {

        @JavascriptInterface
        public void setValue(){
            Toast.makeText(MainActivity.this, "js調用了java代碼 無參函數", Toast.LENGTH_SHORT).show();
        }
        @JavascriptInterface
        public void setValue(String str){
            Toast.makeText(MainActivity.this, "js調用了java代碼 有參函數,c傳遞的數據是---->"+str, Toast.LENGTH_SHORT).show();
        }

    }

結果顯示如圖:

這裏寫圖片描述

好了,講了差不多了,此處就不提供源碼了,這篇主要提供思路,下一篇纔是精彩。

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