您好,歡迎來(lái)電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>數(shù)值算法/人工智能>

深入理解WebView

大?。?/span>0.6 MB 人氣: 2017-10-11 需要積分:1
摘要
  作為Android開發(fā)者,我們都知道在手機(jī)中內(nèi)置了一款高性能 webkit 內(nèi)核瀏覽器,在 SDK 中封裝為一個(gè)叫做 WebView 組件。今天就為大家講講Android中WebView的詳細(xì)使用方法。
  作為Android開發(fā)者,我們都知道在手機(jī)中內(nèi)置了一款高性能 webkit 內(nèi)核瀏覽器,在 SDK 中封裝為一個(gè)叫做 WebView 組件。
  在開發(fā)過(guò)程中應(yīng)該注意幾點(diǎn):
  1.這是最基本的 AndroidManifest.xml 中必須添加訪問(wèn)網(wǎng)絡(luò)權(quán)限。
  2.如果訪問(wèn)的頁(yè)面中有 Java,則 WebView 必須設(shè)置支持 Java。
  WebView.getSettings().setJavaEnabled(true);
  3.如果頁(yè)面中鏈接,如果希望點(diǎn)擊鏈接繼續(xù)在當(dāng)前browser中響應(yīng),而不是新開Android的系統(tǒng)browser中響應(yīng)該鏈接,必須覆蓋 WebView的WebViewClient對(duì)象。
  mWebView.setWebViewClient(newWebViewClient(){ publicbooleanshouldOverrideUrlLoading(WebView view, String url){ view.loadUrl(url); returntrue; } });
  4.如果不做任何處理 ,瀏覽網(wǎng)頁(yè),點(diǎn)擊系統(tǒng)“Back”鍵,整個(gè) Browser 會(huì)調(diào)用 finish()而結(jié)束自身,如果希望瀏覽的網(wǎng)頁(yè)回退而不是推出瀏覽器,需要在當(dāng)前Activity中處理并消費(fèi)掉該 Back 事件。(代碼有些精簡(jiǎn))
  publicboolean onKeyDown(intkeyCode, KeyEvent event) { if((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) { mWebView.goBack(); returntrue; } returnsuper.onKeyDown(keyCode, event); }
  與js互調(diào)
  既然可以顯示網(wǎng)頁(yè),那么當(dāng)然也可以讓網(wǎng)頁(yè)操作本地方法。(由于一行寫不下,縮進(jìn)我調(diào)整了一下)
  publicclassWebViewDemoextendsActivity{privateWebView mWebView; privateHandler mHandler = newHandler(); publicvoidonCreate(Bundle icicle) { setContentView(R.layout.WebViewdemo); mWebView = (WebView) findViewById(R.id.WebView); WebSettings webSettings = mWebView.getSettings(); webSettings.setJavaEnabled(true); mWebView.addJavaInterface(newObject() { publicvoidclickOnAndroid() { mHandler.post(newRunnable() { publicvoidrun() { mWebView.loadUrl(“java:wave()”); } }); } }, “demo”); mWebView.loadUrl(“file:///android_asset/demo.html”); } }
  我們看 addJavaInterface(Object obj,String interfaceName)這個(gè)方法 ,該方法將一個(gè)java對(duì)象綁定到一個(gè)java對(duì)象中,java對(duì)象名就是 interfaceName(demo),作用域是Global.這樣初始化 WebView 后,在WebView加載的頁(yè)面中就可以直接通過(guò)java:window.demo訪問(wèn)到綁定的java對(duì)象了。 來(lái)看看在html中是怎樣調(diào)用的。
  《html》《language=“java”》functionwave(){document.getElementById(“droid”).src=“android_waving.png”; } 《/》《body》《aonClick=“window.demo.clickOnAndroid()”》《imgid=“droid”src=“android_normal.png”mce_src=“android_normal.png”/》《br》Click me! 《/a》《/body》《/html》
  這樣在 java 中就可以調(diào)用 java 對(duì)象的 clickOnAndroid()方法了,同樣我們可以在此對(duì)象中定義很多方法(比如發(fā)短信,調(diào)用聯(lián)系人列表等手機(jī)系統(tǒng)功能),這里 wave()方法是 java 中調(diào)用 java 的例子。
  需要說(shuō)明一點(diǎn):addJavaInterface方法中要綁定的Java對(duì)象及方法要運(yùn)行另外的線程中,不能運(yùn)行在構(gòu)造他的線程中,這也是使用 Handler 的目的。
  深入使用WebView
  讓js調(diào)用Android代碼
  首先簡(jiǎn)述 WebView、WebViewClient、WebChromeClient 之間的區(qū)別:
  在 WebView 的設(shè)計(jì)中,不是什么事都要 WebView類干的,有些雜事是分給其他人的,這樣 WebView 專心干好 自己的解析、渲染工作就行了.WebViewClient 就是幫助 WebView 處理各種通知、請(qǐng)求事件等 ,WebChromeClient 是輔助 WebView 處理 Java 的對(duì)話框,網(wǎng)站圖標(biāo),網(wǎng)站 title.
  功能實(shí)現(xiàn):
  利用 android 中的 WebView 加載一個(gè) html 網(wǎng)頁(yè),在 html 網(wǎng)頁(yè)中定義一個(gè)按鈕,點(diǎn)擊按鈕彈出一 個(gè) toast.
  實(shí)現(xiàn)步驟:
  首先定義一個(gè)接口類,將上下文對(duì)象傳進(jìn)去,在接口類中定義要在 js 中實(shí)現(xiàn)的方法。
  接著在assets資源包下定義一個(gè) html 文件,在文件中定義一個(gè) button.button 的點(diǎn)擊事件定義為一個(gè) js 函數(shù)。
  之后在 xml 中定義一個(gè) WebView 組件,在活動(dòng)類中獲取 WebView 并對(duì) WebView 參數(shù)進(jìn)行設(shè)置,此處特別注意要設(shè)置 WebView 支持 js 且將定義的 js 接口類添加到 WebView 中去,此后在 js 中就可以利用該接口類中定義的 函數(shù)了。即:
  myWebView.getSettings().setJavaEnabled(true); myWebView.addJavaInterface(newJavainterface(this),”android”);
  最后利用 WebView 加載本地 html 文件的方法是:
  myWebView.loadData(htmlText,“text/html”, “utf-8”);
  此處的htmltext 是以字符串的方式讀取 assets 報(bào)下 html中的內(nèi)容。
  4.實(shí)現(xiàn)利用返回鍵返回到上一頁(yè):
  設(shè)置 WebView 的按鍵監(jiān)聽(tīng),監(jiān)聽(tīng)到期返回鍵并判斷網(wǎng)頁(yè)是否能夠返回 ,利用 WebView 的 goBack()返回到上一頁(yè)。
  WebView 緩存
  在項(xiàng)目中如果使用到 WebView 控件,當(dāng)加載 html 頁(yè)面時(shí),會(huì)在/data/data/包名目錄下生成 database 與 cache 兩個(gè)文件夾(我的手機(jī)沒(méi)有root,就不截圖了)。
  請(qǐng)求的 url 記錄是保存在 WebViewCache.db,而 url 的內(nèi)容是保存在 WebViewCache 文件夾下。 大家可以自己動(dòng)手試一下,定義一個(gè)html文件,在里面顯示一張圖片,用WebView加載出來(lái),然后再試著從緩存里把這張圖片讀取出來(lái)并顯示 。
  WebView 刪除緩存
  其實(shí)已經(jīng)知道緩存保存的位置了,那么刪除就很簡(jiǎn)單了,獲取到這個(gè)緩存,然后刪掉他就好了。
  //刪除保存于手機(jī)上的緩存privateintclearCacheFolder(File dir,longnumDays) { intdeletedFiles = 0; if(dir!= null&& dir.isDirectory()){ try{ for(File child:dir.listFiles()){ if(child.isDirectory()) { deletedFiles += clearCacheFolder(child, numDays); } if(child.lastModified() 《 numDays) { if(child.delete()) { deletedFiles++; } } } } catch(Exception e) { e.printStackTrace(); } } returndeletedFiles; }
  是否啟用緩存功能也是可以控制的
  //優(yōu)先使用緩存: WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //不使用緩存: WebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
  在退出應(yīng)用的時(shí)候加上如下代碼,可以完整的清空緩存
  File file= CacheManager.getCacheFileBaseDir(); if(file!= null && file.exists() && file.isDirectory()) { for(File item : file.listFiles()) { item.delete(); } file.delete(); } context.deleteDatabase(“WebView.db”); context.deleteDatabase(“WebViewCache.db”);
  WebView 處理 404 錯(cuò)誤
  顯示網(wǎng)頁(yè)還會(huì)遇到一個(gè)問(wèn)題,就是網(wǎng)頁(yè)有可能會(huì)找不到,WebView當(dāng)然也是可以處理的(代碼如果全部貼出來(lái)實(shí)在太多了,這里就只貼重要部分了)
  publicclassWebView_404extendsActivity{privateHandler handler = newHandler() { publicvoidhandleMessage(Message msg) { if(msg.what==404) {//主頁(yè)不存在//載入本地 assets 文件夾下面的錯(cuò)誤提示頁(yè)面 404.html web.loadUrl(“file:///android_asset/404.html”); }else{ web.loadUrl(HOMEPAGE); } } }; @OverrideprotectedvoidonCreate(Bundle savedInstanceState) { web.setWebViewClient(newWebViewClient() { publicbooleanshouldOverrideUrl(WebView view,String url) { if(url.startsWith(“http://”) && getRespStatus(url)==404) { view.stopLoading(); //載入本地 assets 文件夾下面的錯(cuò)誤提示頁(yè)面 404.html view.loadUrl(“file:///android_asset/404.html”); }else{ view.loadUrl(url); } returntrue; } }); newThread(newRunnable() { publicvoidrun() { Message msg = newMessage(); //此處判斷主頁(yè)是否存在,因?yàn)橹黜?yè)是通過(guò) loadUrl 加載的,//此時(shí)不會(huì)執(zhí)行 shouldOverrideUrlLoading 進(jìn)行頁(yè)面是否存在的判斷 //進(jìn)入主頁(yè)后,點(diǎn)主頁(yè)里面的鏈接,鏈接到其他頁(yè)面就一定會(huì)執(zhí)行shouldOverrideUrlLoading 方法了 if(getRespStatus(HOMEPAGE)==404) { msg.what = 404; } handler.sendMessage(msg); }).start(); } }
  判斷 WebView 是否已經(jīng)滾動(dòng)到頁(yè)面底端
  在View中有一個(gè)getScrollY()方法,可以返回當(dāng)前可見(jiàn)區(qū)域的頂端距整個(gè)頁(yè)面頂端的距離,也就是當(dāng)前內(nèi)容滾動(dòng)的距離。
  還有g(shù)etHeight()或者 getBottom()方法都返回當(dāng)前 View 這個(gè)容器的高度
  在ViewView中還有g(shù)etContentHeight() 方法可以返回整個(gè) html 頁(yè)面的高度,但并不等同于當(dāng)前整個(gè)頁(yè)面的高度 ,因?yàn)?WebView 有縮放功能。你可以通過(guò)如下代碼來(lái)啟動(dòng)或關(guān)閉webview的縮放功能。
  mWebView.getSettings().setSupportZoom(true);mWebView.getSettings().setBuiltInZoomControls(true);
  所以當(dāng)前整個(gè)頁(yè)面的高度實(shí)際上應(yīng)該是原始 html 的高度再乘上縮放比例。 因此,更正后的結(jié)果 ,準(zhǔn)確的判斷方法應(yīng)該是:
  // 如果已經(jīng)處于底端if(WebView.getContentHeight*WebView.getScale()-(webvi ew.getHeight()+WebView.getScrollY())){ //XXX}
  WebView獲取服務(wù)器中的 session 問(wèn)題
  接下來(lái)我們講如下兩個(gè)問(wèn)題:
  Android 中的 WebView 如何獲取服務(wù)器頁(yè)面的 jsessionid 的值A(chǔ)ndroid 的 WebView 又是如何把得到的 jsessionid 的值在 set 到服務(wù)器中,一致達(dá)到他們?cè)谕粋€(gè) jsessionid 的回話中。
  其實(shí)非常非常簡(jiǎn)單,只不過(guò)是幾個(gè)方法罷了:
  CookieManager cm = CookieManager.getInstance(); cm.removeAllCookie();cm.getCookie(url);cm.setCookie(url, cookie);
  另外還有個(gè) CookieSyncManager,也許你會(huì)在一些舊的項(xiàng)目中看到它。從名字來(lái)理解,它實(shí)際上應(yīng)該是一個(gè)異步緩存器。不過(guò)我們看到這個(gè)方法已經(jīng)被標(biāo)記為過(guò)時(shí)了,查看源碼可以看到過(guò)時(shí)原因是現(xiàn)在WebView已經(jīng)是自動(dòng)的異步緩存了,所以這個(gè)類已經(jīng)沒(méi)有存在的意義了。 CookieSyncManager
  WebView清除本地cookies
  首先,要清除肯定要會(huì)添加,這里給大家提供一個(gè)工具方法:
  /*** * 如果用戶已經(jīng)登錄,則同步本地的cookie到webview中 */publicvoidsynCookies() { if(!CacheUtils.isLogin(this)) return; CookieSyncManager.createInstance(this); CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true); cookieManager.removeSessionCookie();//移除String cookies = PreferenceHelper.readString(this, AppConfig.COOKIE_KEY, AppConfig.COOKIE_KEY); KJLoger.debug(cookies); cookieManager.setCookie(url, cookies); CookieSyncManager.getInstance().sync(); }
  在使用網(wǎng)頁(yè)版淘寶或百度登錄時(shí),WebView會(huì)自動(dòng)登錄上次的帳號(hào)?。ㄒ?yàn)閃ebView 記錄了帳號(hào)和密碼的cookies) 所以,需要清除 SessionCookie也是有必要的。
  那么CookieManager同樣也為我們提供了清除cookie的方法
  CookieManager.getInstance().removeSessionCookie();
  這里順便說(shuō)一下WebView本身也是會(huì)記錄html緩存的,上一篇博客中我講了一種通過(guò)文件操作去清理緩存的方法,后來(lái)我又發(fā)現(xiàn),其實(shí)webview本身就提供了清理緩存的方法,其中參數(shù)true是指是否包括磁盤文件也一并清除,傳true就和我們昨天的講的效果是一樣的了:
  webview.clearCache(true);webview.clearHistory();
  講一個(gè)案例
  講了這么多的理論知識(shí),最后講一個(gè)使用案例。WebView在實(shí)際使用中可以分為兩種使用方法,第一種就是類似于QQ微信那種,使用loadUrl直接去顯示一個(gè)鏈接,這種方式太簡(jiǎn)單了,傳一個(gè)url就行,我就不多說(shuō)了。
  那么需要詳細(xì)講的是第二種,類似的實(shí)現(xiàn)大家可以看看開源中國(guó)客戶端,網(wǎng)易新聞客戶端,愛(ài)看博客,等客戶端的實(shí)現(xiàn)方式,它們實(shí)際上也是通過(guò)webview來(lái)顯示的一個(gè)網(wǎng)頁(yè)內(nèi)容,但是并不是單純的loadurl,而是以字符串的形式去加載一個(gè)已經(jīng)獲取到了的html源代碼。這樣做的好處在于顯示的頁(yè)面可以完全的根據(jù)自己喜好來(lái)定義,比如我想在末尾添加一張圖片,那么簡(jiǎn)單,在這個(gè)html字符串的末尾插入一個(gè)img標(biāo)簽就可了。至于使用方法,其實(shí)我們?cè)谏弦黄┛偷臅r(shí)候有提到過(guò):
  myWebView.loadData(htmlText,”text/html”, “utf-8”);
  其中htmltext就是我們需要加載的html字符串,使用這個(gè)方法可以直接將這個(gè)字符串作為網(wǎng)頁(yè)來(lái)顯示。
  最后總結(jié)一下兩種方法的適用場(chǎng)景,前一種載入鏈接的方法適合一個(gè)界面(Activity或Fragment)只有一個(gè)WebView或者說(shuō)WebView占很大一塊的時(shí)候,同時(shí)我們要顯示的內(nèi)容是未知的,那么自然是使用loadurl方法更合適,例如QQ聊天的時(shí)候?qū)Ψ桨l(fā)送一條鏈接,當(dāng)QQ解析出這個(gè)文本是一個(gè)網(wǎng)址時(shí)就通過(guò)webview去加載它。而后一種則適合于定制化內(nèi)容,一般是那種你可以明確的制度網(wǎng)頁(yè)內(nèi)容以及要顯示的內(nèi)容時(shí)使用,至于好處就是上面說(shuō)的,定制性要好很多。
?

非常好我支持^.^

(0) 0%

不好我反對(duì)

(0) 0%

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?