有關WebView的一些使用方法
Android系統中內建了一款高效能 webkit 核心瀏覽器,在 SDK 中封裝為一個叫做 WebView 元件。
在開發過程中應該注意幾點:
1.這是最基本的 AndroidManifest.xml 中必須新增訪問網路許可權。
2.如果訪問的頁面中有 Javascript,則 WebView 必須設定支援 Javascript。
WebView.getSettings().setJavaScriptEnabled(true);
3.如果頁面中連結,如果希望點選連結繼續在當前browser中響應,而不是新開Android的系統browser中響應該連結,必須覆蓋 WebView的WebViewClient物件。
mWebView.setWebViewClient(new WebViewClient(){ public boolean shouldOverrideUrlLoading(WebView view, String url){ view.loadUrl(url); return true; } });
4.如果不做任何處理 ,瀏覽網頁,點選系統“Back”鍵,整個 Browser 會呼叫 finish()而結束自身,如果希望瀏覽的網頁回退而不是推出瀏覽器,需要在當前Activity中處理並消費掉該 Back 事件
public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) { mWebView.goBack(); return true; } return super.onKeyDown(keyCode, event); }
與js互調
既然可以顯示網頁,那麼當然也可以讓網頁操作本地方法。(由於一行寫不下,縮排我調整了一下)
public class WebViewDemo extends Activity { private WebView mWebView; private Handler mHandler = new Handler(); public void onCreate(Bundle icicle) { setContentView(R.layout.WebViewdemo); mWebView = (WebView) findViewById(R.id.WebView); WebSettings webSettings = mWebView.getSettings(); webSettings.setJavaScriptEnabled(true); mWebView.addJavascriptInterface(new Object() { public void clickOnAndroid() { mHandler.post(new Runnable() { public void run() { mWebView.loadUrl("javascript:wave()"); } }); } }, "demo"); mWebView.loadUrl("file:///android_asset/demo.html"); } }
我們看 addJavascriptInterface(Object obj,String interfaceName)這個方法 ,該方法將一個java物件繫結到一個javascript物件中,javascript物件名就是 interfaceName(demo),作用域是Global.這樣初始化 WebView 後,在WebView載入的頁面中就可以直接通過javascript:window.demo訪問到繫結的java物件了. 來看看在html中是怎樣呼叫的.
<html> <script language="javascript"> function wave() { document.getElementById("droid").src="android_waving.png"; } </script> <body> <a onClick="window.demo.clickOnAndroid()"> <img id="droid" src="android_normal.png" mce_src="android_normal.png"/><br> Click me! </a> </body> </html>
這樣在 javascript 中就可以呼叫 java 物件的 clickOnAndroid()方法了,同樣我們可以在此物件中定義很多方法(比如發簡訊,呼叫聯絡人列表等手機系統功能),這裡 wave()方法是 java 中呼叫 javascript 的例子.
需要說明一點:addJavascriptInterface方法中要繫結的Java物件及方法要執行另外的執行緒中,不能執行在構造他的執行緒中,這也是使用 Handler 的目的.
讓js呼叫Android程式碼
首先簡述 WebView、WebViewClient、WebChromeClient 之間的區別:
在 WebView 的設計中,不是什麼事都要 WebView類乾的,有些雜事是分給其他人的,這樣 WebView 專心幹好 自己的解析、渲染工作就行了.WebViewClient 就是幫助 WebView 處理各種通知、請求事件等 ,WebChromeClient 是輔助 WebView 處理 Javascript 的對話方塊,網站圖示,網站 title.
功能實現:
利用 android 中的 WebView 載入一個 html 網頁,在 html 網頁中定義一個按鈕,點選按鈕彈出一 個 toast.
實現步驟:
首先定義一個介面類,將上下文物件傳進去,在介面類中定義要在 js 中實現的方法。
接著在assets資源包下定義一個 html 檔案,在檔案中定義一個 button.button 的點選事件定義為一個 js 函式.
之後在 xml 中定義一個 WebView 元件,在活動類中獲取 WebView 並對 WebView 引數進行設定,此處特別注意要設定 WebView 支援 js 且將定義的 js 介面類新增到 WebView 中去,此後在 js 中就可以利用該介面類中定義的 函數了.即:
myWebView.getSettings().setJavaScriptEnabled(true); myWebView.addJavascriptInterface(new JavaScriptinterface(this),”android”);
最後利用 WebView 載入本地 html 檔案的方法是:
myWebView.loadData(htmlText,"text/html", "utf-8");
此處的htmltext 是以字串的方式讀取 assets 報下 html中的內容.
實現利用返回鍵返回到上一頁:
設定 WebView 的按鍵監聽,監聽到期返回鍵並判斷網頁是否能夠返回 ,利用 WebView 的 goBack()返回到上一頁.
WebView 快取
在專案中如果使用到 WebView 控制元件,當載入 html 頁面時,會在/data/data/包名目錄下生成 database 與 cache 兩個資料夾。
請求的 url 記錄是儲存在 WebViewCache.db,而 url 的內容是儲存在 WebViewCache 資料夾下. 大家可以自己動手試一下,定義一個html檔案,在裡面顯示一張圖片,用WebView加載出來,然後再試著從快取裡把這張圖片讀取出來並顯示 。
WebView 刪除快取
其實已經知道快取儲存的位置了,那麼刪除就很簡單了,獲取到這個快取,然後刪掉他就好了。
//刪除保存於手機上的快取 private int clearCacheFolder(File dir,long numDays) { int deletedFiles = 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(); } } return deletedFiles; }
是否啟用快取功能也是可以控制的
//優先使用快取: WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //不使用快取: WebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
在退出應用的時候加上如下程式碼,可以完整的清空快取
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 錯誤
顯示網頁還會遇到一個問題,就是網頁有可能會找不到,WebView當然也是可以處理的
public class WebView_404 extends Activity { private Handler handler = new Handler() { public void handleMessage(Message msg) { if(msg.what==404) {//主頁不存在 //載入本地 assets 資料夾下面的錯誤提示頁面 404.html web.loadUrl("file:///android_asset/404.html"); }else{ web.loadUrl(HOMEPAGE); } } }; @Override protected void onCreate(Bundle savedInstanceState) { web.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrl(WebView view,String url) { if(url.startsWith("http://") && getRespStatus(url)==404) { view.stopLoading(); //載入本地 assets 資料夾下面的錯誤提示頁面 404.html view.loadUrl("file:///android_asset/404.html"); }else{ view.loadUrl(url); } return true; } }); new Thread(new Runnable() { public void run() { Message msg = new Message(); //此處判斷主頁是否存在,因為主頁是通過 loadUrl 載入的, //此時不會執行 shouldOverrideUrlLoading 進行頁面是否存在的判斷 //進入主頁後,點主頁裡面的連結,連結到其他頁面就一定會執行 shouldOverrideUrlLoading 方法了 if(getRespStatus(HOMEPAGE)==404) { msg.what = 404; } handler.sendMessage(msg); }).start(); } }
判斷 WebView 是否已經滾動到頁面底端
在View中有一個getScrollY()方法,可以返回當前可見區域的頂端距整個頁面頂端的距離,也就是當前內容滾動的距離。
還有getHeight()或者 getBottom()方法都返回當前 View 這個容器的高度
在ViewView中還有getContentHeight() 方法可以返回整個 html 頁面的高度,但並不等同於當前整個頁面的高度 ,因為 WebView 有縮放功能。你可以通過如下程式碼來啟動或關閉webview的縮放功能。
mWebView.getSettings().setSupportZoom(true); mWebView.getSettings().setBuiltInZoomControls(true);
所以當前整個頁面的高度實際上應該是原始 html 的高度再乘上縮放比例. 因此,更正後的結果 ,準確的判斷方法應該是:
// 如果已經處於底端 if(WebView.getContentHeight*WebView.getScale() -(webvi ew.getHeight()+WebView.getScrollY())){ //XXX }
WebView獲取伺服器中的 session 問題
接下來我們講如下兩個問題:
Android 中的 WebView 如何獲取伺服器頁面的 jsessionid 的值
Android 的 WebView 又是如何把得到的 jsessionid 的值在 set 到伺服器中,一致達到他們在同一個 jsessionid 的回話中.
其實非常非常簡單,只不過是幾個方法罷了:
CookieManager cm = CookieManager.getInstance(); cm.removeAllCookie(); cm.getCookie(url); cm.setCookie(url, cookie);
另外還有個 CookieSyncManager,也許你會在一些舊的專案中看到它。從名字來理解,它實際上應該是一個非同步快取器。不過我們看到這個方法已經被標記為過時了,檢視原始碼可以看到過時原因是現在WebView已經是自動的非同步快取了,所以這個類已經沒有存在的意義了。 CookieSyncManager
WebView清除本地cookies
首先,要清除肯定要會新增,這裡給大家提供一個工具方法:
/*** * 如果使用者已經登入,則同步本地的cookie到webview中 */ public void synCookies() { 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(); }
在使用網頁版淘寶或百度登入時,WebView會自動登入上次的帳號!(因為WebView 記錄了帳號和密碼的cookies) 所以,需要清除 SessionCookie也是有必要的。
那麼CookieManager同樣也為我們提供了清除cookie的方法
CookieManager.getInstance().removeSessionCookie();
這裡順便說一下WebView本身也是會記錄html快取的,webview本身就提供了清理快取的方法,其中引數true是指是否包括磁碟檔案也一併清除:
webview.clearCache(true); webview.clearHistory();