[原文鏈接地址](https://developer.android.com/guide/webapps/webview.html)
# 在WebView中構(gòu)建網(wǎng)絡(luò)應(yīng)用
*如果你想在你的客戶端應(yīng)用上引入一個Web應(yīng)用(僅僅是一個Web頁)裙椭,你就可以使用WebView睦擂。WebView是一個允許你在你的Activity布局中展示W(wǎng)eb頁面的View類的實現(xiàn)類晦毙。它不包括一個完全開發(fā)的瀏覽器的任何功能,如導(dǎo)航欄或地址欄。WebView所做的于未,僅僅是顯示一個Web頁面.*
一個更加常見的使用WebView的場景是當(dāng)你想要在你的應(yīng)用中提供一些信息,而這些信息很可能需要更新時而使用WebView喘落。就像用戶協(xié)議和用戶指南等做盅。在你的應(yīng)用中,你可以創(chuàng)建一個包含WebView的Activity分扎,利用它來展示你的在線文檔澄成。
另一個WebView可能很有用的場景就是 你的應(yīng)用需要對用戶提供一些數(shù)據(jù),而這些數(shù)據(jù)需要你經(jīng)常性的訪問網(wǎng)絡(luò)來獲得畏吓,就像email一樣墨状。在這種情況中,你會發(fā)現(xiàn)相比發(fā)送一個網(wǎng)絡(luò)請求菲饼,然后解析其中的數(shù)據(jù)最后將他們展示在你的布局中來說歉胶,使用一個web 頁來展示用戶數(shù)據(jù)時十分簡單的。進(jìn)而巴粪,你可以專門為Android設(shè)備設(shè)計一個web頁,然后通過WebView在你的Android應(yīng)用中加載這個頁面來實現(xiàn)粥谬。
這篇文章向你展示了如何啟用一個WebView肛根,如何做一些額外的事情,就像處理界面導(dǎo)航漏策,從Web頁綁定JavaScript到Android應(yīng)用的客戶端代碼中去派哲。
## 為你的應(yīng)用程序增加一個WebView
為了在你的應(yīng)用中增加WebView,簡單的在布局文件中引入 `<WebView>`標(biāo)簽就可以掺喻。例如芭届,下面就是一個讓W(xué)ebView充滿屏幕的布局文件。
```
<?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"
/>
```
通過`loadUrl()`方法為WebView加載Web頁感耙。例如:
```
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");
```
在它開始工作之前褂乍,你的應(yīng)用必須有訪問網(wǎng)絡(luò)的權(quán)限。為了獲得這一權(quán)限即硼,需要在你的manifest文件中請求[INTERNET](https://developer.android.com/reference/android/Manifest.permission.html#INTERNET)權(quán)限逃片。例如:
```
<manifest ... >
? ? <uses-permission android:name="android.permission.INTERNET" />
? ? ...
</manifest>
```
這就是創(chuàng)建一個基本的展示W(wǎng)eb頁的WebView你所需要做的全部的事情。
## 在WebView中使用JavaScript
如果你想在你的WebView中加載帶有JavaScript的Web頁只酥,你必須讓你的WebView支持JavaScript褥实。一旦JavaScript被啟用了呀狼,你就可以在你的應(yīng)用代碼和JavaScript代碼中創(chuàng)建接口了。
### 啟用JavaScript
默認(rèn)情況下损离,WebView中JavaScript是不啟用的哥艇。你可以通過依附于WebView的[WebSettings](https://developer.android.com/reference/android/webkit/WebSettings.html)類實現(xiàn),使用webView 的`getSetting()`方法返回一個`webSetting`對象僻澎,調(diào)用`setJavaScriptEnabled()`來開啟JavaScript貌踏。
例如:
```
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
```
[WebSettings](https://developer.android.com/reference/android/webkit/WebSettings.html)提供了各種各樣的你可能會發(fā)現(xiàn)很有用的其他設(shè)置。例如怎棱,如果你正在開發(fā)一個專門用WebView設(shè)計的Web應(yīng)用哩俭,你通過`setUserAgentString()`方法自定義了一個一個用戶代理字符串。通過在你的Web頁中查詢這個自定義的用戶代理字符串來核實客戶端的請求是否來自的了Android應(yīng)用拳恋。
### 將 JavaScript 代碼綁定到 Android代碼
當(dāng)我們開發(fā)一個以WebView實現(xiàn)Web的Android應(yīng)用時凡资,你可以在你的javaScript代碼和客戶端Android之前創(chuàng)建接口。例如你的JavaScript代碼可以調(diào)用一段你的Android代碼來啟動一個 [Dialog](https://developer.android.com/reference/android/app/Dialog.html)谬运,而不是通過在JavaScript中使用`alert()`函數(shù)實現(xiàn)隙赁。
為了在你的Android代碼和JavaScript代碼間綁定一個接口,需要調(diào)用`addJavascriptInterface()`方法梆暖,傳遞一個類實例到你綁定的JavaScript中伞访,JavaScript可以調(diào)用以訪問該類的接口名稱。
```
public class WebAppInterface {
? ? Context mContext;
? ? /** Instantiate the interface and set the context */
? ? WebAppInterface(Context c) {
? ? ? ? mContext = c;
? ? }
? ? /** Show a toast from the web page */
? ? @JavascriptInterface
? ? public void showToast(String toast) {
? ? ? ? Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
? ? }
}
```
> 警告:如果你的 [`targetSdkVersion`](https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#target)是17或者更高轰驳,你必須在你想要暴露給JavaScript的方法(方法必須是public方法)前加 `@JavascriptInterface`注解,如果你不提供這個注解厚掷,當(dāng)在Android4.2或者更高的版本中運(yùn)行該程序時,你的web 也將不能取得該方法级解。
在這個例子中冒黑,`WebAppInterface`類允許web頁通過使用`showToast()`方法創(chuàng)建一個Toast信息。
你可以通過`addJavascriptInterface()`方法綁定這個類到運(yùn)行在你的WebView中JavaScript上勤哗,并且以“Android”命名接口抡爹。
例如:
```
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
```
這段代碼為運(yùn)行在WebView上的JavaScript創(chuàng)建了一個名為“Android”的接口,這時芒划,你的Web應(yīng)用可以訪問到
`WebAppInterface`類冬竟。類如,當(dāng)用戶點擊了一個按鈕民逼,這里有的HTML和JavaScript代碼就會使用這個接口創(chuàng)建一個Toast消息泵殴。
```
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
? ? function showAndroidToast(toast) {
? ? ? ? Androi.showToast(toast);
? ? }
</script>
```
這里不需要在JavaScript中初始化你的“Android”接口,WebView自動的讓它在你的Web頁中可獲得缴挖。所以袋狞,在按鈕的點擊事件中,`showAndroidToast()`方法使用“Android”接口來調(diào)用`WebAppInterface.showToast()`方法。
> 注意:綁定到JavaScript上的對象將會運(yùn)行在另一個線程中苟鸯,而不是在構(gòu)造它的線程中運(yùn)行同蜻。
警告:使用`addJavascriptInterface()`方法會允許JavaScript控制你的Android應(yīng)用。這是一個很有用的特點早处,也是一個危險的安全問題湾蔓。當(dāng)WebView中的HTML代碼不可信時(例如,HTML的一部分或全部是由未知的人或進(jìn)程提供的)攻擊者可以植入HTML代碼執(zhí)行你的客戶端代碼砌梆,這些代碼可以是任意代碼默责。正因為如此,除非你WebView中所有的HTML和JavaScript代碼都是自己寫的咸包,否則就不要使用`addJavascriptInterface()`方法桃序。你也不應(yīng)該讓用戶在你的WebView中導(dǎo)航到不屬于你的Web站點上。(相反的是烂瘫,允許用戶使用默認(rèn)瀏覽器應(yīng)用來打開外部鏈接--在默認(rèn)情況下媒熊,用戶的瀏覽器可以打開所有鏈接,所以坟比,在以下情況時要小心處理導(dǎo)航界面)
## 處理頁面導(dǎo)航
當(dāng)用戶在你的WebView中點擊了Web頁中的一個鏈接芦鳍,默認(rèn)的行為是讓Android 系統(tǒng)啟動一個可以處理URLs的應(yīng)用。通常情況下葛账,默認(rèn)的Web瀏覽器將會根據(jù)URL去加載柠衅。然而,你可以在你的WebView中重寫這個行為籍琳,讓鏈接在你的WebView中打開菲宴。你可以允許用戶通過WebView中保存的瀏覽歷史來通過導(dǎo)航欄進(jìn)行前進(jìn)或后退。
為了打開被用戶點擊的鏈接趋急,簡單的為WebView提供了[WebViewClient](https://developer.android.com/reference/android/webkit/WebViewClient.html)類裙顽,通過 `setWebViewClient()`方法獲得,例如:
```
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());
```
就這樣宣谈,所有用戶點擊的鏈接都將在你的WebView中加載。
如果你想對鏈接點擊事件有更多的控制键科,創(chuàng)建你自己的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創(chuàng)建一個新的WebViewClient:
```
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());
```
現(xiàn)在勋颖,每當(dāng)用戶點擊一個鏈接嗦嗡,系統(tǒng)就會調(diào)用 `shouldOverrideUrlLoading()`方法,去檢查是否URL的主機(jī)名稱可以匹配這個特殊的域名饭玲。如果確實匹配侥祭,方法會返回false,不會重寫URL,如果不匹配,就通過一個Intent,去啟動默認(rèn)程序來解析URLs矮冬。
### 瀏覽網(wǎng)頁歷史記錄
當(dāng)你的WebView重新加載了URL時谈宛,它會自動的保存一個瀏覽的歷史記錄。你可以通過導(dǎo)航欄的后退和前進(jìn)在歷史記錄的 `goBack()` 和 `goForward()`方法中瀏覽胎署。
例如吆录,這里是你的Activity能使用的設(shè)備導(dǎo)航欄的后退按鈕的方法。
```
@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代表這里有用戶可以訪問的Web頁的歷史記錄琼牧。同樣的恢筝,你可以使用 `canGoForward()`方法來判斷是否有可以前進(jìn)的歷史記錄。如果你不做這個檢查巨坊,一旦用戶到達(dá)了歷史記錄的底端 `goBack()` 和 `goForward()` 方法將什么也不會做撬槽。