iOS 原生和H5結合 WKWebView的長截圖問題
前言
最近的一版,有很多....泯滅人性的地方.遇到了一些之前沒有遇到的問題,也有了一些自己的體會,先說一個跟技術分享沒有關係的經驗問題: 一定不要為了省程式碼而作過多的邏輯判斷(主要是過不了自己心裡的一關),尤其是在週期緊的情況下,無論是寫還是review都是一個大問題.即使想達到節省程式碼量的目的.這些邏輯判斷最好寫在model裡.不要在頁面裡做過多的展示判斷.否則....你的下場就和我一樣.....
言歸正傳,WKWebView的截圖就是一個坑,你想躲避他,回頭便還是會遇到他.其實如果只是單純的WKWebView的截圖相比較之下相對容易一點,讀了前輩的文章基本上你有兩條路可以走: 1.將WKWebView的contentOffSet進行設定一屏一屏的截圖,然後再拼接起來假裝達到長截圖的效果; 2.將WKWebView放在一個父檢視上然後通過更改這個父檢視的frame 的y來截的當前父檢視的截圖,然後再一屏一屏的截下來.假裝達到長截圖的效果.....於是乎我不信其邪,走上了一條長達1天半的歪路.不過還是有收穫,現將前輩的網址貼過來,供大家瞻仰:
為了能夠方便大家,還得去前輩那裡看具體的技術點.我簡單的形容一下我的理解,和進行探索的過程.
場景描述
在一個tableView 下我需要接上一個webView.我有三條路:
- 放在tableView的tableFooterView上,限制webView的滑動整體讓tableView滑動來彌補.當然後期會解決手勢衝突
- 放在tableView的Cell中
- 將tableView作為webView的頭檢視,然後設定webView的contentInset,之前的blog中有相關操作
然後我選擇了1
主要矛盾
長截圖.....一個原生加webView的長截圖,一個webView大部分時間在螢幕外的長截圖....一個要截tableView 還要截一個放在他footer裡的WKWebView.....對於初出茅廬的我....很是塞心...之前專案裡這種部分都是請求介面得到image....不過鑑於週期短還是不給別人添麻煩了...而且那樣還得一個個生成....其實已經與自己的想法背離.
於是看到了前輩的blog,前輩有個開源庫SwViewCapture,雖然...我...下下來...直接執行截圖WKWebView的時候直接就崩潰了...但是其思路讓我豁然開朗,茅塞頓開.柳暗花明,撥雲見霧.....,這個開源庫裡有關於普通view,tableView,webView以及WKWebView的截圖的所有例子.不過他的嘗試辦法貌似有問題.他的主要思路有下面五個:
- 將WKWebView的frame拉長和ContentSize的高度保持一致, 然後截圖
- 將WKWebView的frame拉長和ContentSize的高度一致, 然後通過WKWebView的
snapshotViewAfterScreenUpdates
獲取的view進行截圖 - 對WKWebView內部的WKContentView直接截圖
- 將WKScrollView對應的Screen進行拉伸, 然後對WKWebView進行等價拉伸, 再截圖
- 使用私有API
_snapshotRect:intoImageOfWidth:completionHandler
首先哈,前輩對於1-3的辦法直接嘗試得到的結論是截圖到空白,或者只有螢幕部分,對此我表示不認可,因為有的系統下我就是直接1方法達到的,至於其他的幾種方法除了5,我都有涉及部分所以重點講我是怎麼實現的.
這個坑很大.希望大家能夠很好地讀完,
在我經過測試之後發現該截圖與iOS系統版本有關
在iOS最新的11.0以後的話整體對WKWebView的scrollView進行截圖則能夠截全圖片.然後再和tableView的圖片進行拼接即可.
//iOS 11.0 以上的系統用這個方法
+ (UIImage *)captureScrollView:(UIScrollView *)scrollView
{
UIImage* image = nil;
UIGraphicsBeginImageContextWithOptions(scrollView.contentSize, NO, 0.0);
{
CGFloat scale = 1;
CGPoint savedContentOffset = scrollView.contentOffset;
CGRect savedFrame = scrollView.frame;
scrollView.contentOffset = CGPointZero;
scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width * scale, scrollView.contentSize.height * scale + 30);
[scrollView.layerrenderInContext:UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
scrollView.contentOffset = savedContentOffset;
scrollView.frame = savedFrame;
}
UIGraphicsEndImageContext();
if (image != nil) {
return image;
}
returnnil;
}
//將WKWebView的截圖拼接到tableView的下邊即可
但是這種方法對於iOS10的機型便出現了WKWebView的scrollView空白的現象,經過不斷地探索,從某個論壇中找到這樣一個方法:
//iOS 10.0 - 11.0的系統用這個方法
-(UIImage *)convertWholePageToImage:(WKWebView *)wkweb{
CGFloat boundsWidth = wkweb.bounds.size.width;
CGFloat boundsHeight = wkweb.bounds.size.height;
UIScrollView *scrollView = wkweb.scrollView;
CGPoint oldOffset = scrollView.contentOffset;
[scrollView setContentOffset:CGPointZeroanimated:NO];
CGFloat contentHeight = scrollView.contentSize.height;
CGFloat scale = [UIScreenmainScreen].scale;
NSMutableArray *images = [NSMutableArrayarray];
while (contentHeight > 0) {
UIGraphicsBeginImageContextWithOptions(wkweb.bounds.size, NO, scale);
[wkweb.layerrenderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[images addObject:image];
CGFloat offsetY = scrollView.contentOffset.y;
[scrollView setContentOffset:CGPointMake(0, offsetY + boundsHeight) animated:NO];
contentHeight -= boundsHeight;
}//針對webView一螢幕一螢幕的截圖拼接
[scrollView setContentOffset:oldOffset animated:NO];
UIGraphicsBeginImageContextWithOptions(scrollView.contentSize, NO, scale);
for (NSInteger index = 0; index < images.count; index++) {
UIImage *image = images[index];
[image drawInRect:CGRectMake(0, boundsHeight * index, boundsWidth, boundsHeight)];
}
UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return fullImage;
}
很難過這個截圖對於10.0 沒有用,之所以有問題可能跟繪製的方法有關.在前輩的文章裡發現瞭解決的方法- view中任意一個子View包含WKWebView, 則採用
drawViewHierarchyInRect
的方式去擷取檢視 - view中任意一個子View都不包含WKWebView, 則採用
renderInContext
的方式去截圖
所以我直接將rederInContext 換成了 drawViewHierarchyInRect發現可以iOS10.0以上11.0 以下的系統都可以成功的進行截圖.
----------------------iOS8.9 之後更新