1. 程式人生 > >跟Google 學程式碼:Web Apps以及WebView究極優化

跟Google 學程式碼:Web Apps以及WebView究極優化

引言

從本篇部落格可以學到什麼?
1. 用WebView構建頁面
2. 優化WebView的載入
3. 成型的WebView優化載入方案,crosswalk
4. hybrid app混合開發,常用框架

WebView

WebView提供了自定義的方式 讓我們在Android App中顯示web內容時,響應使用者的行為,比如在web頁面點選,跳轉url等

  • WebChromeClient

  • WebViewClient 比如可以通過shouldOverrideUrlLoading( )來中斷URL的載入(為什麼要中斷?有的機型會預設跳轉瀏覽器去載入URL,而不是在我們自定義的WebView中展示網頁)

  • WebSettings,比如常用的通過setJavaScriptEnabled( )設定 JavaSrcipt指令碼可用

  • 呼叫WebView物件的addJavascriptInterface(object ,String )介面,這個介面允許js程式碼呼叫Android的程式碼,

瞭解上述四大特性後,通過一個小demo來熟悉

加入WebView物件

WebView和普通的View一樣,可以通過程式碼靜態載入

<?xml version="1.0" encoding="utf-8"?>
<WebView  xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webview" android:layout_width="fill_parent" android:layout_height="fill_parent" />

也可以通過new WebView()建立一個物件的形式載入。

獲取WebView物件之後,通過loadUrl來傳入資料,來完成頁面顯示

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("部落格地址");

比如通過WebView開啟我的部落格:

預覽圖
這裡寫圖片描述

最後不要忘了新增許可權喲!

<manifest ... >
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

在這一環節可能遇到的bug:

很多人可能遇到loadUrl載入地址的時候,App開啟外部瀏覽器來顯示頁面的bug,接下來會告訴你怎麼做!

在WebView中使用JavaScript指令碼

WebView預設不支援JavaScript,我們可以通過WebSettings的setJavaSriptEnabled()來設定它可用

WebSettings 如何獲得?答:mWebView.getSettings();
例如:

WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);

向Android程式碼繫結JavaScript程式碼

通過WebView開發Android App的時候,你可以建立interface來服務於JavaScript指令碼程式碼呼叫Android程式碼。

例如,通過JavaScript程式碼去呼叫Android的程式碼,向用戶展示一個Dialog,我知道你是大牛,瞭解JavaScript的alert()函式也可以完成類似的功能。但這裡只是作為一個引入的例子,通過它我們來了解JavaScript和Android 是如何互動的

首先自定義一個Object物件,任意名稱即可

public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

注意@JavascriptInterface註解,當版本高於17的時候,對應Android4.2以上的系統級別,一定要使用JavascriptInterface註解,否則JS程式碼不識別Android的原生代碼,

建立完畢物件,我們就要把這玩意傳遞給WebView了,如何傳呢?

答案是通過WebView的addJavascriptInterface()方法

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

呃,光這麼做,可能還不夠,我們還缺少測試的javascript程式碼

在Android Studio環境下:
src-main->新建assets資料夾->新建test.html 檔案
程式碼如下:

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>

等等,我們該如何引用assets目錄下的檔案呢?(忽略e的命名)
答:file://android_asset/xx.html

 mWebView.loadUrl("file:///android_asset/e.html");

這一步有的同學可能出錯

出錯原因無非是兩個:

  1. 確定assets目錄名稱和擺放位置是否正確

  2. 確定是否正確引入到webView中

這麼快就OK了嗎?是不是已經迫不及待來看它的效果啦:

嗯,滿足你:

這裡寫圖片描述

處理頁面導航

通常瀏覽器不可能只展示一個頁面,比如頁面前進,頁面後退的功能也是要有的,android也提供了WebViewClient來滿足商戶需求

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());

WebViewClient是系統預設的元件

當日我們也可以自定義WebViewClient

比如:

private class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (Uri.parse(url).getHost().equals("www.example.com")) {
            // This is my web site, so do not override; let my WebView load the page
            return false;
        }
        // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        startActivity(intent);
        return true;
    }
}

shouldOverrideUrlLoading()就是用來解決 有的系統版本 會預設開啟外部瀏覽器 載入頁面。

接著建立webView例項引用WebViewClient例項

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());

最後就是在activity控制層 來處理WebView的跳轉邏輯

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // Check if the key event was the Back button and if there's history
    if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
        myWebView.goBack();
        return true;
    }
    // If it wasn't the Back key or there's no web page history, bubble up to the default
    // system behavior (probably exit the activity)
    return super.onKeyDown(keyCode, event);
}

專案完整程式碼:

Activity.java 類

public class MainActivity extends AppCompatActivity {

    private MyWebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        mWebView = (MyWebView) findViewById(R.id.my_webview);
       //  mWebView.loadUrl("http://www.taobao.com");
       mWebView.loadUrl("file:///android_asset/e.html");
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.addJavascriptInterface(new             WebAppInterface(getApplicationContext()),"Hello");
        mWebView.setWebViewClient(new MyWebClient());


    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode==KeyEvent.KEYCODE_BACK&&mWebView.canGoBack()){
            mWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

}

MyWebClient類,指定頁面載入的邏輯

public class MyWebClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {

        return super.shouldOverrideUrlLoading(view, url);

    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        Log.i("onPageFinished","onPageFinished");
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        Log.i("onPageStarted","onPageStarted");
    }

    @Override
    public void onLoadResource(WebView view, String url) {
        Log.i("onLoadResource","onLoadResource");
        super.onLoadResource(view, url);
    }

}

WebAppInterface類,用來和Javascript互動

public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page
     */

    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

e.html 檔案,模擬伺服器的jsp資料

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Hello.showToast(toast);
    }
</script>

如何優化WebView載入?

為了能夠更好的使用WebView展示出流暢的的頁面,可以從以下幾點做優化:

  • WebView快取

    開啟WebView的快取功能可以減少對伺服器資源的請求,一般使用預設快取策略就可以了。

    //設定 快取模式 
        webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);  
    // 開啟 DOM storage API 功能 
    webView.getSettings().setDomStorageEnabled(true); 
  • 資原始檔本地儲存

    資源等檔案(不需要更新)本地儲存,在需要的時候直接從本地獲取。哪些資源需要我們去儲存在本地呢,當然是一些不會被更新的資源,例如圖片檔案,js檔案,css檔案,替換的方法也很簡單,重寫WebView的方法即可。

    {
      try {
          if (url.endsWith("icon.png")) {
              InputStream is = appRm.getInputStream(R.drawable.icon);
              WebResourceResponse response = new WebResourceResponse("image/png",
                "utf-8", is);
              return response;
          } elseif (url.endsWith("jquery.min.js")) {
              InputStream is = appRm.getInputStream(R.raw.jquery_min_js);
              WebResourceResponse response = new WebResourceResponse("text/javascript",
                "utf-8", is);
              return response;
          }
          } catch (IOException e) {
                 e.printStackTrace();
          }
          returnsuper.shouldInterceptRequest(view, url);
    }
    

    appRm為app資源管理器,讀取drawable,assets,raw下的資源,都是android系統的一些很簡單的函式呼叫。

    getInputStream的引數代表資源具體位置

    WebResourceResponse後的資源型別需要寫正確

    有些時候我們會為我們的網站加入一些統計程式碼,這些也可以精簡掉(自己使用的CNZZ的大概佔的有10k左右),可以使用Charles對客戶端進行抓包檢視。

  • 減少耗時操作

    準確的說,是減少同步操作的操作時間,儘量使用非同步操作替代同步操作。如果服務端存在讀取資料庫和計算耗時的操作,儘量使用非同步(ajax)進行操作,把原本的時間花在非同步操作上。
    舉個例子,A頁面到B頁面,A頁面實現登入功能,B頁面展示主功能頁面,如果讓B頁面去進行使用者登入資訊驗證的話,B頁面載入時間會加長(資料庫查詢等操作),同時客戶端可能需要提供一個等待框(或進度條等)給使用者,那看看在A頁面使用非同步操作的優勢吧:
    可以提供統一的js等待框,多平臺保持一致性,減少客戶端程式碼工作量。
    載入頁面的時間變短。B頁面由於減少了耗時的操作,載入時間變短,使用者等待時間也變短。
    可以方便加入一些驗證後的控制邏輯,不需要進行頁面跳轉。A頁面可以根據非同步操作進行結果判斷,做出相應的處理。

  • 客戶端UI優化

    怎麼讓使用者看不到WebView載入前的白色頁面呢?首次載入後頁面的跳轉可以用上面的步驟進行優化,可以提供給使用者一個很好的體驗,那載入的第一頁呢?我們需要WebView預載入頁面,這個該怎麼做到的呢?下面提供兩種方法:

    ViewPager,將歡迎頁面與WebView頁面一起放進ViewPager中,設定預載入頁面個數,使WebView所在頁面可以預載入,在載入完畢的時候切換到WebView所在頁面。

    FrameLayout,將歡迎頁面與WebView頁面的佈局合在一起,顯示在一個頁面內,起始隱藏WebView佈局,待WebView載入完畢,隱藏歡迎佈局,顯示WebView佈局。

    使用FrameLayout簡單一些,兩種方法都是需要對WebChromeClient的onProgressChanged進行監聽,載入完畢進行頁面切換,如下:

      webView.setWebChromeClient(new WebChromeClient() {
            @OverridepublicvoidonProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
                if (newProgress >= 100) {
                    // 切換頁面
                }
            }
        });
  • 加快HTML網頁裝載完成的速度

    預設情況html程式碼下載到WebView後,webkit開始解析網頁各個節點,發現有外部樣式檔案或者外部指令碼檔案時,會非同步發起網路請求下載檔案,但如果在這之前也有解析到image節點,那勢必也會發起網路請求下載相應的圖片。在網路情況較差的情況下,過多的網路請求就會造成頻寬緊張,影響到css或js檔案載入完成的時間,造成頁面空白loading過久。解決的方法就是告訴WebView先不要自動載入圖片,等頁面finish後再發起圖片載入。

    故在WebView初始化時設定如下程式碼:

    public void int () {
        if(Build.VERSION.SDK_INT >= 19) {
            webView.getSettings().setLoadsImagesAutomatically(true);
        } else {
            webView.getSettings().setLoadsImagesAutomatically(false);
        }
    }

    同時在WebView的WebViewClient例項中的onPageFinished()方法新增如下程式碼:

    @Override
    public void onPageFinished(WebView view, String url) {
        if(!webView.getSettings().getLoadsImagesAutomatically()) {
            webView.getSettings().setLoadsImagesAutomatically(true);
        }
    }

    從上面的程式碼,可以看出我們對系統API在19以上的版本作了相容。因為4.4以上系統在onPageFinished時再恢復圖片載入時,如果存在多張圖片引用的是相同的src時,會只有一個image標籤得到載入,因而對於這樣的系統我們就先直接載入。

  • 自定義出錯介面

    當WebView載入頁面出錯時(一般為404 NOT FOUND),安卓WebView會預設顯示一個賣萌的出錯介面。但我們怎麼能讓使用者發現原來我使用的是網頁應用呢,我們期望的是使用者在網頁上得到是如原生般應用的體驗,那就先要從幹掉這個默認出錯頁面開始。當WebView加載出錯時,我們會在WebViewClient例項中的onReceivedError()方法接收到錯誤,我們就在這裡做些手腳:

    @Override
    public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);
        loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
        mErrorFrame.setVisibility(View.VISIBLE);
    }

    從上面可以看出,我們先使用loadDataWithBaseURL清除掉預設錯誤頁內容,再讓我們自定義的View得到顯示(mErrorFrame為蒙在WebView之上的一個LinearLayout佈局,預設為View.GONE)。

  • 是否滾動到頁面底部

    同樣我們在做上拉載入下一頁這樣的功能時,也需要知道當前頁面滾動條所處的狀態,如果快到底部,則要發起網路請求資料更新網頁。同樣繼承WebView類,在子類覆蓋onScrollChanged方法,具體如下:

    @Override
    protected void onScrollChanged(int newX, int newY, int oldX, int oldY) {
        super.onScrollChanged(newX, newY, oldX, oldY);
        if (newY != oldY) {
            float contentHeight = getContentHeight() * getScale();
            // 當前內容高度下從未觸發過, 瀏覽器存在滾動條且滑動到將抵底部位置
            if (mCurrContentHeight != contentHeight && newY > 0 && contentHeight <= newY + getHeight() + mThreshold) {
                // TODO Something...
                mCurrContentHeight = contentHeight;
            }
        }
    }

    上面mCurrContentHeight用於記錄上次觸發時的網頁高度,用來防止在網頁總高度未發生變化而目標區域發生連續滾動時會多次觸發TODO,mThreshold是一個閾值,當頁面底部距離滾動條底部的高度差<=這個值時會觸發TODO。

  • 遠端網頁需訪問本地資源

    當我們在WebView中加載出從web伺服器上拿取的內容時,是無法訪問本地資源的,如assets目錄下的圖片資源,因為這樣的行為屬於跨域行為(Cross-Domain),而WebView是禁止的。解決這個問題的方案是把html內容先下載到本地,然後使用loadDataWithBaseURL載入html。這樣就可以在html中使用 file:///android_asset/xxx.png 的連結來引用包裡面assets下的資源了。示例如下:

    private void loadWithAccessLocal(final String htmlUrl) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    final String htmlStr = NetService.fetchHtml(htmlUrl);
                    if (htmlStr != null) {
                        TaskExecutor.runTaskOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                loadDataWithBaseURL(htmlUrl, htmlStr, "text/html", "UTF-8", "");
                            }
                        });
                        return;
                    }
                } catch (Exception e) {
                    Log.e("Exception:" + e.getMessage());
                }
    
                TaskExecutor.runTaskOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        onPageLoadedError(-1, "fetch html failed");
                    }
                });
            }
        }).start();
    }

    上面有幾點需要注意:

    1. 從網路上下載html的過程應放在工作執行緒中
    2. html下載成功後渲染出html的步驟應放在UI主執行緒,不然WebView會報錯
    3. html下載失敗則可以使用我們前面講述的方法來顯示自定義錯誤介面
  • ViewPager裡非首屏WebView點選事件不響應

    如果你的多個WebView是放在ViewPager裡一個個加載出來的,那麼就會遇到這樣的問題。ViewPager首屏WebView的建立是在前臺,點選時沒有問題;而其他非首屏的WebView是在後臺建立,滑動到它後點擊頁面會出現如下錯誤日誌:

    20955-20968/xx.xxx.xxx E/webcoreglue﹕ Should not happen: no rect-based-test nodes found

    解決辦法:繼承WebView類,在子類覆蓋onTouchEvent方法,填入如下程式碼:

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY());
        }
        return super.onTouchEvent(ev);
    }
  • WebView硬體加速導致頁面渲染閃爍

    4.0以上的系統我們開啟硬體加速後,WebView渲染頁面更加快速,拖動也更加順滑。但有個副作用就是,當WebView檢視被整體遮住一塊,然後突然恢復時(比如使用SlideMenu將WebView從側邊滑出來時),這個過渡期會出現白塊同時介面閃爍。解決這個問題的方法是在過渡期前將WebView的硬體加速臨時關閉,過渡期後再開啟,程式碼如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
  • 避免addJavaScriptInterface帶來的安全問題

    使用開源專案Safe Java-JS WebView Bridge可以很好替代addJavaScriptInterface方法,同時增加了非同步回撥等支援,並且不存在了安全風險。

  • WebView與上層父元素的TouchMove事件衝突

    在開發過程中你可能會遇到這樣一種情況。端裡面使用ViewPager嵌套了多個WebView頁面,同時某一個WebView中的頁面元素需要響應TouchMove事件

    這時你就會發現上層(ViewPager)阻斷了下層(WebView)接收TouchMove事件,即使你的WebView在TouchDown時返回true也無效,因為上層直接使用了onInterceptTouchEvent對後續的TouchMove進行了攔截。針對這個問題的解決,簡單做法是在重寫WebView onTouchEvent方法,如下

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean ret = super.onTouchEvent(ev);
        if (mPreventParentTouch) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    requestDisallowInterceptTouchEvent(true);
                    ret = true;
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    requestDisallowInterceptTouchEvent(false);
                    mPreventParentTouch = false;
                    break;
            }
        }
        return ret;
    }
    
    public void preventParentTouchEvent () {
        mPreventParentTouch = true;
    }

    程式碼控制的關鍵在於mPreventParentTouch這個變數,mPreventParentTouch預設為false,當用戶touchdown頁面元素時通知該WebView將mPreventParentTouch設定為true。示意程式碼如下:

    <script type="text/javascript">
        document.getElementById("targetEle").addEventListener("touchstart",
            function(ev) {
                HostApp.preventParentTouchEvent();   // 通知WebView阻止祖先對其Touch事件的攔截
            }
        );
        document.getElementById("targetEle").addEventListener("touchmove",
            function(ev) {
                // todo something on this page
            }
        );
    </script>

    剛提到了上面是一種簡單的做法,並不能很好的解決手指滑動過快帶來的誤操作問題,即當用戶快速地滑動時,還是有一定機率會出現ViewPager攔截TouchMove事件而發生了Tab切換而非頁面元素做出了響應。要完美解決此問題,就要用到稍微複雜一點的方法(僅是整體訊息傳遞流程複雜一點)。

    首先假設在ViewPager之上還有一個父元素叫做ParentViewOnViewPager,當我們接收到頁面preventParentTouchEvent通知時就先於ViewPager而進行攔截。如下:

    public class ParentViewOnViewPager extends FrameLayout {
        private MineWebView mDispatchWebView;
    
        public void preventParentTouchEvent (WebView view) {
            mDispatchWebView = (MineWebView)view;
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            if (ev.getAction() == MotionEvent.ACTION_MOVE && mDispatchWebView != null) {
                mDispatchWebView.ignoreTouchCancel(true);
                return true;
            }
            return false;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            if (mDispatchWebView != null){
                switch (ev.getAction()) {
                    case MotionEvent.ACTION_MOVE:
                        mDispatchWebView.onTouchEvent(ev);
                        break;
                    default:
                        mDispatchWebView.ignoreTouchCancel(false);
                        mDispatchWebView.onTouchEvent(ev);
                        mDispatchWebView = null;
                        break;
                }
                return true;
            }
            return super.onTouchEvent(ev);
        }
    }

    即當ParentViewOnViewPager接收到通知時,發起TouchEvent攔截,將攔截到的Touch事件轉嫁到裝載頁面的mDispatchWebView進行事件派發。這樣就直接跳過了ViewPager這一層。這裡需要注意的是當ParentViewOnViewPager發起攔截時,WebView會接收到一個TouchCancel事件,WebView應該忽略這個事件,以避免頁面接收到這個事件而打斷整個處理流程。如下程式碼所示:

    public class MineWebView extends WebView {
        boolean mIgnoreTouchCancel;
    
        public void ignoreTouchCancel (boolean val) {
            mIgnoreTouchCancel = val;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            return ev.getAction() == MotionEvent.ACTION_CANCEL && mIgnoreTouchCancel || super.onTouchEvent(ev);
        }
    }
  • 究極優化方案

    就是想辦法讓瀏覽器延遲載入JS指令碼,但是Android的WebView控制元件沒有這樣的引數。無法單獨阻塞JS指令碼,另外有個setBlockNetworkLoads,用了之後也無法實現類似圖片的非同步載入的功能,頁面成了光板,連CSS也阻塞了。

    這個問題困擾了很久,直到在做HTML照片牆時,由於setBlockNetworkImage在OnPageFinished之後才會釋放,導致在JS指令碼載入圖片過程中無法獲取圖片的高寬資訊,最後巧妙地通過$(document).ready(function()
    {setTimeout(func,10)});,成功將函式在onPageFinished之後執行。那麼延伸來想,是否可以將JS指令碼也用同樣的方式延遲載入呢?

    我改造了之前速度奇慢的介面,我所使用的核心JS程式碼如下:

     <script src="/css/j/lazyload-min.js" type="text/javascript"></script>
    
            <script type="text/javascript" charset="utf-8"> 
    
           loadComplete(){
    
              //instead of document.read()
    
           }
    
            function loadscript()
    
            {
    
    LazyLoad.loadOnce([
    
     '/css/j/jquery-1.6.2.min.js',
    
     '/css/j/flow/jquery.flow.1.1.min.js',  
    
     '/css/j/min.js?v=2011100852'
    
    ], loadComplete);
    
            }
    
            setTimeout(loadscript,10);
    
            </script>
    
    

    就是混搭setTimeout和layzload,讓JS指令碼可以真正在onPageFinish之後執行。

經過以上幾步的優化,一個流暢的webapp生成了。

成型的優化方案:crosswalk以及相應的整合工具

Crosswalk是一款為HTML應用提供執行時環境的開源專案,同時它也擴充套件了一些Web平臺的新特性。

Web平臺已經擁有很多優勢,例如從簡單的雲服務整合到靈活的使用者介面元素。當前隨其對移動效能和裝置API持續增長的關注,Web平臺也越來越具有吸引力。

然而對於很多開發者而言,由於基礎功能仍然缺失,導致時至今日採用Web平臺依舊困難重重。

使用Crosswalk專案,可以改變這種情況

通過使用Crosswalk專案,應用開發人員可以:

  • 使用所有現代瀏覽器可提供的特性:HTML5,CSS3,JavaScript。
  • 訪問主流和新興的Web標準。
  • 使用主流瀏覽器無法獲取的實驗性API。
  • 通過部署自己的執行時環境來控制應用的升級週期。
  • 通過為應用新增自定義擴充套件,來使用並未通過Crosswalk或公共Web標準暴露的系統平臺功能

crosswalk擴充套件閱讀

hybrid App(混合App)開發

Hybrid App:Hybrid App is a mobile application that is coded in both browser-supported language and computer language. They are available through application distribution platforms such as the Apple App Store, Google Play etc. Usually, they are downloaded from the platform to a target device, such as iPhone, Android phone or Windows Phone. The subscribers need to install to run them.

我們來拆解一下里面的含義:
1、mobile application:Hybrid App就是一個移動應用
2、both browser-supported language and computer language:同時使用網頁語言與程式語言編寫
3、available through application distribution platforms:通過應用商店進行分發
4、a target device:區分目標平臺
5、install to run:使用者需要安裝使用

綜合一下就是:“Hybrid App同時使用網頁語言與程式語言開發,通過應用商店區分移動作業系統分發,使用者需要安裝使用的移動應用”。總體特性更接近Native App但是和Web App區別較大。只是因為同時使用了網頁語言編碼,所以開發成本和難度比Native App要小很多。因此說,Hybrid App兼具了Native App的所有優勢,也兼具了Web App使用HTML5跨平臺開發低成本的優勢

hybrid擴充套件閱讀:

  1. 點評:前攜程員工,經歷過最初的hybrid開發,後加入百度,學習到完整的hybrid app開發流程

未完成的部分

Android developer Web Apps課程 只翻譯了一部分

還有Migrating to WebView in Android 4.4 等重要章節沒有翻譯,日後補充上來!

參考並感謝