編輯:Android資訊
現在的App開發,或多或少都會用到Hybrid模式,到了WebView這邊,經常會加載一些js文件(例如和WebView用來Native通信的bridge.js),而這些js文件不會經常發生變化,所以我們希望js在WebView裡面加載一次之後,如果js沒有發生變化,下次就不用再發起網絡請求去加載,從而減少流量和資源的占用。那麼有什麼方式可以達到這個目的呢?先得從WebView的緩存原理入手。
WebView主要包括兩類緩存,一類是浏覽器自帶的網頁數據緩存,這是所有的浏覽器都支持的、由HTTP協議定義的緩存;另一類是H5緩存,這是由web頁面的開發者設置的,H5緩存主要包括了App Cache、DOM Storage、Local Storage、Web SQL Database 存儲機制等,這裡我們主要介紹App Cache來緩存js文件。
浏覽器緩存機制是通過HTTP協議Header裡的Cache-Control(或Expires)和Last-Modified(或 Etag)等字段來控制文件緩存的機制。關於這幾個字段的作用和浏覽器的緩存更新機制,大家可以看看這兩篇文章(H5 緩存機制淺析 移動端 Web 加載性能優化,Android:手把手教你構建 WebView 的緩存機制 & 資源預加載方案),裡面有詳細的介紹。下面從我實際應用的角度,介紹一下通常會在HTTP協議中遇到的Header。
這兩個字段是接收響應時,浏覽器決定文件是否需要被緩存;或者需要加載文件時,浏覽器決定是否需要發出請求的字段。
下面兩個字段是發起請求時,服務器決定文件是否需要更新的字段。
If-Modified-Since:Wed, 28 Sep 2016 09:24:35 GMT
,服務器接收到請求後,會把文件的Last-Modified時間和這個時間對比,如果時間沒變,那麼浏覽器將返回304 Not Modified
給浏覽器,且content-length肯定是0個字節。如果時間有變化,那麼服務器會返回200 OK
,並返回相應的內容給浏覽器。If-None-Match:"57eb8c5c-129"
字段傳到服務器。服務器和最新的文件特征串對比,如果相同那麼返回304 Not Modified
,不同則返回200 OK
。當ETag和Last-Modified同時出現時,任何一個字段只要生效了,就認為文件是沒有更新的。由上面的介紹可知,只要是個主流的、合格的浏覽器,都應該能夠支持HTTP協議層面的這幾個字段。這不是我們開發者可以修改的,也不是我們應該修改的配置。在Android上,我們的WebView也支持這幾個字段。但是我們可以通過代碼去設置WebView的Cache Mode,而使得協議生效或者無效。WebView有下面幾個Cache Mode:
設置WebView緩存的Cache Mode示例代碼如下:
WebSettings settings = webView.getSettings(); settings.setCacheMode(WebSettings.LOAD_DEFAULT);
網上很多人都說根據網絡條件去選擇Cache Mode,當有網絡時,設置為LOAD_DEFAULT,當沒有網絡時設置為LOAD_CACHE_ELSE_NETWORK。但是在我的業務中,js文件的更新都是非覆蓋式的更新,也就是時候每次改變js文件的時候,文件的url地址一定會發生變化,所以我希望浏覽器能夠緩存下來js,並且一直使用它,那麼我就給它只設置為LOAD_CACHE_ELSE_NETWORK。當然如果你要是可以改js的cdn服務器的Cache-Control字段,那也行啊,用LOAD_DEFAULT就ok了。至於文件是應該采用覆蓋式or非覆蓋式的更新,不是我今天要討論的內容,在web前端領域,這是一個可以聊聊的topic。
關於iOS的WebView,我同事在實際測試的時候竟然發現,控制文件緩存的Response Header是Expires字段。。而且iOS無法針對整個WebView設置Cache Mode,只能針對每一個URLRequest去設置。。後續有機會要學習一下iOS那塊的情況。
浏覽器默認緩存下來的文件是怎麼被存儲到了哪裡呢?這個問題在接觸到WebView以來,就一直是一個謎題。這次由於工作的需要,我特意root了兩台手機,一台紅米1(Android 4.4)和一台小米4c(Android 5.1),在root高系統版本(6.0和7.1)的兩台Nexus都以失敗告終之後,我決定還是先看看4.4和5.1系統上,WebView自帶的緩存存到了哪裡。
首先,不用思考就知道,這些文件一定是在/data/data/包名/目錄下,在我之前的一篇博客裡面提到過,這是每一個應用自己的內部存儲目錄。
接著,我們打開終端,使用adb連接手機,然後按照下面命令操作一下。
// 1.先進入shell adb shell // 2.開啟root賬號 su // 3.修改文件夾權限 chmod 777 data/data/你的應用包名/ // 4.修改子文件夾的權限,因為Android命令行不支持向Linux那樣的-R命令實現遞歸式的chmod。。。 chmod 777 data/data/你的應用包名/* // 5.所以如果你對應用目錄層級更深,你就要進一步地chmod。。。 chmod 777 data/data/你的應用包名/*/* // 6.直到終端裡提示你說,no such file or directory時,說明chmod完了,所有的內部存儲裡面的文件夾和文件都可以看到了,如果大家有更好的方法請一定告訴我,多謝了~
/data/data/包名/app_webview/cache/
,如下圖所示的第二個文件夾。可能你注意到了,第一個文件夾是叫Application Cache,我們後面再說它。
/data/data/包名/cache/org.chromium.android_webview/
下面,如下圖所示。但是在5.1系統上,/data/data/包名/app_webview/
文件夾依然存在,只是4.4系統上面存儲WebView自帶緩存的app_webview/cache
文件夾不再存在了(注意下App Cache目錄還在),如下圖所示。
綜上所述,WebView自帶的浏覽器協議支持的緩存,在不同的系統版本上,位置是不一樣的。也許除了我root過的4.4、5.1以外,其他版本系統的WebView自帶緩存還可能存在於不同的目錄裡面。
另外一個是關於緩存文件的存儲格式和索引格式,在不同的手機上可能也有差別,因為之前看到網上的人都說有叫webview.db或者webviewCache.db的文件,這個文件呢,還不是在app_webview/cache
或者org.chromium.android_webview
下面,而是在/data/data/包名/database/
裡面。但是,我這兩台root過的手機都沒有看到這種文件,而且我把/data/data/包名/
下面所有的db文件都打開看了,並沒有發現有存儲url記錄的table。。
實際上,以5.1系統為例,我看到了/data/data/包名/cache/org.chromium.android_webview/
下面有叫index和/index-dir/the-real-index的文件,以及一堆名稱為md5+下劃線+數字的文件,上面的圖中也可以看得到,這塊的原理仍然有些疑問,也希望專業的大神可以解答一下。
講完了WebView自帶的緩存,下面講一下H5裡面的App Cache。這個Cache是由開發Web頁面的開發者控制的,而不是由Native去控制的,但是Native裡面的WebView也需要我們做一下設置才能支持H5的這個特性。
寫Web頁面代碼時,指定manifest屬性即可讓頁面使用App Cache。通常html頁面代碼會這麼寫:
<html manifest="xxx.appcache"> </html>
xxx.appcache文件用的是相對路徑,這時appcache文件的路徑是和頁面一樣的。也可以使用的絕對路徑,但是域名要保持和頁面一致。
完整的xxx.appcache文件一般包括了3個section,基本格式如下:
CACHE MANIFEST # 2017-05-13 v1.0.0 /bridge.js NETWORK: * FALLBACK: /404.html
AppCache工作的原理:當一個設置了manifest文件的html頁面被加載時,CACHE MANIFEST指定的文件就會被緩存到浏覽器的App Cache目錄下面。當下次加載這個頁面時,會首先應用通過manifest已經緩存過的文件,然後發起一個加載xxx.appcache文件的請求到服務器,如果xxx.appcache文件沒有被修改過,那麼服務器會返回304 Not Modified
給到浏覽器,如果xxx.appcache文件被修改過,那麼服務器會返回200 OK
,並返回新的xxx.appcache文件的內容給浏覽器,浏覽器收到之後,再把新的xxx.appcache文件中指定的內容加載過來進行緩存。
可以看到,AppCache緩存需要在每次加載頁面時都發出一個xxx.appcache的請求去檢查manifest文件是不是有更新(byte by byte)。根據這篇文章(H5 緩存機制淺析 移動端 Web 加載性能優化)的介紹,AppCache有一些坑的地方,且官方已經不推薦使用了,但目前主流的浏覽器依然是支持的。文章裡主要提到下面這些坑:
WebView默認是沒有開啟AppCache支持的,需要添加下面這幾行代碼來設置:
WebSettings webSettings = webView.getSettings(); webSettings.setAppCacheEnabled(true); String cachePath = getApplicationContext().getCacheDir().getPath(); // 把內部私有緩存目錄'/data/data/包名/cache/'作為WebView的AppCache的存儲路徑 webSettings.setAppCachePath(cachePath); webSettings.setAppCacheMaxSize(5 * 1024 * 1024);
注意:WebSettings的setAppCacheEnabled和setAppCachePath都必須要調用才行。
按照Android SDK的API說明,setAppCachePath是可以用來設置AppCache路徑的,但是我實際測試發現,不管你怎麼設置這個路徑,設置到應用自己的內部私有目錄還是外部SD卡,都無法生效。AppCache緩存文件最終都會存到/data/data/包名/app_webview/cache/Application Cache
這個文件夾下面,在上面的Android 4.4和5.1系統目錄截圖可以看得到,但是如果你不調用setAppCachePath方法,WebView將不會產生這個目錄。這裡有點讓我覺得奇怪,我猜測可能從某一個系統版本開始,為了緩存文件的完整性和安全性考慮,SDK實現的時候就吧AppCache緩存目錄設置到了內部私有存儲。
WebView自帶的緩存和AppCache都是可以用來做文件級別的緩存的,基本上比較好地滿足對於非覆蓋式的js、css等文件更新。
最後說一下,其實很多時候,這兩類緩存是共同在工作的,當manifest文件沒有控制某些資源加載時,例如我上面寫的xxx.appcache文件裡,NETWORK section下面用的是*號,意思是所有不緩存的文件都要去網絡加載。此時,這些資源就會走到WebView自帶的緩存機制去,結合WebView的CacheMode,我們實際上對這些文件進行了一次WebView自帶的緩存。搞清楚這兩類緩存的原理有利於我們更好的設計自己的頁面和App,盡可能減少網絡請求,提高App運行效率。
較長的構建時間將會減緩項目的開發進度,特別是對於大型的項目,app的構建時間長則十幾分鐘,短則幾分鐘,長的構建時間已經成了開發瓶頸,本篇文章根據Google官方文
一、ActionBar概述 ActionBar是androiD3.0以後新增的組件,主要用於標示應用程序以及用戶所處的位置並提供相關操作以及全局的導航功能。下面我
一、概述 熱修復這項技術,基本上已經成為項目比較重要的模塊了。主要因為項目在上線之後,都難免會有各種問題,而依靠發版去修復問題,成本太高了。 現在熱修復的技術基本
TextView比較簡單,不能夠用來進行編輯,只能夠用來顯示信息 布局文件裡的一些常用的XML屬性 android:gravity—用來設置控件內文本