概述:
如果一個 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