WebView深度學習(二)之全面總結WebView遇到的坑及優化

AWeiLoveAndroid發表於2018-01-09

上篇文章講到了WebView的基本使用以及Android和js的互動.

這篇文章講一下WebView遇到的那些坑,帶領各位爬坑。這裡如果有你沒遇到的問題,歡迎留言告訴我,我盡我所能幫你解決。感謝大家支援。


⇒ 三、WebView的那些坑

(1) 為什麼Webview開啟一個頁面,播放一段音樂,退出Activity時音樂還在後臺播放?

◆◆ 解決方案 1:

//銷燬Webview
@Override
protected void onDestroy() {
    if (mWebview != null) {
        mWebview.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
        mWebview.clearHistory();
        ((ViewGroup) mWebview.getParent()).removeView(mWebview);
        mWebview.destroy();
        mWebview = null;
    }
    super.onDestroy();
}

還有別問我為什麼要移除,等你Error: WebView.destroy() called while still attached!之後你就知道了。

◆◆ 解決方案 2:

@Override
protected void onPause() {
   h5_webview.onPause();
   h5_webview.pauseTimers();
   super.onPause();
}
@Override
protected void onResume() {
   h5_webview.onResume();
   h5_webview.resumeTimers();
   super.onResume();
}

Webview的onPause()方法官網是這麼解釋的:

   Does a best-effort attempt to pause any processing that can be paused safely, such as animations
and geolocation. Note that this call does not pause JavaScript. To pause JavaScript globally, use 
pauseTimers(). To resume WebView, call onResume().  
【翻譯:】通知核心嘗試停止所有處理,如動畫和地理位置,但是不能停止Js,如果想全域性停止Js,
可以呼叫pauseTimers()全域性停止Js,呼叫onResume()恢復。

(2) 怎麼用網頁的標題來設定自己的標題欄?

◆◆ 解決方案:

WebChromeClient mWebChromeClient = new WebChromeClient() {    
    @Override    
    public void onReceivedTitle(WebView view, String title) {    
        super.onReceivedTitle(view, title);    
        txtTitle.setText(title);    
    }    
};  
mWedView.setWebChromeClient(mWebChromeClient());

注意事項:

●   1.可能當前頁面沒有標題,獲取到的是null,那麼你可以在跳轉到該Activity的時候自己帶一個標題,或者有一個預設標題。
●   2.在一些機型上面,Webview.goBack()後,這個方法不一定會呼叫,所以標題還是之前頁面的標題。那麼
你就需要用一個ArrayList來保持載入過的url,一個HashMap儲存url及對應的title.然後就是用WebView.canGoBack()來做判斷處理了。

(3) 為什麼打包之後JS呼叫失敗(或者WebView與JavaScript相互呼叫時,如果是debug沒有配置混淆時,呼叫時沒問題的,但是當設定混淆後發現無法正常呼叫了)?

◆◆ 解決方案:在proguard-rules.pro中新增混淆。

-keepattributes *Annotation*  
-keepattributes *JavascriptInterface*
-keep public class org.mq.study.webview.DemoJavaScriptInterface{
   public <methods>;
}
#假如是內部類,混淆如下:
-keepattributes *JavascriptInterface*
-keep public class org.mq.study.webview.webview.DemoJavaScriptInterface$InnerClass{
    public <methods>;
}

其中org.mq.study.webview.DemoJavaScriptInterface 是不需要混淆的類名

(4) 5.0 以後的WebView載入的連結為Https開頭,但是連結裡面的內容,比如圖片為Http連結,這時候,圖片就會載入不出來,怎麼解決?

原因分析:原因是Android 5.0上Webview預設不允許載入Http與Https混合內容:

◆◆ 解決方案:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
    //兩者都可以
    webSetting.setMixedContentMode(webSetting.getMixedContentMode());
    //mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

引數說明:

●   MIXED_CONTENT_ALWAYS_ALLOW 允許從任何來源載入內容,即使起源是不安全的;
●   MIXED_CONTENT_NEVER_ALLOW 不允許Https載入Http的內容,即不允許從安全的起源去載入一個不安全的
    資源;
●   MIXED_CONTENT_COMPLTIBILITY_MODE 當涉及到混合式內容時,WebView會嘗試去相容最新Web瀏覽器的
    風格;

另外:在認證證照不被Android所接受的情況下,我們可以通過設定重寫WebViewClient的onReceivedSslError方法在其中設定接受所有網站的證照來解決,具體程式碼如下:

webView.setWebViewClient(new WebViewClient() {
        @Override
        public void onReceivedSslError(WebView view,
                SslErrorHandler handler, SslError error) {
            //super.onReceivedSslError(view, handler, error);注意一定要去除這行程式碼,否則設定無效。
            // handler.cancel();// Android預設的處理方式
            handler.proceed();// 接受所有網站的證照
            // handleMessage(Message msg);// 進行其他處理
        }
});

(5) WebView呼叫手機系統相簿來上傳圖片,開發過程中發現在很多機器上無法正常喚起系統相簿來選擇圖片。怎麼解決?

原因分析:因為Google攻城獅們對setWebChromeClient的回撥方法openFileChooser做了多次修改,5.0以下openFileChooser有幾種過載方法,在5.0以上將回撥方法該為了onShowFileChooser。

◆◆ 解決方案:為了相容各個版本,我們需要對openFileChooser()進行過載,同時針對5.0及以上重寫onShowFileChooser()方法:

上一段示例程式碼,給大家看看:

public class MainActivity extends AppCompatActivity {

private ValueCallback<Uri> uploadMessage;
private ValueCallback<Uri[]> uploadMessageAboveL;
private final static int FILE_CHOOSER_RESULT_CODE = 10000;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    WebView webview = (WebView) findViewById(R.id.web_view);
    assert webview != null;
    WebSettings settings = webview.getSettings();
    settings.setUseWideViewPort(true);
    settings.setLoadWithOverviewMode(true);
    settings.setJavaScriptEnabled(true);
    webview.setWebChromeClient(new WebChromeClient() {

        //  android 3.0以下:用的這個方法
        public void openFileChooser(ValueCallback<Uri> valueCallback) {
            uploadMessage = valueCallback;
            openImageChooserActivity();
        }

        // android 3.0以上,android4.0以下:用的這個方法
        public void openFileChooser(ValueCallback valueCallback, String acceptType) {
            uploadMessage = valueCallback;
            openImageChooserActivity();
        }

        //android 4.0 - android 4.3  安卓4.4.4也用的這個方法
        public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, 
                        String capture) {
            uploadMessage = valueCallback;
            openImageChooserActivity();
        }

        //android4.4 無方法。。。

        // Android 5.0及以上用的這個方法
        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> 
                 filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
            uploadMessageAboveL = filePathCallback;
            openImageChooserActivity();
            return true;
        }
    });
    String targetUrl = "file:///android_asset/up.html";
    webview.loadUrl(targetUrl);
}

private void openImageChooserActivity() {
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");
    startActivityForResult(Intent.createChooser(i, "Image Chooser"),
                  FILE_CHOOSER_RESULT_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == FILE_CHOOSER_RESULT_CODE) {
        if (null == uploadMessage && null == uploadMessageAboveL) return;
        Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
        if (uploadMessageAboveL != null) {
            onActivityResultAboveL(requestCode, resultCode, data);
        } else if (uploadMessage != null) {
            uploadMessage.onReceiveValue(result);
            uploadMessage = null;
        }
    }
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {
    if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null)
        return;
    Uri[] results = null;
    if (resultCode == Activity.RESULT_OK) {
        if (intent != null) {
            String dataString = intent.getDataString();
            ClipData clipData = intent.getClipData();
            if (clipData != null) {
                results = new Uri[clipData.getItemCount()];
                for (int i = 0; i < clipData.getItemCount(); i++) {
                    ClipData.Item item = clipData.getItemAt(i);
                    results[i] = item.getUri();
                }
            }
            if (dataString != null)
                results = new Uri[]{Uri.parse(dataString)};
        }
    }
    uploadMessageAboveL.onReceiveValue(results);
    uploadMessageAboveL = null;
}

}


重點坑:針對Android4.4,系統把openFileChooser方法去掉了,怎麼解決?

詳情請見 部落格 http://blog.csdn.net/xiexie758/article/details/52446937 我這裡就不多說了。

(6) WebView呼叫手機系統相簿來上傳圖片,處理好第六點說的方法,我們打好release包測試的時候卻又發現還是沒法選擇圖片了。怎麼解決?

原因分析:無奈去翻WebChromeClient的原始碼,發現openFileChooser()是系統API,我們的release包是開啟了混淆的,所以在打包的時候混淆了openFileChooser(),這就導致無法回撥openFileChooser()了。

◆◆ 解決方案也很簡單,直接不混淆openFileChooser()就好了。

-keepclassmembers class * extends android.webkit.WebChromeClient{
   public void openFileChooser(...);
}

(7)怎麼在 WebView 中長按儲存圖片?

1. 給 WebView新增監聽

mWebview.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
    }
});

2. 獲取點選的圖片地址

先獲取型別,根據相應的型別來處理對應的資料。

//首先判斷點選的型別
WebView.HitTestResult result = ((WebView) v).getHitTestResult();
int type = result.getType();

//獲取具體資訊,圖片這裡就是圖片地址
String imgurl = result.getExtra();

type有這幾種型別:

  • WebView.HitTestResult.UNKNOWN_TYPE 未知型別
  • WebView.HitTestResult.PHONE_TYPE 電話型別
  • WebView.HitTestResult.EMAIL_TYPE 電子郵件型別
  • WebView.HitTestResult.GEO_TYPE 地圖型別
  • WebView.HitTestResult.SRC_ANCHOR_TYPE 超連結型別
  • WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE 帶有連結的圖片型別
  • WebView.HitTestResult.IMAGE_TYPE 單純的圖片型別
  • WebView.HitTestResult.EDIT_TEXT_TYPE 選中的文字型別

3. 操作圖片

你可以彈出儲存圖片,或者點選之後跳轉到顯示圖片的頁面。

最後整理一下程式碼:

mWebView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        WebView.HitTestResult result = ((WebView)v).getHitTestResult();
        if (null == result)
            return false;
        int type = result.getType();
        if (type == WebView.HitTestResult.UNKNOWN_TYPE)
            return false;

        // 這裡可以攔截很多型別,我們只處理圖片型別就可以了
        switch (type) {
            case WebView.HitTestResult.PHONE_TYPE: // 處理撥號
                break;
            case WebView.HitTestResult.EMAIL_TYPE: // 處理Email
                break;
            case WebView.HitTestResult.GEO_TYPE: // 地圖型別
                break;
            case WebView.HitTestResult.SRC_ANCHOR_TYPE: // 超連結
                break;
            case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
                break;
            case WebView.HitTestResult.IMAGE_TYPE: // 處理長按圖片的選單項
                // 獲取圖片的路徑
                String saveImgUrl = result.getExtra();

                // 跳轉到圖片詳情頁,顯示圖片
                Intent i = new Intent(MainActivity.this, ImageActivity.class);
                i.putExtra("imgUrl", saveImgUrl);
                startActivity(i);
                break;
            default:
                break;
        }
    }
});

(8) WebView 開啟硬體加速導致的問題?

WebView有很多問題,比如:不能開啟pdf,播放視屏也只能開啟硬體加速才能支援,在某些機型上會崩潰。
下面看一下硬體加速, 硬體加速 分為四個級別:

  • Application級別
     <application android:hardwareAccelerated="true"...>
  • Activity級別
     <activity android:hardwareAccelerated="true"...>
  • window級別(目前為止,Android還不支援在Window級別關閉硬體加速。)
    getWindow().setFlags(
         WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
         WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
  • View級別
     view.setLayerType(View.LAYER_TYPE_HARDWARE, null);

WebView開啟硬體加速導致螢幕花屏問題的解決:

原因分析:
4.0以上的系統我們開啟硬體加速後,WebView渲染頁面更加快速,拖動也更加順滑。但有個副作用就是,當WebView檢視被整體遮住一塊,然後突然恢復時(比如使用SlideMenu將WebView從側邊滑出來時),這個過渡期會出現白塊同時介面閃爍。

◆◆ 解決方案:
在過渡期前將WebView的硬體加速臨時關閉,過渡期後再開啟,程式碼如下:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

Android 4.0+ 版本中的EditText字元重疊問題:
做的軟體,在一些機器上,打字的時候,EditText中的內容會出現重疊,而大部分機器沒有,所以感覺不是程式碼的問題,一直沒有頭緒。

出現原因:JellyBean的硬體加速bug,在此我們關掉硬體加速即可。
解決方案:在EditText中加入一句:

android:layerType=”software”  

圖片無法顯示:
做的程式裡有的時候會需要載入大圖,但是硬體加速中 OpenGL對於記憶體是有限制的。如果遇到了這個限制,LogCat只會報一個Warning: Bitmap too large to be uploaded into a texture (587×7696, max=2048×2048)

這時我們就需要把硬體加速關閉了。
但開始我是這樣處理的,我關閉了整個應用的硬體加速:

<application  
    android:allowBackup="true"  
    android:icon="@drawable/ic_launcher"  
    android:hardwareAccelerated="false"  
    android:label="@string/app_name"  
    android:theme="@style/AppTheme" >  

隨後我就發現,雖然圖片可以顯示了,但是ListView和WebView等控制元件顯得特別的卡,這說明硬體加速對於程式的效能提升是很明顯的。所以我就改為對於Activity的關閉。

<activity  
    android:name="icyfox.webviewimagezoomertest.MainActivity"  
    android:label="@string/app_name"  
    android:hardwareAccelerated="false"  

(9) 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);
}

(10) WebView白屏是什麼原因?

◆◆ 解決方案:
WebView設定setLayerType(View.LAYER_TYPE_SOFTWARE,null); 示例程式碼如此下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

◆◆ 相關原始碼分析:
WebView繼承View,View中有三種layer type分別為LAYER_TYPE_NONELAYER_TYPE_SOFTWARELAYER_TYPE_HARDWARE

  • 1.LAYER_TYPE_NONE:表明檢視沒有多餘渲染層。
  • 2.LAYER_TYPE_SOFTWARE:表明檢視有一個軟體渲染層。無論是否開啟硬體加速,都會有一張
    Bitmap(software layer),並在上面對 WebView 進行渲染。
    好處:在進行動畫,使用software可以只畫一次ViewTree,很省。
    不適合使用場景:View樹經常更新時不要用。尤其是在硬體加速開啟時,每次更新消耗的時間更多。因為渲染完這張Bitmap後還需要再把這張Bitmap渲染到hardware layer上面去。
  1. LAYER_TYPE_HARDWARE:
    表明檢視有一個硬體渲染層。硬體加速關閉時,作用同software。硬體加速開啟時會在FBO(Framebuffer Object)上做渲染,在進行動畫時,View樹也只需要畫一次。

◆◆ LAYER_TYPE_SOFTWARE 和 LAYER_TYPE_HARDWARE的區別:

1.前者是渲染到Bitmap,後者是渲染到FB上。
2.hardware可能會有一些操作不支援(出現白屏)。

◆◆ LAYER_TYPE_SOFTWARE 和 LAYER_TYPE_HARDWARE的相同:

都是開了一個buffer,把View畫到這個buffer上面去。

(11)給GLSurfaceView設定為software或者hardware後,發現沒有畫面了是什麼原因?

◆◆ 問題分析:GLSurfaceView和WebView預設LayerType都是NONE。

◆◆ 解決方案:給GLSurfaceView的LayerType設定為LAYER_TYPE_NONE就可以了。

(12) WebView的快取機制,比如token cookie session之類的在下一篇會講到,希望大家去看看

⇒ 四、安卓8.0關於WebView的新特性

WebView新增了一些非常有用的API,可以使用和chrome瀏覽器類似的API來實現對惡意網站的檢測來保護web瀏覽的安全性,為此需要在manifest中新增如下meta-data標籤:

<manifest>
<meta-data
    android:name="android.webkit.WebView.EnableSafeBrowing"
    android:value="true" />
<!-- ... -->
</manifest>

WebView還增加了關於多程式的API,可以使用多程式來增強安全性和健壯性,如果render程式崩潰了,你還可以使用Termination Handler API來檢測到崩潰並做出相應處理。


⇒ 五、關於WebView的一點小優化:

(1)給WebView加一個載入進度條

  用Webview載入一個網頁時,如果載入時間長,介面會一直空白,體驗不太好,所以加個進度條更好看一下,主流APP也都有進度條效果,大概思路我來說一下:
  首先自定義一個HorizontalProgressView繼承View,然後自定義一個MyWebView繼承WebView,然後初始化的時候通過addView方法把前面自定義HorizontalProgressView,然後在MyWebView裡面寫一個內部類繼承WebChromeClient,大致程式碼如下:

private class MyWebCromeClient extends WebChromeClient {
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        if (newProgress == 100) {
            //載入完畢進度條消失
            progressView.setVisibility(View.GONE);
        } else {
            //更新進度
            progressView.setProgress(newProgress);
        }
        super.onProgressChanged(view, newProgress);
    }
}

主要是通過MyWebCromeClient 的onProgressChanged方法裡面的進度值呼叫
progressView.setProgress()方法去更新進度條,當載入100%的時候讓進度條消失。
具體實現你們自己去處理吧。

(2)加快HTML網頁載入完成的速度,等頁面finish再載入圖片

  預設情況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);
    }
}

(3)自定義WebView頁面載入出錯介面

  當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)。

(4) 怎麼知道WebView是否已經滾動到頁面底端?

◆◆ 解決方案:

  • 方案1,使用原生WebView的api可以獲取到:
    if (mWebView.getContentHeight() * mWebView.getScale()  == (mWebView.getHeight() + 
    mWebView.getScrollY())) {
        //說明已經到底了
    }
  • 方案2,繼承WebView,重寫onScrollChanged方法:
      我們在做上拉載入下一頁這樣的功能時,也需要知道當前頁面滾動條所處的狀態,如果快到底部,則要發起網路請求資料更新網頁。同樣繼承WebView類,在子類覆蓋onScrollChanged方法。
      以下程式碼中mCurrContentHeight用於記錄上次觸發時的網頁高度,用來防止在網頁總高度未發生變化而目標區域發生連續滾動時會多次觸發TODO,mThreshold是一個閾值,當頁面底部距離滾動條底部的高度差<=這個值時會觸發TODO裡面的程式碼。

具體如下:

@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;
        }
    }
}

相關API介紹:

●   getContentHeight() @return the height of the HTML content
●   getScale() @return the current scale
●   getHeight() @return The height of your view
●   getScrollY() @return The top edge of the displayed part of your view, in pixels.

(5) 怎麼知道WebView是否存在滾動條?

  當我們做類似上拉載入下一頁這樣的功能的時候,頁面初始的時候需要知道當前WebView是否存在縱向滾動條,如果有則不載入下一頁,如果沒有則載入下一頁直到其出現縱向滾動條。
  首先繼承WebView類,在子類新增下面的程式碼:

public boolean existVerticalScrollbar () {
    return computeVerticalScrollRange() > computeVerticalScrollExtent();
}

  computeVerticalScrollRange得到的是可滑動的最大高度,computeVerticalScrollExtent得到的是滾動把手自身的高,當不存在滾動條時,兩者的值是相等的。當有滾動條時前者一定是大於後者的。


其實也有一些替代WebView的庫,比如騰訊的TBS 騰訊瀏覽服務, 比如WebViewJavascriptBridge等方式,有興趣的可以去了解一下,個人建議還是用原生的WebView比較好,不能動不動就用框架,框架也不一定適用於自己專案,所以我們可以看看這些框架它的使用原理,吸收框架的精華,自己去靈活封裝一下用在自己專案中。


下一篇我們講解 WebView的記憶體洩漏、漏洞以及快取機制原理和解決方案


參考博文:
http://blog.csdn.net/carson_ho/article/details/64904691
http://bbs.csdn.net/topics/390905615
http://blog.csdn.net/cyuyanshujujiegou/article/details/52267817


相關文章