[貝聊科技] WebView截長圖解決方案

做者:Windin  貝聊移動開發部  Android工程師
前言:本文主要講述瞭如下兩個方面:android

  1. 普通WebView如何截取長圖
  2. 針對X5內核中WebView如何截取長圖

平常開發中,遇到爲WebView截取長圖算是一種常見的需求。網上聰明的程序員們提供了多種截取WebView長圖的方法,這爲咱們的開發提供了不少便利。如今,也有不少APP是集成了X5內核的,網上對於X5內核的截長圖方案介紹比較少,因此這裏我整理了對WebView截取長圖的比較通用可行的方法,而且對使用了x5內核的WebView的截圖方法進行分享。程序員

1、普通WebView截長圖方案

普通WebView截取長圖,這裏是指項目中沒有集成X5內核的狀況。利用Google文檔上的api能夠順利截圖。以Android5.0爲版本分界線,截圖採用不一樣的處理方式。web

1. Android5.0如下版本

/**
     * 對WebView進行截屏,雖然使用過時方法,但在當前Android版本中測試可行
     *
     * @param webView
     * @return
     */
    private static Bitmap captureWebViewKitKat(WebView webView) {
            Picture picture = webView.capturePicture();
            int width = picture.getWidth();
            int height = picture.getHeight();
            if (width > 0 && height > 0) {
                Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
                Canvas canvas = new Canvas(bitmap);
                picture.draw(canvas);
                return bitmap;
            }
            return null;
        }
    }複製代碼

2. Android5.0及以上版本

在Android5.0及以上版本,Android對WebView進行了優化,爲了減小內存使用和提升性能,使用WebView加載網頁時只繪製顯示部分。若是咱們不作處理,仍然使用上述代碼截圖的話,就會出現只截到屏幕內顯示的WebView內容,其它部分是空白的狀況。
這時候,咱們經過調用WebView.enableSlowWholeDocumentDraw()方法能夠關閉這種優化,但要注意的是,該方法須要在WebView實例被建立前就要調用,不然沒有效果。因此咱們在WebView實例被建立前加入代碼:canvas

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        android.webkit.WebView.enableSlowWholeDocumentDraw();
    }複製代碼

根據Google文檔中描述,capturePicture()方法已不鼓勵使用,推薦咱們經過webViewonDraw(Canvas)去獲取圖像,因此這裏咱們去拿到網頁的寬高後,就調用webView.draw(Canvas)方法生成webView截圖。api

private void captureWebViewLollipop(WebView webView) {
        float scale = webView.getScale();
        int width = webView.getWidth();
        int height = (int) (webView.getContentHeight() * scale + 0.5);
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        webView.draw(canvas);
        return bitmap;
    }複製代碼

2、X5內核截取長圖

使用X5內核截取長圖有兩種方法,而且均可以不用考慮版本問題,這爲咱們提供了方便。在X5內核下,若是使用WebViewonDraw(Canvas)方法,會出現或多或少的問題,因此對這個方法棄坑了。如下是兩個截圖方法:bash

1. 使用X5內核方法snapshotWholePage(Canvas, boolean, boolean)

在X5內核中提供了一個截取整個WebView界面的方法snapshotWholePage(Canvas, boolean, boolean),可是這個方法有個缺點,就是不以屏幕上WebView的寬高截圖,只是以WebViewcontentWidthcontentHeight爲寬高截圖,因此截出來的圖片會不怎麼清晰,但做爲縮略圖效果仍是不錯了。性能

private static Bitmap captureX5WebViewUnsharp(Context context, WebView webView) {
        if (webView == null) {
            return null;
        }
        if (context == null) {
            context = webView.getContext();
        }
        int width = webView.getContentWidth();
        int height = webView.getContentHeight();
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        webView.getX5WebViewExtension().snapshotWholePage(canvas, false, false);
        return bitmap;
    }複製代碼

2. 使用capturePicture()截取清晰長圖

若是想要在X5內核下截到清晰的長圖,不能使用snapshotWholePage(),依然能夠採用capturePicture()。X5內核下使用capturePicture()進行截圖,能夠直接拿到WebView的清晰長圖,但這是個Deprecated的方法,使用的時候要作好異常處理。測試

3、總結

以上是WebView截長圖方法的總結和分享,對X5內核的截圖也是嘗試了多種途徑最後找到滿意的解決方案。另外,截長圖會佔用大量內存,容易觸發OOM,因此代碼中也要注意對OOM的處理。優化

在使用了X5內核的項目中,使用WebView截取長圖的判斷邏輯能夠是:ui

// 有x5內核沒有生效,而且Android版本是5.0及以上時,調用enableSlowWholeDocumentDraw()方便截取長圖
    if (!isX5Enabled() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        android.webkit.WebView.enableSlowWholeDocumentDraw();
    }
/* 建立WebView ×/

...

// 網頁截圖
    public void captureWholePage() {
        try {
            Bitmap bitmap = captureWebView();
            /* 對拿到的bitmap根據須要進行處理 */
        } catch (OutOfMemoryError oom) {
            /* 對OOM作處理
        }
    }複製代碼
相關文章
相關標籤/搜索