Android開發(fā)之Webview的簡(jiǎn)單使用

前言


如果您希望在客戶端應(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 = "&lt;html&gt;&lt;body&gt;'%23' is the percent code for ‘#‘ &lt;/body&gt;&lt;/html&gt;"
    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 更改的方式吐葵。

參考:在 WebView 中編譯 Web 應(yīng)用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末规揪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子温峭,更是在濱河造成了極大的恐慌猛铅,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凤藏,死亡現(xiàn)場(chǎng)離奇詭異奕坟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)清笨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)刃跛,“玉大人抠艾,你說(shuō)我怎么就攤上這事〗瓣迹” “怎么了检号?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蛙酪。 經(jīng)常有香客問(wèn)我齐苛,道長(zhǎng),這世上最難降的妖魔是什么桂塞? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任凹蜂,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘玛痊。我一直安慰自己汰瘫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布擂煞。 她就那樣靜靜地躺著混弥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪对省。 梳的紋絲不亂的頭發(fā)上蝗拿,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音蒿涎,去河邊找鬼哀托。 笑死,一個(gè)胖子當(dāng)著我的面吹牛同仆,可吹牛的內(nèi)容都是我干的萤捆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼俗批,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼俗或!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起岁忘,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤辛慰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后干像,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帅腌,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年麻汰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了速客。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡五鲫,死狀恐怖溺职,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情位喂,我是刑警寧澤浪耘,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站塑崖,受9級(jí)特大地震影響七冲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜规婆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一澜躺、第九天 我趴在偏房一處隱蔽的房頂上張望蝉稳。 院中可真熱鬧,春花似錦苗踪、人聲如沸颠区。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)毕莱。三九已至,卻和暖如春颅夺,著一層夾襖步出監(jiān)牢的瞬間朋截,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工吧黄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留部服,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓拗慨,卻偏偏與公主長(zhǎng)得像廓八,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赵抢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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