在WebView中構(gòu)建網(wǎng)絡(luò)應(yīng)用

[原文鏈接地址](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()` 方法將什么也不會做撬槽。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市趾撵,隨后出現(xiàn)的幾起案子侄柔,更是在濱河造成了極大的恐慌,老刑警劉巖鼓寺,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勋拟,死亡現(xiàn)場離奇詭異,居然都是意外死亡妈候,警方通過查閱死者的電腦和手機(jī)敢靡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苦银,“玉大人啸胧,你說我怎么就攤上這事♂B玻” “怎么了纺念?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長想括。 經(jīng)常有香客問我陷谱,道長,這世上最難降的妖魔是什么瑟蜈? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任烟逊,我火速辦了婚禮,結(jié)果婚禮上铺根,老公的妹妹穿的比我還像新娘宪躯。我一直安慰自己,他們只是感情好位迂,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布访雪。 她就那樣靜靜地躺著详瑞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪臣缀。 梳的紋絲不亂的頭發(fā)上坝橡,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機(jī)與錄音肝陪,去河邊找鬼驳庭。 笑死,一個胖子當(dāng)著我的面吹牛氯窍,可吹牛的內(nèi)容都是我干的饲常。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼狼讨,長吁一口氣:“原來是場噩夢啊……” “哼贝淤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起政供,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤播聪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后布隔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體离陶,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年衅檀,在試婚紗的時候發(fā)現(xiàn)自己被綠了招刨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡哀军,死狀恐怖沉眶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杉适,我是刑警寧澤谎倔,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站猿推,受9級特大地震影響片习,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蹬叭,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一毯侦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧具垫,春花似錦、人聲如沸试幽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至起宽,卻和暖如春洲胖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坯沪。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工绿映, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腐晾。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓叉弦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親藻糖。 傳聞我的和親對象是個殘疾皇子淹冰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容