iOS 原生和H5结合 WKWebView的长截图问题

本文介绍了在iOS应用中,如何处理WKWebView的长截图问题,包括在不同系统版本下的截图策略,如通过调整WKWebView的frame和利用scrollView的截图方法,并提供了一种适用于iOS 10.0至11.0系统的方法。

前言

        最近的一版,有很多....泯灭人性的地方.遇到了一些之前没有遇到的问题,也有了一些自己的体会,先说一个跟技术分享没有关系的经验问题: 一定不要为了省代码而作过多的逻辑判断(主要是过不了自己心里的一关),尤其是在周期紧的情况下,无论是写还是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.layer renderInContext:UIGraphicsGetCurrentContext()];

        image = UIGraphicsGetImageFromCurrentImageContext();

        scrollView.contentOffset = savedContentOffset;

        scrollView.frame = savedFrame;

    }

    UIGraphicsEndImageContext();

    

    if (image != nil) {

        return image;

    }

    return nil;

}

//将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:CGPointZero animated:NO];

    CGFloat contentHeight = scrollView.contentSize.height;

    CGFloat scale = [UIScreen mainScreen].scale;

    

    NSMutableArray *images = [NSMutableArray array];

    while (contentHeight > 0) {

        UIGraphicsBeginImageContextWithOptions(wkweb.bounds.size, NO, scale);

        [wkweb.layer renderInContext: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 之后更新

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值