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)頁在所有屏幕配置上都能夠呈現(xiàn)出合適的尺寸和大小。

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

使Web Apps支持不同的屏幕

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

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

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

屏幕密度:Web類和Android大部分的網(wǎng)頁瀏覽器將CSS像素值轉(zhuǎn)換為獨(dú)立設(shè)備像素值。因此一個(gè)網(wǎng)頁在中等密度的屏幕上(160dpi)呈現(xiàn)出相同的可感知尺寸嵌削。如果圖形是我們網(wǎng)頁設(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)頁)作為一個(gè)客戶端應(yīng)用程序的一部分,我們可以使用WebView。WebView類是Android中View類的擴(kuò)展艇劫,它允許我們將網(wǎng)頁作為我們布局的一部分進(jìn)行展示吼驶。它不包含非常完善的web瀏覽器所具備的任何特性,比如導(dǎo)航控件或一個(gè)地址欄。WebView默認(rèn)能做的是顯示一個(gè)網(wǎng)頁店煞。

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

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

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

1.布局中添加WebView

2.代碼中找到WebView膏秫,并以url為參數(shù)調(diào)用WebView對象的loadUrl()方法

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

在WebView中使用JavaScript

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

啟用JavaScript

WebView默認(rèn)禁用JavaScript吹榴。我們可以通過WebView的WebSettings來啟用它亭敢。我們可以通過getSettings()方法來獲取WebSettings,然后通過setJavaScriptEnabled()方法來啟用它图筹。

例如:

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)頁中查詢這個(gè)用戶代理字符串,來驗(yàn)證用戶請求網(wǎng)頁實(shí)際是請求我們的Android應(yīng)用锥余。

JavaScript代碼綁定到Android代碼

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

在二者之間綁定接口需要調(diào)用addJavascriptInterface()方法嘲恍,傳遞給這個(gè)方法一個(gè)類的實(shí)例來綁定到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è)備上該方法將無法執(zhí)行。

WebAppInterface類允許網(wǎng)頁使用showToast()方法來創(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頁面遥皂。

提示:綁定在JavaScript的對象運(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)頁中(相反贬芥,默認(rèn)允許用戶的默認(rèn)瀏覽器應(yīng)用打開外部鏈接宣决,用戶的網(wǎng)頁瀏覽器打開所有的URL鏈接)尊沸。

處理頁面導(dǎo)航

當(dāng)用戶在我們的WebView中點(diǎn)擊一個(gè)鏈接的時(shí)候,默認(rèn)處理方式是Android運(yùn)行一個(gè)應(yīng)用來處理所有的URLs洼专。通常壶熏,是默認(rèn)網(wǎng)頁瀏覽器來打開和加載這個(gè)目標(biāo)URL棒假。然而帽哑,我們在WebView中可以復(fù)寫這個(gè)行為妻枕,使得鏈接在我們的WebView中打開。然后我們允許用戶在WebView中通過網(wǎng)頁歷史來前后導(dǎo)航至某一網(wǎng)頁蝌数。

為了打開用戶點(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對象:

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

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

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

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

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

@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è)變化升級了WebView的性能居扒。所有的在Android4.4或更高版本的Android設(shè)備使用WebView的Apps將繼承這些優(yōu)化丑慎。

調(diào)試Web Apps

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市玉吁,隨后出現(xiàn)的幾起案子照弥,更是在濱河造成了極大的恐慌,老刑警劉巖进副,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件这揣,死亡現(xiàn)場離奇詭異,居然都是意外死亡敢会,警方通過查閱死者的電腦和手機(jī)曾沈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸥昏,“玉大人塞俱,你說我怎么就攤上這事±艨澹” “怎么了障涯?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長膳汪。 經(jīng)常有香客問我唯蝶,道長,這世上最難降的妖魔是什么遗嗽? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任粘我,我火速辦了婚禮,結(jié)果婚禮上痹换,老公的妹妹穿的比我還像新娘征字。我一直安慰自己,他們只是感情好娇豫,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布匙姜。 她就那樣靜靜地躺著,像睡著了一般冯痢。 火紅的嫁衣襯著肌膚如雪氮昧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天浦楣,我揣著相機(jī)與錄音袖肥,去河邊找鬼。 笑死椒振,一個(gè)胖子當(dāng)著我的面吹牛昭伸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播澎迎,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼庐杨,長吁一口氣:“原來是場噩夢啊……” “哼选调!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起灵份,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤仁堪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后填渠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弦聂,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年氛什,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了莺葫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,687評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡枪眉,死狀恐怖捺檬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贸铜,我是刑警寧澤堡纬,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布,位于F島的核電站蒿秦,受9級特大地震影響烤镐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜棍鳖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一繁莹、第九天 我趴在偏房一處隱蔽的房頂上張望及刻。 院中可真熱鬧克婶,春花似錦绿映、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽川尖。三九已至登下,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叮喳,已是汗流浹背被芳。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留馍悟,地道東北人畔濒。 一個(gè)月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像锣咒,于是被迫代替她去往敵國和親侵状。 傳聞我的和親對象是個(gè)殘疾皇子赞弥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評論 2 349

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