WebView Apps

Web Apps

實(shí)現(xiàn)一個(gè)Android應(yīng)用的兩個(gè)基本方式是:客戶端應(yīng)用和Web應(yīng)用。前者使用Android SDK開發(fā)并且以一個(gè)APK方式安裝在用戶的設(shè)備上,后者使用標(biāo)準(zhǔn)的Web開發(fā),不需要在用戶設(shè)備上安裝,通過一個(gè)Web瀏覽器獲取。

如果我們?yōu)锳ndroid設(shè)備提供一個(gè)基于web的app,我們可以確定的是主流的Android瀏覽器(WebView框架)允許我們指定視窗和樣式屬性,確保我們的網(wǎng)頁(yè)在所有屏幕配置上都能夠呈現(xiàn)出合適的尺寸和大小。

我們不應(yīng)該開發(fā)一個(gè)app僅僅用來(lái)展示我們的網(wǎng)站。相反的,網(wǎng)頁(yè)應(yīng)該嵌入在我們的app中。我們甚至可以在Android應(yīng)用和網(wǎng)頁(yè)之間定義一個(gè)接口,以此允許我們網(wǎng)頁(yè)中的JavaScript可以調(diào)用Android應(yīng)用的APIs。

使Web Apps支持不同的屏幕

因?yàn)楦鞣NAndroid設(shè)備有不同的屏幕大小及像素密度,我們?cè)趙eb設(shè)計(jì)的時(shí)候應(yīng)該考慮這些因素,以便我們的網(wǎng)頁(yè)總能以合適的大小展現(xiàn)出來(lái)。

當(dāng)網(wǎng)頁(yè)的目標(biāo)設(shè)備是Android設(shè)備的時(shí)候,有兩個(gè)方面的因素需要我們考慮:

Viewport:Viewpost是一個(gè)矩形區(qū)域,它為我們的網(wǎng)頁(yè)提供一個(gè)可繪制區(qū)域。我們可以指定不同的Viewpost屬性,例如大小和初始縮放百分比。最重要的是Viewport的寬度,它定義了這個(gè)網(wǎng)頁(yè)視圖的橫向可用像素?cái)?shù)(可用CSS像素的數(shù)量)。

屏幕密度:Web類和Android大部分的網(wǎng)頁(yè)瀏覽器將CSS像素值轉(zhuǎn)換為獨(dú)立設(shè)備像素值。因此一個(gè)網(wǎng)頁(yè)在中等密度的屏幕上(160dpi)呈現(xiàn)出相同的可感知尺寸。如果圖形是我們網(wǎng)頁(yè)設(shè)計(jì)重要元素,我們應(yīng)該更加考慮出現(xiàn)在不同密度屏幕上的縮,因?yàn)橐粋€(gè)300像素寬的圖片在一個(gè)320dpi的屏幕上將被按比例放大(每CSS像素使用更多的物理像素),這將會(huì)導(dǎo)致偽影(模糊像素)。

使用WebView構(gòu)建Web Apps

如果我們想實(shí)現(xiàn)一個(gè)web應(yīng)用程序(或只是一個(gè)網(wǎng)頁(yè))作為一個(gè)客戶端應(yīng)用程序的一部分,我們可以使用WebView。WebView類是Android中View類的擴(kuò)展,它允許我們將網(wǎng)頁(yè)作為我們布局的一部分進(jìn)行展示。它不包含非常完善的web瀏覽器所具備的任何特性,比如導(dǎo)航控件或一個(gè)地址欄。WebView默認(rèn)能做的是顯示一個(gè)網(wǎng)頁(yè)。

一個(gè)常見的場(chǎng)景,比如我們想要在應(yīng)用程序中展示一些信息,這些需要更新,如一個(gè)終端用戶協(xié)議或用戶指南,此時(shí)使用WebView是有益的。我們可以創(chuàng)建一個(gè)僅含有一個(gè)WebView的Activity來(lái)展示在線托管的文檔。

另一個(gè)場(chǎng)景,如果我們的應(yīng)用提供給用戶的數(shù)據(jù)總是需要一個(gè)網(wǎng)絡(luò)連接來(lái)檢索數(shù)據(jù),比如郵件,此時(shí)使用WebView是有用的。我們將會(huì)發(fā)現(xiàn)在應(yīng)用中使用WebView來(lái)顯示用戶的所有數(shù)據(jù)比執(zhí)行一個(gè)網(wǎng)絡(luò)請(qǐng)求、解析數(shù)據(jù)、布局展示更加簡(jiǎn)單方便。我們可以為Android設(shè)備設(shè)計(jì)一個(gè)網(wǎng)頁(yè),然后在Android應(yīng)用中實(shí)現(xiàn)一個(gè)WebView中加載這個(gè)網(wǎng)頁(yè)。

向應(yīng)用中添加一個(gè)WebView

1.布局中添加WebView

2.代碼中找到WebView,并以u(píng)rl為參數(shù)調(diào)用WebView對(duì)象的loadUrl()方法

3.添加網(wǎng)絡(luò)權(quán)限

在WebView中使用JavaScript

如果要加載的網(wǎng)頁(yè)使用到的JavaScript,我們必須使WebView啟用JavaScript。一旦JavaScript被啟用,我們可以在我們的應(yīng)用代碼和JavaScript代碼之間創(chuàng)建接口。

啟用JavaScript

WebView默認(rèn)禁用JavaScript。我們可以通過WebView的WebSettings來(lái)啟用它。我們可以通過getSettings()方法來(lái)獲取WebSettings,然后通過setJavaScriptEnabled()方法來(lái)啟用它。

例如:

WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);

WebSettings提供了大量非常有用的其他設(shè)置。例如,如果我們開發(fā)一個(gè)Web應(yīng)用程序,它被設(shè)計(jì)為僅用WebView,我們可以通過setUserAgentString()方法定義一個(gè)用戶代理字符串,然后在網(wǎng)頁(yè)中查詢這個(gè)用戶代理字符串,來(lái)驗(yàn)證用戶請(qǐng)求網(wǎng)頁(yè)實(shí)際是請(qǐng)求我們的Android應(yīng)用。

JavaScript代碼綁定到Android代碼

我們可以在JavaScript代碼和客戶端的Android代碼之間創(chuàng)建一個(gè)接口,例如我們的JavaScript代碼可以調(diào)用我們的Android代碼來(lái)顯示一個(gè)Dialog,而不是使用JavaScript的alert()方法。

在二者之間綁定接口需要調(diào)用addJavascriptInterface()方法,傳遞給這個(gè)方法一個(gè)類的實(shí)例來(lái)綁定到JavaScript,再傳遞一個(gè)接口名,讓我們的JavaScript可以調(diào)用獲取到這個(gè)類。

例如,在Android代碼中有如下一個(gè)類:

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是17或更高,必須在JavaScript可以調(diào)用的方法上添加@JavascriptInterface注解,該方法也必須使公有的。若不添加,Android 4.2或更高設(shè)備上該方法將無(wú)法執(zhí)行。

WebAppInterface類允許網(wǎng)頁(yè)使用showToast()方法來(lái)創(chuàng)建一個(gè)吐司信息。我們可以如下將該類綁定至JavaScript。

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

這為JavaScript創(chuàng)建了一個(gè)名為Android的接口,此時(shí),我們的web應(yīng)用可以獲取WebAppInterface類了。例如,下面的HTML和JavaScript當(dāng)用戶點(diǎn)擊按鈕的時(shí)候使用這個(gè)新接口創(chuàng)建了一個(gè)吐司信息。

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>

在JavaScript中不需要初始化這個(gè)接口,WebView自動(dòng)使它可用于您的web頁(yè)面。

提示:綁定在JavaScript的對(duì)象運(yùn)行在其他線程,而不再它被構(gòu)造的線程。

注意:使用addJavascriptInterface()方法允許JavaScript控制我們的Android應(yīng)用,它非常有用但也產(chǎn)生了嚴(yán)重的安全問題。例如在WebView中的HTML是不可靠的(例如HTML的一部分或所有由未知的人或進(jìn)程提供),然后攻擊者可以執(zhí)行你的包括HTML客戶端代碼,并且可能選擇攻擊任意代碼。就此,我們不應(yīng)該使用addJavascriptInterface()方法,除非我們寫的所有HTML和JavaScript出現(xiàn)在我們的WebView中。我們也不應(yīng)該允許用戶在我們的WebView中導(dǎo)航至那些不屬于我們的網(wǎng)頁(yè)中(相反,默認(rèn)允許用戶的默認(rèn)瀏覽器應(yīng)用打開外部鏈接,用戶的網(wǎng)頁(yè)瀏覽器打開所有的URL鏈接)。

處理頁(yè)面導(dǎo)航

當(dāng)用戶在我們的WebView中點(diǎn)擊一個(gè)鏈接的時(shí)候,默認(rèn)處理方式是Android運(yùn)行一個(gè)應(yīng)用來(lái)處理所有的URLs。通常,是默認(rèn)網(wǎng)頁(yè)瀏覽器來(lái)打開和加載這個(gè)目標(biāo)URL。然而,我們?cè)赪ebView中可以復(fù)寫這個(gè)行為,使得鏈接在我們的WebView中打開。然后我們?cè)试S用戶在WebView中通過網(wǎng)頁(yè)歷史來(lái)前后導(dǎo)航至某一網(wǎng)頁(yè)。

為了打開用戶點(diǎn)擊的鏈接,僅需調(diào)用setWebViewClient()方法為WebView提供一個(gè)WebViewClient,如下:

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

就是這樣,然后我們的WebView就可以加載所有用戶點(diǎn)的鏈接了。

如果我們想要更多地控制被點(diǎn)擊的鏈接,需要通過繼承自定義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)建一個(gè)新的WebViewClient對(duì)象:

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

現(xiàn)在當(dāng)用戶點(diǎn)擊一個(gè)鏈接時(shí),系統(tǒng)調(diào)用shouldOverrideUrlLoading()方法,來(lái)檢查這個(gè)URL的主機(jī)地址是否匹配代碼中指定的域名。如果匹配,這個(gè)方法將返回false(通常允許WebView加載這個(gè)網(wǎng)頁(yè))。如果不匹配,創(chuàng)建一個(gè)Intent來(lái)啟動(dòng)默認(rèn)Activity來(lái)處理URL。

瀏覽網(wǎng)頁(yè)的歷史

讓我們的WebView重復(fù)加載了多個(gè)URL,它自動(dòng)地累積瀏覽過的歷史,我們可以可以通過goBack()goForward()方法來(lái)前進(jìn)或者后退這些歷史網(wǎng)頁(yè)。

如下展示了在Activity中使用設(shè)備返回鍵來(lái)回退歷史網(wǎng)頁(yè):

@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);
}

Android 4.4的WebView(需要注意的地方)

Android4.4引進(jìn)了全新的基于Chrominum的WebView。這個(gè)變化升級(jí)了WebView的性能。所有的在Android4.4或更高版本的Android設(shè)備使用WebView的Apps將繼承這些優(yōu)化。

調(diào)試Web Apps

開發(fā)Web Apps的一些建議

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

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

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