如果要將Web
應(yīng)用程序(或僅僅是網(wǎng)頁(yè))作為客戶端應(yīng)用程序的一部分提供,則可以使用WebView
執(zhí)行此操作摧茴。 WebView
類是Android
的View
類的擴(kuò)展绵载,允許您將Web
頁(yè)面顯示為活動(dòng)布局的一部分。它不包括完全開發(fā)的Web
瀏覽器的任何功能蓬蝶,例如導(dǎo)航控件或地址欄。默認(rèn)情況下猜惋,WebView
所做的就是顯示一個(gè)網(wǎng)頁(yè)丸氛。
本文檔向您展示了如何開始使用WebView
以及如何執(zhí)行其他操作,例如處理頁(yè)面導(dǎo)航以及將網(wǎng)頁(yè)中的JavaScript
綁定到Android
應(yīng)用程序中的客戶端代碼著摔。
一缓窜、將WebView添加到您的應(yīng)用程序
要將WebView
添加到應(yīng)用程序,可以在活動(dòng)布局中包含<WebView>
元素谍咆,也可以將整個(gè)“活動(dòng)”窗口設(shè)置為onCreate()
中的WebView
禾锤。
在活動(dòng)布局中添加WebView
將以下代碼添加到活動(dòng)的布局XML
文件中:
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
要在WebView
中加載網(wǎng)頁(yè),請(qǐng)使用loadUrl()
摹察。 例如:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");
在onCreate()中添加WebView
在活動(dòng)的onCreate()
方法中向您的應(yīng)用添加WebView
:
WebView myWebView = new WebView(activityContext);
setContentView(myWebView);
然后加載頁(yè)面:
myWebView.loadUrl("https://www.example.com");
或者從HTML
字符串加載URL
:
// Create an unencoded HTML string
// then convert the unencoded HTML string into bytes, encode
// it with Base64, and load the data.
String unencodedHtml =
"<html><body>'%23' is the percent code for ‘#‘ </body></html>";
String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(),
Base64.NO_PADDING);
myWebView.loadData(encodedHtml, "text/html", "base64");
注意:此
HTML
可以執(zhí)行的操作有一些限制恩掷。 有關(guān)編碼選項(xiàng)的詳細(xì)信息,請(qǐng)參閱loadData()
和loadDataWithBaseURL()
供嚎。
權(quán)限
在此之前黄娘,您的應(yīng)用必須能夠訪問Internet
峭状。 請(qǐng)?jiān)谇鍐挝募姓?qǐng)求INTERNET權(quán)限:
<manifest ... >
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
這就是顯示網(wǎng)頁(yè)的基本WebView
所需的全部?jī)?nèi)容。 此外逼争,您可以通過修改以下內(nèi)容來自定義WebView
:
- 使用
WebChromeClient
啟用全屏支持优床。 當(dāng)WebView
需要更改主機(jī)應(yīng)用程序UI的權(quán)限時(shí),也會(huì)調(diào)用此類誓焦,例如創(chuàng)建或關(guān)閉窗口以及向用戶發(fā)送JavaScript
對(duì)話框胆敞。 - 處理影響內(nèi)容呈現(xiàn)的事件,例如表單提交上的錯(cuò)誤或使用
WebViewClient
導(dǎo)航杂伟。 您還可以使用此子類來攔截URL加載移层。 - 通過修改
WebSettings
啟用JavaScript
。 - 使用
JavaScript
訪問已注入WebView
的Android
框架對(duì)象稿壁。
二幽钢、在WebView中使用JavaScript
如果您計(jì)劃在WebView
中加載的網(wǎng)頁(yè)使用JavaScript
,則必須為WebView
啟用JavaScript
傅是。 啟用JavaScript
后匪燕,您還可以在應(yīng)用代碼和JavaScript
代碼之間創(chuàng)建接口。
啟用JavaScript
默認(rèn)情況下喧笔,在WebView
中禁用JavaScript
帽驯。
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
WebSettings
提供對(duì)您可能會(huì)發(fā)現(xiàn)有用的各種其他設(shè)置的訪問。 例如书闸,如果您正在開發(fā)專門為Android
應(yīng)用程序中的WebView
設(shè)計(jì)的Web
應(yīng)用程序尼变,則可以使用setUserAgentString()
定義自定義用戶代理字符串,然后在網(wǎng)頁(yè)中查詢自定義用戶代理以驗(yàn)證浆劲,請(qǐng)求您的網(wǎng)頁(yè)的客戶實(shí)際上是您的Android
應(yīng)用嫌术。
將JavaScript代碼綁定到Android代碼
在開發(fā)專為Web
應(yīng)用程序中的WebView
設(shè)計(jì)的Web
應(yīng)用程序時(shí),您可以在JavaScript
代碼和客戶端Android
代碼之間創(chuàng)建接口牌借。 例如度气,您的JavaScript
代碼可以調(diào)用Android
代碼中的方法來顯示Dialog
,而不是使用JavaScript
的alert()
函數(shù)膨报。
要綁定JavaScript
和Android
代碼之間的新接口磷籍,請(qǐng)調(diào)用addJavascriptInterface()
,向其傳遞一個(gè)類實(shí)例以綁定到您的JavaScript
以及您可以調(diào)用以訪問該類的接口名稱现柠。
例如院领,您可以在Android應(yīng)用中包含以下類:
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
設(shè)置為17或更高,則必須將@JavascriptInterface
注釋添加到您希望JavaScript
可用的任何方法(該方法也必須是公共的)够吩。 如果您未提供注釋比然,則在Android 4.2
或更高版本上運(yùn)行時(shí),您的網(wǎng)頁(yè)無法訪問該方法周循。
在此示例中谈秫,WebAppInterface
類允許網(wǎng)頁(yè)使用showToast()
方法創(chuàng)建Toast
消息扒寄。
您可以使用addJavascriptInterface()
將此類綁定到在WebView
中運(yùn)行的JavaScript
,并將接口命名為Android
拟烫。 例如:
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
這將在WebView
中創(chuàng)建一個(gè)名為Android for JavaScript
的界面该编。 此時(shí),您的Web
應(yīng)用程序可以訪問WebAppInterface
類硕淑。 例如课竣,以下是一些HTML
和JavaScript
,當(dāng)用戶單擊按鈕時(shí)置媳,使用新界面創(chuàng)建Toast
消息:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
無需從JavaScript
初始化Android
界面于樟。 WebView
會(huì)自動(dòng)將其提供給您的網(wǎng)頁(yè)。 因此拇囊,只需單擊按鈕迂曲,showAndroidToast()
函數(shù)就會(huì)使用Android
界面調(diào)用WebAppInterface.showToast()
方法。
注意:綁定到
JavaScript
的對(duì)象在另一個(gè)線程中運(yùn)行寥袭,而不是在構(gòu)造它的線程中運(yùn)行路捧。
警告:使用
addJavascriptInterface()
可以讓JavaScript
控制您的Android
應(yīng)用。 這可能是一個(gè)非常有用的功能或危險(xiǎn)的安全問題传黄。 當(dāng)WebView
中的HTML
不可信(例如杰扫,部分或全部HTML
由未知的人或進(jìn)程提供)時(shí),攻擊者可以包含執(zhí)行客戶端代碼的HTML
膘掰,也可能包括攻擊者選擇的任何代碼章姓。 因此,除非您編寫了WebView中顯示的所有HTML
和JavaScript
识埋,否則不應(yīng)使用addJavascriptInterface()
凡伊。 您也不應(yīng)允許用戶在WebView
中導(dǎo)航到不屬于您自己的其他網(wǎng)頁(yè)(而是允許用戶的默認(rèn)瀏覽器應(yīng)用程序打開外部鏈接 - 默認(rèn)情況下,用戶的Web
瀏覽器會(huì)打開所有URL
鏈接窒舟,因此 只有在按照以下部分所述處理頁(yè)面導(dǎo)航時(shí)才要小心)系忙。
三、處理頁(yè)面導(dǎo)航
當(dāng)用戶從WebView
中的網(wǎng)頁(yè)單擊鏈接時(shí)辜纲,Android
的默認(rèn)行為是啟動(dòng)處理URL
的應(yīng)用程序笨觅。 通常拦耐,默認(rèn)Web
瀏覽器會(huì)打開并加載目標(biāo)URL
耕腾。 但是,您可以為WebView
覆蓋此行為杀糯,以便在WebView
中打開鏈接扫俺。 然后,您可以允許用戶在WebView
維護(hù)的網(wǎng)頁(yè)歷史記錄中前后導(dǎo)航固翰。
注意:出于安全考慮狼纬,系統(tǒng)的瀏覽器應(yīng)用程序不會(huì)與您的應(yīng)用共享其應(yīng)用程序數(shù)據(jù)羹呵。
要打開用戶單擊的鏈接,請(qǐng)使用setWebViewClient()
為WebView
提供WebViewClient
疗琉。 例如:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(MyWebViewClient);
現(xiàn)在冈欢,用戶在WebView
中單擊加載的所有鏈接。
如果您想要更好地控制單擊鏈接的加載位置盈简,請(qǐng)創(chuàng)建自己的WebViewClient來覆蓋shouldOverrideUrlLoading()
方法凑耻。 例如:
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading( WebView view, String url) {
if (Uri.parse(url).getHost().equals("https://www.example.com")) {
// This is my website, 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)建這個(gè)新WebViewClient的實(shí)例:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());
現(xiàn)在,當(dāng)用戶單擊鏈接時(shí)柠贤,系統(tǒng)調(diào)用shouldOverrideUrlLoading()
香浩,它會(huì)檢查URL
主機(jī)是否與特定域匹配(如上所述)。 如果它匹配臼勉,則該方法返回false以便不覆蓋URL
加載(它允許WebView
像往常一樣加載URL
)邻吭。 如果URL主機(jī)不匹配瘩蚪,則會(huì)創(chuàng)建一個(gè)Intent
以啟動(dòng)處理UR
L的默認(rèn)活動(dòng)(解析為用戶的默認(rèn)Web
瀏覽器)盛险。
瀏覽網(wǎng)頁(yè)歷史記錄
當(dāng)WebView
覆蓋URL
加載時(shí),它會(huì)自動(dòng)累積訪問過的網(wǎng)頁(yè)的歷史記錄实愚。 您可以使用goBack()
和goForward()
在歷史記錄中前后導(dǎo)航猖败。
例如速缆,以下是您的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);
}
}
如果實(shí)際存在用戶要訪問的網(wǎng)頁(yè)歷史記錄,則canGoBack()
方法返回true
恩闻。 同樣艺糜,您可以使用canGoForward()
來檢查是否存在轉(zhuǎn)發(fā)歷史記錄。 如果您不執(zhí)行此檢查幢尚,那么一旦用戶到達(dá)歷史記錄的末尾破停,goBack()
或goForward()
就不會(huì)執(zhí)行任何操作。
處理設(shè)備配置更改
在運(yùn)行時(shí)期間尉剩,當(dāng)設(shè)備的配置發(fā)生更改(例如真慢,用戶旋轉(zhuǎn)設(shè)備或關(guān)閉輸入法編輯器(IME)時(shí))會(huì)發(fā)生活動(dòng)狀態(tài)更改。 這些更改將導(dǎo)致銷毀WebView
對(duì)象的活動(dòng)并創(chuàng)建新活動(dòng)理茎,這也會(huì)創(chuàng)建一個(gè)新的WebView
對(duì)象黑界,該對(duì)象將加載銷毀對(duì)象的URL
。 要修改活動(dòng)的默認(rèn)行為皂林,您可以更改其在清單中處理方向更改的方式朗鸠。
四、管理窗口
默認(rèn)情況下础倍,將忽略打開新窗口的請(qǐng)求烛占。 無論是通過JavaScript
還是通過鏈接中的target
屬性打開它都是如此。 您可以自定義WebChromeClient
以提供打開多個(gè)窗口的行為。
警告:為了使您的應(yīng)用更安全忆家,最好防止彈出窗口和新窗口打開犹菇。 實(shí)現(xiàn)此行為的最安全方法是將“
true
”傳遞給setSupportMultipleWindows()
,但不覆蓋setSupportMultipleWindows()
依賴的onCreateWindow()
方法芽卿。 但請(qǐng)記住揭芍,此邏輯還會(huì)阻止任何在其鏈接中使用target =“_ blank”
的頁(yè)面加載。