前言
如果您希望在客戶端應(yīng)用中提供 Web 應(yīng)用(或只是網(wǎng)頁(yè))商虐,則可以使用 WebView 執(zhí)行該操作怀酷。WebView 類是 Android 的 View 類的擴(kuò)展稻爬,可讓您將網(wǎng)頁(yè)顯示為 Activity 布局的一部分。它不會(huì)包含功能全面的網(wǎng)絡(luò)瀏覽器的任何功能蜕依,例如導(dǎo)航控件或地址欄桅锄。WebView 默認(rèn)只顯示網(wǎng)頁(yè)。
使用 WebView 非常有用的一種常見情形是样眠,您希望在應(yīng)用中提供可能需要更新的信息友瘤,例如最終用戶協(xié)議或用戶指南。在 Android 應(yīng)用中檐束,您可以創(chuàng)建一個(gè)包含 WebView 的 Activity辫秧,然后使用它來(lái)顯示在線托管的文檔。
另一種 WebView 可能會(huì)有所幫助的情形是厢塘,如果您的應(yīng)用向用戶提供始終需要互聯(lián)網(wǎng)連接才能檢索數(shù)據(jù)的數(shù)據(jù)(例如電子郵件)茶没。在這種情況下肌幽,您可能會(huì)發(fā)現(xiàn)相比于執(zhí)行網(wǎng)絡(luò)請(qǐng)求,然后解析數(shù)據(jù)并在 Android 布局中呈現(xiàn)數(shù)據(jù)抓半,在 Android 應(yīng)用中編譯 WebView 以顯示包含所有用戶數(shù)據(jù)的網(wǎng)頁(yè)更加輕松喂急。您可以改為設(shè)計(jì)一個(gè)專為 Android 設(shè)備定制的網(wǎng)頁(yè),然后在加載該網(wǎng)頁(yè)的 Android 應(yīng)用中實(shí)現(xiàn) WebView笛求。
本文檔向您介紹了如何開始使用 WebView 以及如何執(zhí)行其他操作廊移,例如處理網(wǎng)頁(yè)導(dǎo)航以及將網(wǎng)頁(yè)中的 JavaScript 綁定到 Android 應(yīng)用中的客戶端代碼。
向應(yīng)用中添加Webview
要向應(yīng)用中添加 WebView探入,您可以在 Activity 布局中添加 <WebView> 元素狡孔,或在 onCreate() 中將整個(gè) Activity 窗口設(shè)置為 WebView。
1.在 Activity 布局中添加 WebView
要在布局中為應(yīng)用添加 WebView蜂嗽,請(qǐng)將以下代碼添加到 Activity 的布局 XML 文件中:
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
要在 WebView 中加載網(wǎng)頁(yè)苗膝,請(qǐng)使用 loadUrl()。例如:
val myWebView: WebView = findViewById(R.id.webview)
myWebView.loadUrl("http://www.example.com")
2.在 onCreate() 中添加 WebView
要在 Activity 的 onCreate() 方法中向應(yīng)用添加 WebView植旧,請(qǐng)使用類似如下的邏輯:
val myWebView = WebView(activityContext)
setContentView(myWebView)
然后使用以下命令加載網(wǎng)頁(yè):
myWebView.loadUrl("http://www.example.com")
或者通過(guò) HTML 字符串加載網(wǎng)址:
// Create an unencoded HTML string
// then convert the unencoded HTML string into bytes, encode
// it with Base64, and load the data.
val unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"
val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING)
myWebView.loadData(encodedHtml, "text/html", "base64")
記得再此之前配置網(wǎng)絡(luò)權(quán)限:
<manifest ... >
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
以上就是用于顯示網(wǎng)頁(yè)的基本 WebView 所需的全部?jī)?nèi)容辱揭。此外,您還可以通過(guò)修改以下內(nèi)容來(lái)自定義 WebView:
- 使用 WebChromeClient 啟用全屏支持病附。如果 WebView 需要權(quán)限以更改主機(jī)應(yīng)用的界面(例如創(chuàng)建或關(guān)閉窗口以及向用戶發(fā)送 JavaScript 對(duì)話框)问窃,也需要調(diào)用此類。要詳細(xì)了解如何在這種情況下進(jìn)行調(diào)試完沪;
- 處理影響內(nèi)容呈現(xiàn)的事件域庇,例如提交表單時(shí)或使用 WebViewClient 導(dǎo)航時(shí)出現(xiàn)的錯(cuò)誤。 您也可以使用此子類攔截網(wǎng)址加載覆积。
- 通過(guò)修改 WebSettings 來(lái)啟用 JavaScript听皿。
- 使用 JavaScript 訪問(wèn)已注入到 WebView 的 Android 框架對(duì)象。
在 WebView 中使用 JavaScript
如果您打算在 WebView 中加載的網(wǎng)頁(yè)使用 JavaScript技健,則必須為您的 啟用 JavaScript写穴。啟用 JavaScript 后,您還可以在應(yīng)用代碼和 JavaScript 代碼之間創(chuàng)建接口雌贱。
啟用 JavaScript
JavaScript 在 WebView 中默認(rèn)處于停用狀態(tài)啊送。您可以通過(guò)附加到 WebView 的 WebSettings 啟用 JavaScript。您也可以使用 getSettings() 檢索 WebSettings欣孤,然后使用 setJavaScriptEnabled() 啟用 JavaScript馋没。
val myWebView: WebView = findViewById(R.id.webview)
myWebView.settings.javaScriptEnabled = true
WebSettings 提供對(duì)其他各種實(shí)用設(shè)置的訪問(wèn)權(quán)限。例如降传,如果您正在開發(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ā)專為 Android 應(yīng)用中的 WebView 設(shè)計(jì)的 Web 應(yīng)用時(shí)笔链,您可以在 JavaScript 代碼和客戶端 Android 代碼之間創(chuàng)建接口。例如腮猖,您的 JavaScript 代碼可以調(diào)用 Android 代碼中的方法(而不是使用 JavaScript 的 alert() 函數(shù))來(lái)顯示 Dialog鉴扫。
要綁定 JavaScript 代碼與 Android 代碼之間的新接口,請(qǐng)調(diào)用 addJavascriptInterface()澈缺,并傳入類實(shí)例以綁定到 JavaScript 以及 JavaScript 可調(diào)用以訪問(wèn)類的接口名稱坪创。
例如,您可以在 Android 應(yīng)用中包含以下類:
class WebAppInterface(private val mContext: Context) {
/**
* 彈Toast
*/
@JavascriptInterface
fun showToast(toast: String) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show()
}
}
注意:如果您將 targetSdkVersion 設(shè)置為 17 或更高姐赡,則必須向您希望 JavaScript(此方法也必須為公開方法)可用的任何方法添加 @JavascriptInterface 注釋莱预。如果您未提供注釋,那么在 Android 4.2 或更高版本的平臺(tái)上運(yùn)行時(shí)您的網(wǎng)頁(yè)將無(wú)法訪問(wèn)該方法项滑。
在此示例中依沮,WebAppInterface 類允許網(wǎng)頁(yè)使用 showToast() 方法創(chuàng)建 Toast 消息。
您可以使用 addJavascriptInterface() 將此類綁定到在 WebView 中運(yùn)行的 JavaScript枪狂,并為接口 Android 命名悉抵。例如:
val webView: WebView = findViewById(R.id.webview)
webView.addJavascriptInterface(WebAppInterface(this), "Android")
這會(huì)為在 WebView 中運(yùn)行的 JavaScript 創(chuàng)建名為 Android 的接口。此時(shí)摘完,您的 Web 應(yīng)用可以訪問(wèn) WebAppInterface 類。例如傻谁,以下是用于在用戶點(diǎn)擊按鈕時(shí)使用新接口創(chuàng)建提示消息的 HTML 和 JavaScript:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
無(wú)需從 JavaScript 初始化 Android 接口孝治。WebView 會(huì)自動(dòng)將其提供給您的網(wǎng)頁(yè)。因此审磁,點(diǎn)擊此按鈕后谈飒,showAndroidToast() 函數(shù)會(huì)使用 Android 接口調(diào)用 WebAppInterface.showToast() 方法。
注意:綁定到 JavaScript 的對(duì)象在另一個(gè)線程中運(yùn)行态蒂,而不是在構(gòu)造它的線程中運(yùn)行杭措。
注意:使用 addJavascriptInterface() 可讓 JavaScript 控制您的 Android 應(yīng)用。這可能是非常實(shí)用的功能钾恢,也可能會(huì)造成危險(xiǎn)的安全問(wèn)題手素。如果 WebView 中的 HTML 不可信(例如,部分或全部 HTML 由未知人員或進(jìn)程提供)瘩蚪,則攻擊者可以包含執(zhí)行客戶端代碼的 HTML泉懦,并且可能包含攻擊者選擇的任何代碼。因此疹瘦,除非您編寫了在 WebView 中顯示的所有 HTML 和 JavaScript崩哩,否則請(qǐng)不要使用 addJavascriptInterface()。您也不應(yīng)允許用戶在您的 WebView 內(nèi)導(dǎo)航到并非您自己的其他網(wǎng)頁(yè)(而應(yīng)允許用戶的默認(rèn)瀏覽器應(yīng)用打開外部鏈接,默認(rèn)情況下邓嘹,用戶的網(wǎng)絡(luò)瀏覽器會(huì)打開所有網(wǎng)址鏈接酣栈,因此,請(qǐng)務(wù)必謹(jǐn)慎處理網(wǎng)頁(yè)導(dǎo)航汹押,如下文所述)矿筝。
處理網(wǎng)頁(yè)導(dǎo)航
當(dāng)用戶在 WebView 中點(diǎn)擊網(wǎng)頁(yè)中的鏈接時(shí),Android 的默認(rèn)行為是啟動(dòng)處理網(wǎng)址的應(yīng)用鲸阻。默認(rèn)網(wǎng)絡(luò)瀏覽器通常會(huì)打開并加載目標(biāo)網(wǎng)址跋涣。不過(guò),您可以為 WebView 替換此行為鸟悴,以便在 WebView 內(nèi)打開鏈接陈辱。然后,您可以允許用戶向后/向前瀏覽由您的 WebView 維護(hù)的網(wǎng)頁(yè)歷史記錄细诸。
注意:出于安全考慮沛贪,系統(tǒng)的瀏覽器應(yīng)用不會(huì)與您的應(yīng)用共享其應(yīng)用數(shù)據(jù)。
要想在當(dāng)前webview中打開用戶點(diǎn)擊的鏈接震贵,請(qǐng)使用 setWebViewClient() 為您的 WebView 提供 WebViewClient利赋。例如:
val myWebView: WebView = findViewById(R.id.webview)
myWebView.webViewClient = WebViewClient()
大功告成。現(xiàn)在猩系,用戶點(diǎn)擊的所有鏈接都會(huì)在您的 WebView 中加載媚送。
如果您希望更好地控制用戶點(diǎn)擊的鏈接的加載位置,請(qǐng)創(chuàng)建您自己的 WebViewClient 以替換 shouldOverrideUrlLoading() 方法寇甸。例如:
private class MyWebViewClient : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
if (Uri.parse(url).host == "www.example.com") {
// 這是我的網(wǎng)站塘偎,所以不要覆蓋;讓我的WebView加載頁(yè)面
return false
}
// 否則拿霉,該鏈接不適合我網(wǎng)站上的頁(yè)面吟秩,因此啟動(dòng)另一個(gè)處理URL的活動(dòng)。
Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
startActivity(this)
}
return true
}
}
然后绽淘,為 WebView 創(chuàng)建這一新 WebViewClient 的實(shí)例:
val myWebView: WebView = findViewById(R.id.webview)
myWebView.webViewClient = MyWebViewClient()
現(xiàn)在涵防,當(dāng)用戶點(diǎn)擊某個(gè)鏈接時(shí),系統(tǒng)會(huì)調(diào)用 shouldOverrideUrlLoading()沪铭,后者會(huì)檢查網(wǎng)址主機(jī)是否與特定網(wǎng)域匹配(如上所述)壮池。如果匹配,則該方法會(huì)返回 false杀怠,以避免替換網(wǎng)址加載(它允許 WebView 像往常一樣加載網(wǎng)址)火窒。如果網(wǎng)址主機(jī)不匹配,則創(chuàng)建 Intent 以啟動(dòng)用于處理網(wǎng)址的默認(rèn) Activity(解析為用戶的默認(rèn)網(wǎng)絡(luò)瀏覽器)驮肉。
瀏覽網(wǎng)頁(yè)歷史記錄
當(dāng)您的 WebView 替換網(wǎng)址加載時(shí)熏矿,它會(huì)自動(dòng)累積已訪問(wèn)網(wǎng)頁(yè)的歷史記錄。您可以使用 goBack() 和 goForward() 向后/向前瀏覽歷史記錄。
例如票编,下面顯示了您的 Activity 是如何使用設(shè)備的返回按鈕向后導(dǎo)航的:
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
// 檢查按鍵事件是否為“后退”按鈕以及是否有歷史記錄
if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) {
myWebView.goBack()
return true
}
// 如果不是Back鍵或沒有網(wǎng)頁(yè)歷史記錄褪储,則執(zhí)行系統(tǒng)處理
return super.onKeyDown(keyCode, event)
}
如果確實(shí)存在用戶要訪問(wèn)的網(wǎng)頁(yè)歷史記錄,則 canGoBack() 方法會(huì)返回 true慧域。同樣鲤竹,您可以使用 canGoForward() 檢查是否存在向前歷史記錄。如果您不執(zhí)行此檢查昔榴,那么當(dāng)用戶瀏覽到歷史記錄的末尾時(shí)辛藻,goBack() 或 goForward() 將不執(zhí)行任何操作。
處理設(shè)備狀態(tài)更改
在運(yùn)行時(shí)互订,Activity 狀態(tài)更改會(huì)在設(shè)備的配置發(fā)生更改時(shí)發(fā)生吱肌,例如用戶旋轉(zhuǎn)設(shè)備或關(guān)閉輸入法 (IME) 時(shí)。這些更改會(huì)導(dǎo)致 WebView 對(duì)象的 Activity 被銷毀并創(chuàng)建新的 Activity仰禽,而這也會(huì)創(chuàng)建新的 WebView 對(duì)象來(lái)加載已銷毀對(duì)象的網(wǎng)址氮墨。要修改 Activity 的默認(rèn)行為,您可以在清單中更改其處理 orientation 更改的方式吐葵。