該片文章講述項目中遇到的問題,以及相關優化細節。
一、項目背景
1、項目需要支援hybrid應用,是以部分提供h5調用的通用js儲存在用戶端本地。優點有:通路速度快和無需額外資料流量。
2、項目首頁都是h5形式,采用vue架構,支援離線緩存
3、使用CordovaWebView加載h5應用。
二、問題清單和優化
1、h5應用如何讀到本地js檔案?
針對第1個問題,很簡單解決。webview提供攔截方法,隻要和js端定義好import的格式,比對好即可。代碼編寫如下:
攔截方法入口,系統版本不一緻,調用方法不一樣,請知曉。
/**
* URL攔截請求方法(API21以上)
* @param webView
* @param webResourceRequest 請求資訊
* @return
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest) {
//21版本
//通過版本控制來将2個入口引入到一個攔截方法中
String method = webResourceRequest != null ? webResourceRequest.getMethod() : null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//OPTIONS請求跳過
if (method != null && method.equalsIgnoreCase("OPTIONS")) {
return null;
}
return customInterceptRequest(webView,
webResourceRequest.getUrl().toString(),
method,
webResourceRequest.getRequestHeaders(),
super.shouldInterceptRequest(webView, webResourceRequest));
}
return super.shouldInterceptRequest(webView, webResourceRequest);
}
/**
* URL攔截請求方法(API21以下)
* @param view
* @param url 請求位址
* @return
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
//11版本
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return customInterceptRequest(view, url, null, null, super.shouldInterceptRequest(view, url));
}
return super.shouldInterceptRequest(view, url);
}
比對url,重新寫回WebResourceResponse
/**
* 加載本地js檔案
* @param url
* @param injection
* @return
*/
private WebResourceResponse handleInjectUrl(String url,String injection){
try{
String assetPath = url.substring(url.indexOf(injection) + injection.length(), url.length());
String cordovaPath = JS_PATH + assetPath;
InputStream fis = new FileInputStream(new File(cordovaPath));
return new WebResourceResponse(
"application/javascript",
"UTF-8",
fis
);
}catch (Exception e){
if (ModuleCommImpl.getInstance().isDebug()) {
LOG.e(TAG, "handleInjectUrl loading file fail.", e);
}
}
return new WebResourceResponse("application/javascript", "UTF-8", null);
}
此處有個優化點,非常耗時,第三點會解釋,請繼續閱讀。
2、無網情況下如何繼續通路資料?
首先h5應用需要支援離線緩存,使用localstorage把網絡資料暫存起來。Android端需要把緩存開關打開。如圖:
// Enable database
// We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
String databasePath = webView.getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
settings.setDatabaseEnabled(true);
settings.setDatabasePath(databasePath);
// Enable AppCache
// Fix for CB-2282
settings.setCacheMode(WebSettings.LOAD_DEFAULT); // 預設使用緩存
settings.setAppCacheMaxSize(20 * 1048576);
settings.setAppCachePath(databasePath);
// 可以讀取檔案緩存(manifest生效)
settings.setAllowFileAccess(true);
settings.setAppCacheEnabled(true);
網上資料很多,查下即可。
3、加載首頁資料緩慢?
h5應用往往遇到加載慢,體驗不好的問題。在我們做了離線緩存時,稍微好點。但是此項目中遇到一個問題就是加載資料慢。
排查思路:
a、檢查首頁webview對象初始化時間
期初懷疑是對象初始化耗時,經列印時間,發現不是。
b、檢查onPageStarted 和onPageFinished時間。
如果此處耗時比較大,就存在問題,當初我們這邊耗時800ms,後來發現攔截代碼,擷取路徑函數
public static File getCacheDirectory(Context context, boolean preferExternal, boolean persist) {
File appCacheDir = null;
String externalStorageState;
try {
externalStorageState = Environment.getExternalStorageState();
} catch (NullPointerException e) { // (sh)it happens (Issue #660)
externalStorageState = "";
}
該方法調用時間10ms,單次調用沒什麼問題。
對于我們加載本地js,比如本地60個js,針對浏覽器,并行加載6個js,也就是加載所有的js需要總的時間:600ms,太費時了。
是以我們把路徑寫出
private static final String JS_PATH = ModuleCommImpl.getInstance().getFileJsPath()+"/plugin.apis/";
時間立馬下降了。
此處一個優化點。後續開發者在做攔截時,需要考慮下。
c、頁面沒有渲染好的問題,需要h5優化。這裡就不描述了。