在WebView中構(gòu)建Web應(yīng)用程序(二)

如果要將Web應(yīng)用程序(或僅僅是網(wǎng)頁)作為客戶端應(yīng)用程序的一部分提供,則可以使用WebView執(zhí)行此操作。 WebView類是AndroidView類的擴(kuò)展,允許您將Web頁面顯示為活動布局的一部分。它不包括完全開發(fā)的Web瀏覽器的任何功能,例如導(dǎo)航控件或地址欄。默認(rèn)情況下,WebView所做的就是顯示一個網(wǎng)頁。

本文檔向您展示了如何開始使用WebView以及如何執(zhí)行其他操作,例如處理頁面導(dǎo)航以及將網(wǎng)頁中的JavaScript綁定到Android應(yīng)用程序中的客戶端代碼。

一、將WebView添加到您的應(yīng)用程序

要將WebView添加到應(yīng)用程序,可以在活動布局中包含<WebView>元素,也可以將整個“活動”窗口設(shè)置為onCreate()中的WebView。

在活動布局中添加WebView

將以下代碼添加到活動的布局XML文件中:

<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
/>

要在WebView中加載網(wǎng)頁,請使用loadUrl()。 例如:

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");
在onCreate()中添加WebView

在活動的onCreate()方法中向您的應(yīng)用添加WebView

WebView myWebView = new WebView(activityContext);
setContentView(myWebView);

然后加載頁面:

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 =
     "&lt;html&gt;&lt;body&gt;'%23' is the percent code for ‘#‘ &lt;/body&gt;&lt;/html&gt;";
String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(),
        Base64.NO_PADDING);
myWebView.loadData(encodedHtml, "text/html", "base64");

注意:此HTML可以執(zhí)行的操作有一些限制。 有關(guān)編碼選項的詳細(xì)信息,請參閱loadData()loadDataWithBaseURL()。

權(quán)限

在此之前,您的應(yīng)用必須能夠訪問Internet。 請在清單文件中請求INTERNET權(quán)限:

<manifest ... >
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

這就是顯示網(wǎng)頁的基本WebView所需的全部內(nèi)容。 此外,您可以通過修改以下內(nèi)容來自定義WebView

  • 使用WebChromeClient啟用全屏支持。 當(dāng)WebView需要更改主機(jī)應(yīng)用程序UI的權(quán)限時,也會調(diào)用此類,例如創(chuàng)建或關(guān)閉窗口以及向用戶發(fā)送JavaScript對話框。
  • 處理影響內(nèi)容呈現(xiàn)的事件,例如表單提交上的錯誤或使用WebViewClient導(dǎo)航。 您還可以使用此子類來攔截URL加載。
  • 通過修改WebSettings啟用JavaScript。
  • 使用JavaScript訪問已注入WebViewAndroid框架對象。

二、在WebView中使用JavaScript

如果您計劃在WebView中加載的網(wǎng)頁使用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提供對您可能會發(fā)現(xiàn)有用的各種其他設(shè)置的訪問。 例如,如果您正在開發(fā)專門為Android應(yīng)用程序中的WebView設(shè)計的Web應(yīng)用程序,則可以使用setUserAgentString()定義自定義用戶代理字符串,然后在網(wǎng)頁中查詢自定義用戶代理以驗證,請求您的網(wǎng)頁的客戶實際上是您的Android應(yīng)用。

將JavaScript代碼綁定到Android代碼

在開發(fā)專為Web應(yīng)用程序中的WebView設(shè)計的Web應(yīng)用程序時,您可以在JavaScript代碼和客戶端Android代碼之間創(chuàng)建接口。 例如,您的JavaScript代碼可以調(diào)用Android代碼中的方法來顯示Dialog,而不是使用JavaScriptalert()函數(shù)。

要綁定JavaScriptAndroid代碼之間的新接口,請調(diào)用addJavascriptInterface(),向其傳遞一個類實例以綁定到您的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)行時,您的網(wǎng)頁無法訪問該方法。
在此示例中,WebAppInterface類允許網(wǎng)頁使用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)建一個名為Android for JavaScript的界面。 此時,您的Web應(yīng)用程序可以訪問WebAppInterface類。 例如,以下是一些HTMLJavaScript,當(dāng)用戶單擊按鈕時,使用新界面創(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會自動將其提供給您的網(wǎng)頁。 因此,只需單擊按鈕,showAndroidToast()函數(shù)就會使用Android界面調(diào)用WebAppInterface.showToast()方法。

注意:綁定到JavaScript的對象在另一個線程中運(yùn)行,而不是在構(gòu)造它的線程中運(yùn)行。

警告:使用addJavascriptInterface()可以讓JavaScript控制您的Android應(yīng)用。 這可能是一個非常有用的功能或危險的安全問題。 當(dāng)WebView中的HTML不可信(例如,部分或全部HTML由未知的人或進(jìn)程提供)時,攻擊者可以包含執(zhí)行客戶端代碼的HTML,也可能包括攻擊者選擇的任何代碼。 因此,除非您編寫了WebView中顯示的所有HTMLJavaScript,否則不應(yīng)使用addJavascriptInterface()。 您也不應(yīng)允許用戶在WebView中導(dǎo)航到不屬于您自己的其他網(wǎng)頁(而是允許用戶的默認(rèn)瀏覽器應(yīng)用程序打開外部鏈接 - 默認(rèn)情況下,用戶的Web瀏覽器會打開所有URL鏈接,因此 只有在按照以下部分所述處理頁面導(dǎo)航時才要小心)。

三、處理頁面導(dǎo)航

當(dāng)用戶從WebView中的網(wǎng)頁單擊鏈接時,Android的默認(rèn)行為是啟動處理URL的應(yīng)用程序。 通常,默認(rèn)Web瀏覽器會打開并加載目標(biāo)URL。 但是,您可以為WebView覆蓋此行為,以便在WebView中打開鏈接。 然后,您可以允許用戶在WebView維護(hù)的網(wǎng)頁歷史記錄中前后導(dǎo)航。

注意:出于安全考慮,系統(tǒng)的瀏覽器應(yīng)用程序不會與您的應(yīng)用共享其應(yīng)用程序數(shù)據(jù)。

要打開用戶單擊的鏈接,請使用setWebViewClient()WebView提供WebViewClient。 例如:

WebView myWebView =  (WebView) findViewById(R.id.webview); 
myWebView.setWebViewClient(MyWebViewClient);

現(xiàn)在,用戶在WebView中單擊加載的所有鏈接。

如果您想要更好地控制單擊鏈接的加載位置,請創(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)建這個新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加載(它允許WebView像往常一樣加載URL)。 如果URL主機(jī)不匹配,則會創(chuàng)建一個Intent以啟動處理URL的默認(rèn)活動(解析為用戶的默認(rèn)Web瀏覽器)。

瀏覽網(wǎng)頁歷史記錄

當(dāng)WebView覆蓋URL加載時,它會自動累積訪問過的網(wǎng)頁的歷史記錄。 您可以使用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);  
    }  
}

如果實際存在用戶要訪問的網(wǎng)頁歷史記錄,則canGoBack()方法返回true。 同樣,您可以使用canGoForward()來檢查是否存在轉(zhuǎn)發(fā)歷史記錄。 如果您不執(zhí)行此檢查,那么一旦用戶到達(dá)歷史記錄的末尾,goBack()goForward()就不會執(zhí)行任何操作。

處理設(shè)備配置更改

在運(yùn)行時期間,當(dāng)設(shè)備的配置發(fā)生更改(例如,用戶旋轉(zhuǎn)設(shè)備或關(guān)閉輸入法編輯器(IME)時)會發(fā)生活動狀態(tài)更改。 這些更改將導(dǎo)致銷毀WebView對象的活動并創(chuàng)建新活動,這也會創(chuàng)建一個新的WebView對象,該對象將加載銷毀對象的URL。 要修改活動的默認(rèn)行為,您可以更改其在清單中處理方向更改的方式。

四、管理窗口

默認(rèn)情況下,將忽略打開新窗口的請求。 無論是通過JavaScript還是通過鏈接中的target屬性打開它都是如此。 您可以自定義WebChromeClient以提供打開多個窗口的行為。

警告:為了使您的應(yīng)用更安全,最好防止彈出窗口和新窗口打開。 實現(xiàn)此行為的最安全方法是將“true”傳遞給setSupportMultipleWindows(),但不覆蓋setSupportMultipleWindows()依賴的onCreateWindow()方法。 但請記住,此邏輯還會阻止任何在其鏈接中使用target =“_ blank”的頁面加載。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容