1. 程式人生 > >WebView詳解及使用說明;(android外殼專案總結版)

WebView詳解及使用說明;(android外殼專案總結版)

最近做了一個關於webview寫安卓的殼,套HTML5的應用,雖然整個寫下來後,到了目前的進度,程式碼量不多,共有1000多行,但是整個殼的設計思想和實現思路還是當初查了很久的。所以寫下來,以備後續檢視和分享。

這個webview的殼目前實現的功能我將從三方面說明並總結。

1. 最基本的功能:
  • 增加useragent以便HTML5判斷出是哪個應用
  • 設定webSetting快取
  • 攔截url並將相應網路資源替換成本地資源
  • javascript和android互動  
2. 增加使用者體驗的功能:
  • 網路狀態監聽
  • HTML進度條替換成Android原生進度條,以及onPageFinished中遇到的坑
3. 我們的應用需要增加的額外功能:

  • 口語評測打分
  • 下載資源包並在本地解壓,本地MP3的播放、暫停以及退出並返回當前的播放進度。
  • 本地錄音並存儲為PCM格式,本地PCM的播放
  • 訊息推送功能

下面進行詳細說明:

  1. 最基本的功能
  • 增加useragent以便HTML5判斷出是哪個應用(android或者ios)(這裡的android_agent和HTML商量好就可以)
WebSettings webSettings = webView.getSettings();
String ua = webSettings.getUserAgentString();
webSettings.setUserAgentString(ua + getString(R.string.android_agent));
  • 設定webSettting快取
我們原來的想法是將圖片、css、js、son、plain、vtt等一些不變的檔案下載到本地,然後通過攔截替換url進行網路資源替換成本地資源,但是後來發現webSetting快取其實webView這個控制元件自己以及做的比較完善了,所以就用了webSetting自帶的快取,我們只需要進行一些webSetting的函式設定就可以了。
  • 攔截url並將相應網路資源替換成本地資源
我們將一些固定不變的圖片放到工程的assets檔案下,然後攔截網路的url進行替換,這樣使用者在第一次進入介面時,就不會因為載入圖片而花費較長時間,造成使用者體驗不好,但是如果攔截到相應的的url時間長了,頁面依舊會載入比較長的時間,但這個Android就無能為力了。 攔截替換函式如下:
webView.setWebViewClient(new WebViewClient() {

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        Log.d("start", url);

    }

    @Override
    public void onLoadResource(WebView view, String url) {
        Log.e("cache", "onLoadResource-url=" + url);
        super.onLoadResource(view, url);
    }


    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        WebResourceResponse response = null;
        Log.d("Webview", "shouldInterceptRequest url=" + url);

        if (url.contains("ajax.php") && !Validate.isNetworkConnected(Webview.this)) {
            //網路連線不可用時並且攔截到ajax時

        }

        if (url.contains("http://emodou.com/resource/be")) {
            //三種中的第一種,替換資原始檔
            String path = url.substring(17, url.length());
            File file = new File(Constants.STORAGE_URL_START + path);//path: /resource/be/e_Res/BF1/22101/res/1.jpg
            Log.d("path", path);
            FileInputStream fin = null;
            try {
                fin = new FileInputStream(file);
                //進行"/"分割
                String[] urlArray = url.split("/");
                int urlCount = urlArray.length;
                Log.d("count", urlCount + "");

                //進行"."分割
                String suffixes = urlArray[urlCount - 1];
                String[] suffixesArray = suffixes.split("\\.");
                int suCount = suffixesArray.length;

                //如果遇到字尾名符合的,進行攔截替換
                if (suffixesArray[suCount - 1].equals("jpg") ||
                        suffixesArray[suCount - 1].equals("png") ||
                        suffixesArray[suCount - 1].equals("jpeg") ||
                        suffixesArray[suCount - 1].equals("JPG") ||
                        suffixesArray[suCount - 1].equals("PNG") ||
                        suffixesArray[suCount - 1].equals("JPEG")) {
                    response = new WebResourceResponse("image/png", "UTF-8", fin);
                } else if (suffixesArray[suCount - 1].equals("mp3") ||
                        suffixesArray[suCount - 1].equals("MP3")) {
                    response = new WebResourceResponse("audio/mpeg", "UTF-8", fin);//mp3替換不到
                } else if (suffixesArray[suCount - 1].equals("JSON") ||
                        suffixesArray[suCount - 1].equals("json")) {
                    response = new WebResourceResponse("application/json", "UTF-8", fin);
                } else if (suffixesArray[suCount - 1].equals("lrc") ||
                        suffixesArray[suCount - 1].equals("LRC")) {
                    response = new WebResourceResponse("text/plain", "UTF-8", fin);
                } else if (suffixesArray[suCount - 1].equals("mp4") ||
                        suffixesArray[suCount - 1].equals("MP4")) {
                    response = new WebResourceResponse("video/mp4", "UTF-8", fin);
                } else if (suffixesArray[suCount - 1].equals("vtt") ||
                        suffixesArray[suCount - 1].equals("VTT")) {
                    response = new WebResourceResponse("text/vtt", "UTF-8", fin);
                }
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            }
        }


        return response;

    }

   
});
雖然看著程式碼很多,但是其實有用的只有   WebResourceResponse response = null;以及response = new WebResourceResponse("text/vtt", "UTF-8", fin);這兩句
  • js和android互動
android呼叫js的程式碼
webView.loadUrl("javascript:DM.progress("+percent+")");

其中DM.progress是HTML的方法,percent是android需要傳過去的引數,其他為固定內容。

js呼叫android的程式碼方法:

webView.addJavascriptInterface(new JsToJava(), "record");

JsToJava()是android裡面自己寫的類,這個類中所有的函式都可以被JS以window.record.XX(); 方式呼叫,其中XX是函式名。需要特別注意的是XX函式上要新增@SuppressLint("JavascriptInterface"),否則呼叫會無響應

@SuppressLint("JavascriptInterface")
public void initWebView() {
}

2.增加使用者體驗的功能

  • 網路狀態的監聽
這個功能用了一個廣播監聽,動態註冊或解綁廣播,提示資訊顯示方式用了SnackBar(Material Design中的控制元件)
  • HTML進度條替換成Android原生進度條,以及onPageFinished中遇到的坑
由於android將資源替換成本地的了,因此相應的進度條也要替換成android的,由android端來控制什麼時候載入完成,按正常來說,onPageFinished在被呼叫時,該介面就已經載入完成了,但是實際操作中發現,onPageFinished被呼叫的時候,介面並沒有被載入完成,還有一部分web的進度條會顯示,因此我們在onPageFinished函式中執行了延遲函式
public class TimeControlTask extends AsyncTask {

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        av.setVisibility(View.GONE);
        webView.setVisibility(View.VISIBLE);
    }

    @Override
    protected String doInBackground(Integer... params) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
然後在onPageFinished函式中進行呼叫即可
new TimeControlTask().execute();
3.我們的應用需要增加的額外功能
  • 口語評測打分,採用的科大訊飛語音打分的技術,具體請點開超連結,參考文件。
  • 下載資源包並在本地解壓,本地MP3的播放、暫停以及退出並返回當前的播放進度。這裡需要說明的是,下載資源包使用的是OKHttpUtils
  • 訊息推送功能,整合的是友盟的推送
暫時功能模組如上所述,如果有更新新功能,還會回頭來補充這篇文章。