1. 程式人生 > >Android webView 快取 Cache + HTML5離線功能解決

Android webView 快取 Cache + HTML5離線功能解決

WebView的快取可以分為頁面快取和資料快取。

           頁面快取是指載入一個網頁時的html、JS、CSS等頁面或者資源資料。這些快取資源是由於瀏覽器的行為而產生,開發者只能通過配置HTTP響應頭影響瀏覽器的行為才能間接地影響到這些快取資料。

         他們的索引存放在/data/data/package_name/databases下。他們的檔案存放在/data/data/package_name/cache/xxxwebviewcachexxx下。資料夾的名字在2.x和4.x上有所不同,但都資料夾名字中都包含webviewcache。



            資料快取分為兩種:AppCache和DOM Storage(Web Storage)。他們是因為頁面開發者的直接行為而產生。所有的快取資料都由開發者直接完全地掌控。

AppCache使我們能夠有選擇的緩衝web瀏覽器中所有的東西,從頁面、圖片到指令碼、css等等。尤其在涉及到應用於網站的多個頁面上的CSS和JavaScript檔案的時候非常有用。其大小目前通常是5M。
            在Android上需要手動開啟(setAppCacheEnabled),並設定路徑(setAppCachePath)和容量(setAppCacheMaxSize)

Android中Webkit使用一個db檔案來儲存AppCache資料(my_path/ApplicationCache.db)

          如果需要儲存一些簡單的用key/value對即可解決的資料,DOM Storage是非常完美的方案。根據作用範圍的不同,有Session Storage和Local Storage兩種,分別用於會話級別的儲存(頁面關閉即消失)和本地化儲存(除非主動刪除,否則資料永遠不會過期)。
在Android中可以手動開啟DOM Storage(setDomStorageEnabled),設定儲存路徑(setDatabasePath)
Android中Webkit會為DOM Storage產生兩個檔案(my_path/localstorage/http_h5.m.taobao.com_0.localstorage和my_path/localstorage/Databases.db)

           另外,在Android中清除快取時,如果需要清除Local Storage的話,僅僅刪除Local Storage的本地儲存檔案是不夠的,記憶體裡面有快取資料。如果再次進入頁面,Local Storage中的快取資料同樣存在。需要殺死程式執行的當前程序再重新啟動才可以。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

HTML5的離線應用功能可以使得WebApp即使在網路斷開的情況下仍能正常使用,這是個非常有用的功能。近來工作中也要用到HTML5離線應用功能,由於是在Android平臺上做,所以自然而然的選擇Webview來解析網頁。但如何使Webivew支援HTML5離線應用功能呢,經過反覆摸索和上網查詢資料,反覆做試驗終於成功了。

首先需配置webview的的一些屬性,假設activity中已經有了一個Webview的例項物件,名為m_webview,然後增加以下程式碼:

  1. WebSettings webseting = m_webview.getSettings();  
  2.     webseting.setDomStorageEnabled(true);             
  3.         webseting.setAppCacheMaxSize(1024*1024*8);//設定緩衝大小,我設的是8M  
  4.     String appCacheDir = this.getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath();      
  5.         webseting.setAppCachePath(appCacheDir);  
  6.         webseting.setAllowFileAccess(true);  
  7.         webseting.setAppCacheEnabled(true);  
  8.         webseting.setCacheMode(WebSettings.LOAD_DEFAULT);   
webview可以設定一個WebChromeClient物件,在其onReachedMaxAppCacheSize函式對擴充緩衝做出響應。程式碼如下:
  1. m_webview.setWebChromeClient(m_chromeClient);  
  2.     private WebChromeClient m_chromeClient = new WebChromeClient(){  
  3.         //擴充快取的容量    
  4.     @Override  
  5.     public void onReachedMaxAppCacheSize(long spaceNeeded,    
  6.                 long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {    
  7.             quotaUpdater.updateQuota(spaceNeeded * 2);    
  8.         }         
  9.     };  


其次要修改http伺服器中的配置,使其支援text/cache-manifest,我使用的是apache伺服器,是windows版本的,在apache的conf資料夾中找到mime.types檔案,開啟後在檔案的最後加上
“text/cache-manifest              mf  manifest”,重啟伺服器即可。這一步很重要,我就是因為伺服器端沒有配置這個,所以失敗了好多次,最後是在附錄連結1的回覆中找到的線索。


經過以上設定Webview就可以支援HTML5的離線應用了。

附錄連結1中說緩衝目錄應該是getApplicationContext().getCacheDir().getAbsolutePath();但我經過試驗後發現設定那個目錄不起作用,可能是Android版本不同吧,我的是Android4.0.3,而他的可能是以前的Android版本吧。

原因:
webview載入 服務端的網頁,為了減少訪問壓力,用html5快取技術,本地建了資料庫,在手機瀏覽器裡  可以顯示頁面,換成webView就不行了。


解決範例:
Activity code:

?
程式碼片段,雙擊複製
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class efan_NewsReader extendsActivity { /** Called when the activity is first created. */ @Override publicvoidonCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);             WebView myWebView=(WebView)findViewById(R.id.my_webview);    myWebView.setWebViewClient(newWebViewClient());    WebSettings settings = myWebView.getSettings(); // 開啟javascript設定 settings.setJavaScriptEnabled(true);   // 設定可以使用localStorage settings.setDomStorageEnabled(true); // 應用可以有資料庫 settings.setDatabaseEnabled(true);    String dbPath =this.getApplicationContest().getDir("database", Context.MODE_PRIVATE).getPath(); settings.setDatabasePath(dbPath); // 應用可以有快取 settings.setAppCacheEnabled(true);             String appCaceDir =this.getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath(); settings.setAppCachePath(appCaceDir); myWebView.loadUrl("http://10.10.35.47:8080/html5test/test.htm"); } }

HTML5 page source code:
?
程式碼片段,雙擊複製
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <htmlmanifest="mymanifest.manifest"> <head> <metahttp-equiv="Content-Type"content="text/html; content="no-cache"charset=utf-8" /> <scripttype="text/javascript"src="js/jquery-1.6.1.min.js"></script> <script> $(document).ready(function(){       databaseTest(); }); function databaseTest(){ //open database var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);   db.transaction(function (tx) {             tx.executeSql('CREATE TABLE IF NOT EXISTS testHtml (id unique, contentText)'); tx.executeSql('INSERT INTO testHtml (contentText) VALUES ("insert data test!")');   });   db.transaction(function(tx){            tx.executeSql('SELECT * FROM testHtml',[],function(tx,result){ var len=result.rows.length; var msg = "<p>Found rows: " + len + "</p>";   $("#testinfo").append(msg); },null); });    } </script> </head> <body> <div>here is test info:</div> <divid="testinfo"></div> </body>




其他設定還有:
settings.setCacheMode(WebSettings.LOAD_DEFAULT);   // 預設使用快取
settings.setAppCacheMaxSize(8*1024*1024);   //快取最多可以有8M
settings.setAllowFileAccess(true);   // 可以讀取檔案快取(manifest生效)


in WebChromeClient :
?
程式碼片段,雙擊複製
01 02 03 04 05 06 07 08 09 10 myWebView.setWebChromeClient(newWebChromeClient() {    @Override    publicvoidonExceededDatabaseQuota(String url, String databaseIdentifier, longcurrentQuota,longestimatedSize,longtotalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)    {         quotaUpdater.updateQuota(estimatedSize * 2);    } }


or:
?
程式碼片段,雙擊複製
01 02 03 04 05 06 07 08 09 10 myWebView.setWebChromeClient(newWebChromeClient() { // 擴充快取的容量    @Override    publicvoidonReachedMaxAppCacheSize(longspaceNeeded,longtotalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)    {         quotaUpdater.updateQuota(spaceNeeded * 2); } }




按照範例,我成功的解決了我的問題,而且之前彈出框所出現的找不到資料(提示:underfine)也解決了,這個應該是當初資料庫沒設所引起的。

WebView中存在著兩種快取:網頁資料快取(儲存開啟過的頁面及資源)、H5快取(即appcache)。

一、網頁快取

1、快取構成
/data/data/package_name/cache/
/data/data/package_name/database/webview.db
/data/data/package_name/database/webviewCache.db

2、快取模式
較難理解的是以下兩個模式:
LOAD_DEFAULT,根據cache-control決定是否從網路上取資料。
LOAD_CACHE_ELSE_NETWORK,只要本地有,無論是否過期,或者no-cache,都使用快取中的資料。
如:m.taobao.com的cache-control為no-cache,在模式LOAD_DEFAULT下,無論如何都會從網路上取資料,如果沒有網路,就會出現錯誤頁面;在LOAD_CACHE_ELSE_NETWORK模式下,無論是否有網路,只要本地有快取,都使用快取。本地沒有快取時才從網路上獲取。
m.sina.com.cn的cache-control為max-age=60,在兩種模式下都使用本地快取資料。

總結:根據以上兩種模式,建議快取策略為,判斷是否有網路,有的話,使用LOAD_DEFAULT,無網路時,使用LOAD_CACHE_ELSE_NETWORK。


3、清除快取
clearCache(boolean)。
CacheManager.clear。高版本中需要呼叫隱藏API。

4、控制大小
無系統API支援。
可選方式:定時統計快取大小、按時間順序刪除快取。

二、H5快取

1、快取構成
根據setAppCachePath(String appCachePath)提供的路徑,在H5使用快取過程中生成的快取檔案。

2、快取模式
無模式選擇,通過setAppCacheEnabled(boolean flag)設定是否開啟。預設關閉,即,H5的快取無法使用。

3、清除快取
找到呼叫setAppCachePath(String appCachePath)設定快取的路徑,把它下面的檔案全部刪除就OK了。

4、控制大小
通過setAppCacheMaxSize(long appCacheMaxSize)設定快取最大容量,預設為Max Integer。
同時,可能通過覆蓋WebChromeClient.onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater)來設定快取超過先前設定的最大容量時的策略。

三、參考網址

以下地址有關於H5快取的一些內幕,如每個Application只調用一次WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()被忽略等一系列問題,需要仔細閱讀和實驗。
http://code.google.com/p/android/issues/detail?id=24180