1. 程式人生 > >iOS 原生和H5結合 WKWebView的長截圖問題

iOS 原生和H5結合 WKWebView的長截圖問題

前言

        最近的一版,有很多....泯滅人性的地方.遇到了一些之前沒有遇到的問題,也有了一些自己的體會,先說一個跟技術分享沒有關係的經驗問題: 一定不要為了省程式碼而作過多的邏輯判斷(主要是過不了自己心裡的一關),尤其是在週期緊的情況下,無論是寫還是review都是一個大問題.即使想達到節省程式碼量的目的.這些邏輯判斷最好寫在model裡.不要在頁面裡做過多的展示判斷.否則....你的下場就和我一樣.....

        言歸正傳,WKWebView的截圖就是一個坑,你想躲避他,回頭便還是會遇到他.其實如果只是單純的WKWebView的截圖相比較之下相對容易一點,讀了前輩的文章基本上你有兩條路可以走: 1.將WKWebView的contentOffSet進行設定一屏一屏的截圖,然後再拼接起來假裝達到長截圖的效果; 2.將WKWebView放在一個父檢視上然後通過更改這個父檢視的frame 的y來截的當前父檢視的截圖,然後再一屏一屏的截下來.假裝達到長截圖的效果.....於是乎我不信其邪,走上了一條長達1天半的歪路.不過還是有收穫,現將前輩的網址貼過來,供大家瞻仰:

我只是想要截個屏.而且和很多我看過的解決blog不一樣的是前輩是個有始有終的人.... 他還有一個截圖續,完美的解決了我的一些困惑...並非問題.

        為了能夠方便大家,還得去前輩那裡看具體的技術點.我簡單的形容一下我的理解,和進行探索的過程.

場景描述   

        在一個tableView 下我需要接上一個webView.我有三條路: 

  1. 放在tableView的tableFooterView上,限制webView的滑動整體讓tableView滑動來彌補.當然後期會解決手勢衝突
  2. 放在tableView的Cell中
  3. 將tableView作為webView的頭檢視,然後設定webView的contentInset,之前的blog中有相關操作

        然後我選擇了1

主要矛盾   

        長截圖.....一個原生加webView的長截圖,一個webView大部分時間在螢幕外的長截圖....一個要截tableView 還要截一個放在他footer裡的WKWebView.....對於初出茅廬的我....很是塞心...之前專案裡這種部分都是請求介面得到image....不過鑑於週期短還是不給別人添麻煩了...而且那樣還得一個個生成....其實已經與自己的想法背離.

        於是看到了前輩的blog,前輩有個開源庫SwViewCapture,雖然...我...下下來...直接執行截圖WKWebView的時候直接就崩潰了...但是其思路讓我豁然開朗,茅塞頓開.柳暗花明,撥雲見霧.....,這個開源庫裡有關於普通view,tableView,webView以及WKWebView的截圖的所有例子.不過他的嘗試辦法貌似有問題.他的主要思路有下面五個:

  1. 將WKWebView的frame拉長和ContentSize的高度保持一致, 然後截圖
  2. 將WKWebView的frame拉長和ContentSize的高度一致, 然後通過WKWebView的snapshotViewAfterScreenUpdates獲取的view進行截圖
  3. 對WKWebView內部的WKContentView直接截圖
  4. 將WKScrollView對應的Screen進行拉伸, 然後對WKWebView進行等價拉伸, 再截圖
  5. 使用私有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 之後更新