Android 使用WebView

概述:

如果一個 APP需要訪問Web, 我們可以使用WebView. WebView類是Android的View類的子類, 它讓我們可以以activity的layout形式顯示網頁. 它不包括一個完整開發的web瀏覽器的任何功能, 比如導航控制, 或者地址欄. 所有WebView做的事情, 默認情況下就只是顯示一個網頁. 

一個常用的使用WebView的場景就是當我們想要在APP內提供更新相關信息的時候, 比如一個最終用戶同意(同意xx協議)或者一個用戶嚮導. 在Android APP內, 我們可以創建一個Activity包含一個WebView, 然後用它來顯示我們的在線文檔. 另一個使用WebView的場景就是如果我們的APP需要提供數據給用戶並總是需要網絡連接來獲取數據的時候, 比如Email. 在這種情況下我們可能發現在Android APP中使用WebView來顯示所有的用戶數據比執行一個網絡請求然後解析數據並顯示在layout中更加簡單. 下面的小節將會介紹如何使用WebView實現額外的功能, 比如處理頁面導航和支持網頁中的JavaScript.

爲APP添加一個WebView:

想要向APP中添加一個WebView, 只要在Activity的layout中包含一個<WebView>標籤就可以了. 栗子:

<?xml version="1.0" encoding="utf-8"?>
<WebView  xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/>

想要在WebView中加載一個網頁的話, 使用loadUrl()方法, 栗子:

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");

在這些生效之前, 我們的APP必須擁有對網絡的訪問權限. 只需要這樣就OK了:

<manifest ... >
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

如果想要WebView顯示一個網頁, 這就是所有我們需要做的了.

在WebView中使用JavaScript:

如果WebView即將加載的網頁使用了JavaScript, 我們必須爲WebView啓用JavaScript. 啓用之後, 我們就可以在APP和JavaScript代碼之間創建接口了.

啓用JavaScript:

JavaScript在WebView中默認是禁用的. 我們可以通過設置WebView中的WebSettings來啓用它. 要獲取WebSettings需要使用getSettings()方法, 然後用setJavaScriptEnabled()啓用JavaScript.栗子:

WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);

WebSettings提供了對多種設置項的訪問. 比如可以使用setUserAgentString()來設置用戶代理, 然後在網頁中查詢自定義用戶代理來識別客戶端是不是我們真正的APP, 還是其它的什麼東西.

綁定JavaScript代碼到Android代碼:

當開發一個web app特別是WebView的時候, 我們可以在JavaScript代碼和客戶端Android代碼之間創建接口. 比如, JavaScript代碼可以調用一個Android代碼中的方法來電視一個Dialog, 而不是使用JavaScript的alert()方法. 要在JavaScript和Android代碼之間綁定一個新的接口, 需要調用addJavascriptInterface()方法, 並傳入一個類實例來綁定到JavaScript,還有一個參數就是JavaScript可以調用的接口的名字. 比如, 我們可以包含這些類到Android APP中:

public class WebAppInterface {
    Context mContext;

    /** Instantiatethe interface and set the context */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toastfrom the web page */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

注意: 如果已經設置了targetSdkVersion爲17或者更高, 我們必須添加@JavascriptInterface註解到任何想要在JavaScript中可用的方法前面, 該方法也必須爲public. 如果不這麼做, 那麼在Android4.2及更高版本中網頁就無法訪問該方法.

在上面的栗子中, WebAppInterface類讓網頁可以通過showToast()方法來創建一個Toast消息. 我們可以使用addJavascriptInterface()綁定該類到JavaScript, 並將其命名爲Android,栗子:

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

這爲WebView中運行的JavaScript創建了一個叫做Android的接口. 此刻web app便擁有了訪問WebAppInterface類的權限. 慄如, 這是一些HTML和使用showToast()方法的JavaScript代碼:

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>

並不需要從JavaScript初始化Android接口. WebView將會自動使其對網頁可用. 所以, 在點擊button之後, showAndroidToast()方法使用Android接口來調用WebAppInterface.showToast()方法.

提醒: 綁定到JavaScript的對象將會運行在其它線程中而不是在構造它的線程中.

注意: 使用addJavascriptInterface()可以讓JavaScript控制我們的APP. 這能提供很多便利, 提供強大的功能, 也可以引起危險的安全問題.當在WebView中的HTML不值得信任的時候(比如一部分或者全部的HTML由未知的對象提供的), 可以執行代碼的HTML完全可以發起一次攻擊. 正因爲這樣, 除非所有顯示在WebView中的HTML和JavaScript都是我們自己寫的, 否則不應該使用addJavascriptInterface(). 同理也應該阻止用戶通過WebView導航到其它不是自己的網站的頁面去. (默認情況下應該允許用戶使用默認的系統瀏覽器訪問外部網站).

處理頁面導航:

當用戶在WebView中點擊一個連接的時候, Android的默認行爲是加載一個APP來處理URL. 通常默認的網頁瀏覽器會打開並加載目標地址. 但是我們可以爲WebView重寫這個行爲, 讓連接在WebView內部打開. 然後可以在WebView內部通過瀏覽記錄來控制向前向後的導航. 要打開用戶點擊的連接, 只需要簡單的使用setWebViewClient()向WebView提供一個WebViewClient即可, 栗子:

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());

這就是所有的代碼了, 現在所有WebView內部的連接將會在WebView中打開. 如果想要更多的控制, 那麼創建自己的WebViewClient並重寫shouldOverrideUrlLoading()方法, 慄如:

private class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (Uri.parse(url).getHost().equals("www.example.com")) {
            // This is my web site, so do not override; let my WebView load the page
            return false;
        }
        // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        startActivity(intent);
        return true;
    }
}

然後爲WebView創建一個新的WebViewClient的實例:

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());

現在當用戶點擊一個連接, 系統將會調用shouldOverrideUrlLoading(), 它會檢查URL的域名是否滿足指定的域名(就像上面定義的). 如果匹配了, 就返回false不重新加載URL(正常處理). 如果URL的host不匹配, 那麼會創建一個新的intent,並啓動默認的Activity來處理URL(使用用戶默認的web瀏覽器).

導航網頁歷史:

當我們的WebView重寫了URL加載, 它會自動累積訪問歷史. 我們可以通過goBack()和goForward()方法來在訪問歷史中執行向前或者向後操作. 慄如, 這裏是Activity中使用設備的返回按鈕實現向後導航的操作:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // Check if the key event was the Back button and if there's history
    if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
        myWebView.goBack();
        return true;
    }
    // If it wasn't the Back key or there's no web page history, bubble up to the default
    // system behavior (probably exit the activity)
    return super.onKeyDown(keyCode, event);
}

如果有訪問歷史可以用, 那麼canGoBack()方法會返回true. 同樣我們可以使用canGoForward()方法來檢查是否可以向前. 如果不執行這個檢查, 那麼一旦用戶到達了歷史記錄的盡頭, goBack()和goForward()方法將會什麼也不做.

 

參考: https://developer.android.com/guide/webapps/webview.html

發佈了81 篇原創文章 · 獲贊 4 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章