作者:Windin 貝聊移動開發部 Android工程師
前言:本文主要講述了以下兩個方面:
- 普通
WebView
如何擷取長圖- 針對
X5核心中WebView
如何擷取長圖
日常開發中,遇到為WebView
擷取長圖算是一種常見的需求。網上聰明的程式設計師們提供了多種擷取WebView
長圖的方法,這為我們的開發提供了很多便利。現在,也有很多APP是整合了X5核心的,網上對於X5核心的截長圖方案介紹比較少,所以這裡我整理了對WebView
擷取長圖的比較通用可行的方法,並且對使用了x5核心的WebView
的截圖方法進行分享。
一、普通WebView
截長圖方案
普通WebView
擷取長圖,這裡是指專案中沒有整合X5核心的情況。利用Google
文件上的api可以順利截圖。以Android5.0
為版本分界線,截圖採用不同的處理方式。
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
例項被建立前加入程式碼:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
android.webkit.WebView.enableSlowWholeDocumentDraw();
}複製程式碼
根據Google
文件中描述,capturePicture()
方法已不鼓勵使用,推薦我們通過webView
的onDraw(Canvas)
去獲取影像,所以這裡我們去拿到網頁的寬高後,就呼叫webView.draw(Canvas)
方法生成webView
截圖。
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;
}複製程式碼
二、X5核心擷取長圖
使用X5核心擷取長圖有兩種方法,並且都可以不用考慮版本問題,這為我們提供了方便。在X5核心下,如果使用WebView
的onDraw(Canvas)
方法,會出現或多或少的問題,所以對這個方法棄坑了。以下是兩個截圖方法:
1. 使用X5核心方法snapshotWholePage(Canvas, boolean, boolean)
在X5核心中提供了一個擷取整個WebView
介面的方法snapshotWholePage(Canvas, boolean, boolean)
,但是這個方法有個缺點,就是不以螢幕上WebView
的寬高截圖,只是以WebView
的contentWidth
和contentHeight
為寬高截圖,所以截出來的圖片會不怎麼清晰,但作為縮圖效果還是不錯了。
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
的方法,使用的時候要做好異常處理。
三、總結
以上是WebView
截長圖方法的總結和分享,對X5核心的截圖也是嘗試了多種途徑最後找到滿意的解決方案。另外,截長圖會佔用大量記憶體,容易觸發OOM,所以程式碼中也要注意對OOM的處理。
在使用了X5核心的專案中,使用WebView
擷取長圖的判斷邏輯可以是:
// 有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做處理
}
}複製程式碼