1. 程式人生 > >Android Webview優化及與Js互動

Android Webview優化及與Js互動

在做的一個專案裡主要是webview載入HTML頁面,移動端工作量不多,主要是webview的優化問題,雖說看似很簡單,但仍遇到了幾個令人頭疼的問題。
問題解決及優化之路主要經歷了以下幾個過程:

1、第一次開啟webview耗時過長

剛開始在做webview載入url時,發現首次開啟頁面所耗時長比之後再開啟時多了很多。
這是因為webview從建立到載入url需要時間而且首次載入沒有快取。所以最初解決辦法是提前建立一個全域性webview,供所有頁面使用,我是在application初始化時就建立了webview,也確實解決了第一次開啟耗時過長問題。

2、H5頁面select選擇框無法正常使用

在解決第一個問題把webview放在application中後,又出現了新的問題,H5頁面裡select元件在Android中不能調起,錯誤原因是Dialog在show的時候必須要有一個activity作為視窗載體,而我的webview是有application建立,並沒有任何activity作為載體,所以我又將webview放回activity中建立,發現select選擇框果然工作正常了。

3、Webview資源預載入

為了進一步優化載入H5頁面耗時過長,資料流量多的問題,我做了資源預載入攔截配置,即將html頁面使用到的一些靜態資源提前放在Android本地,編譯進apk裡,在載入頁面時,攔截相關的資源,進行替換,節省載入時間和載入的資料量。

public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request){}

其中,可以將js,css,圖片等資源放置android新建assets資料夾下,攔截到對應url請求後,
用本地資料返回。

return new WebResourceResponse(mimeType, "utf-8", getAssets().open(resourceName));

4、Android webview 與JS互動

因為專案裡HTML頁面不僅僅是顯示效果,還需要和Android本地有一些互動效果或資料互動。所以又涉及到js與Android互動問題。

一、是js呼叫Android原生代碼:

1)先允許與js互動
webSettings.setJavaScriptEnabled(true);
2)新增互動介面
mWebView.addJavascriptInterface(new AndroidtoJs(), “android”);//用this也可以 存在安全隱患 漏洞
//為了防止WebView呼叫我們不想被它呼叫的函式,所以我們需要單獨為WebView互動定義一個類,讓它只執行這個類裡面的函式
3)寫js需要呼叫的android程式碼

 private class AndroidtoJs {
      @android.webkit.JavascriptInterface
      public void finishActivity() {
         finish();
      }
      @android.webkit.JavascriptInterface
      public String toJs() {
          return "123456";
      }   }

4)js端呼叫
關閉activity例子
function finishActivity(){
window.android.finishActivity();//此即上面finishActivity()
}

二、還有Android呼叫js程式碼:

1)js程式碼(帶參例子)
function putData(key,value){
window.localStorage.setItem(key,value);
}

2)Android端呼叫
此例子是呼叫帶參的方法
mWebView.evaluateJavascript(“javascript:putData(‘serverUrl’,’http://192.168.1.5:8089/‘)”, new ValueCallback() {
@Override
public void onReceiveValue(String value) {
//此處為 js 返回的結果
toast(value);
}
});

5、js與android互調問題,關於localstorage

Webview有多種快取機制,其中有種Dom Storage 快取機制,DOM Storage 分為 sessionStorage & localStorage; 二者使用方法基本相同,區別在於作用範圍不同:
a. sessionStorage:具備臨時性,即儲存與頁面相關的資料,它在頁面關閉後無法使用
b. localStorage:具備永續性,即儲存的資料在頁面關閉後也可以使用。
問題:android調js,並傳送資料 使用localstorage儲存。

我們原來的需求是android將一些資料儲存在localstorage中,然後js呼叫獲取localstorage中資料。其中,要使用js方法儲存資料,如下。
javascript:putData(‘serverUrl’,’http://192.168.1.5:8089/‘)
遇到的問題及注意事項:
1) webview setting需要設定檔案快取等

webSettings.setDomStorageEnabled(true);
webSettings.setAppCacheMaxSize(1024 * 1024 * 8);
String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
webSettings.setAppCachePath(appCachePath);
webSettings.setAppCacheEnabled(true);
webSettings.setAllowFileAccess(true);

2) 剛開始在js載入之前onPageStarted()中呼叫,發現返回null,這是因為這個頁面js還沒載入。
3) 在頁面onPageFinished()中呼叫,發現所有資源已載入完,對該需求此時已沒意義
所以,這個方法主動呼叫js並傳入資料讓js獲取,受到js載入時機等因素問題會比較受限,遂放棄。
後來轉念一想,改為js主動呼叫android程式碼獲取想要的資料,實現很簡單而且不用考慮js是否已載入,資源載入順序等問題,需要時即可從android端獲取資料。所以有時不能一味根據別人要求完成功能實現,要理清需求,理順邏輯,才能避免無謂的歪路。

補充除錯過程中遇到的幾個相關問題:
1、html頁面中alert()在android端顯示,需要寫上

mWebView.setWebChromeClient(new WebChromeClient(){
   @Override
   public boolean onJsAlert(WebView view, String url,String message, JsResult result) {
      toast("message:"+message + "  JsResult" + result.toString());
      return super.onJsAlert(view, url, message, result);
   }
});

2、關於webview快取
除錯時我改動了H5頁面,移動端卻沒有顯示出來改動,是因為我為了加快webview載入速度,在webview設定裡,對快取設定里加載使用快取,而在除錯程式碼過程中,沒有清理快取,所以無論我怎麼修改H5頁面,移動端始終沒有效果,耗費了不少時間和精力,後來載入新頁面,才發現是因為快取,沒有實時替換成修改過的HTML頁面,而且即使退出應用或重新部署程式也不會自動清理快取,只有完全手動解除安裝再安裝,才會替換新修改後的頁面。所以要在程式碼裡注意新增清理快取程式碼。
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);