用WKWebView 截取整个Html页面

以前使用UIWebview时,想截取整个页面,可以调整内部scrollView的frame,之后调用 scrollView的layer的 render 方法,很方便。

但是在WKWebView上,行不通。

我觉得以前的UIWebview其实是把整个页面都渲染在内存中,只是我们看不到。而WKWebView为了优化内存,只渲染WKWebView的Frame大小的内容。

所以想用WKWebview截取整个页面,必须放大WKWebview的frame。

 webView.frame = CGRect(x: 0, y: 0, width: webView.scrollView.frame.size.width, height: webView.scrollView.contentSize.height);

改变了frame之后,我们就可以利用scrollView.layer.render 去渲染整个页面了。

但是这时候又出现了另一个问题:  渲染网页是需要时间的,把webview的frame扩大后,我们不知道什么时候,系统完成了渲染。比如下面这个例子:

@IBAction func takeScreenshot(){

        webView.frame = CGRect(x: 0, y: 0, width: webView.scrollView.frame.size.width, height: webView.scrollView.contentSize.height);

            let scrollView = self.webView.scrollView

            UIGraphicsBeginImageContextWithOptions(self.webView.scrollView.contentSize,false, UIScreen.main.scale)

            scrollView.layer.render(in: UIGraphicsGetCurrentContext()!)

            let image = UIGraphicsGetImageFromCurrentImageContext()

            let pngData = UIImagePNGRepresentation(image!);

            let dstPath = NSHomeDirectory()+"/Documents/test.png"
            let dstUrl = URL(fileURLWithPath: dstPath)
            do{
                try  pngData?.write(to: dstUrl, options: .atomicWrite)
            }catch{

            }

            print("dest is %@",dstUrl);

            UIGraphicsEndImageContext()
    }
    

由于立即调用了截图函数,webView没有足够的时间渲染,只多渲染了一小部分。

之后,我用下面的代码进行测试,注意,这里延时了0.3s,给了webview一定的渲染时间:

    @IBAction func takeScreenshot(){

        webView.frame = CGRect(x: 0, y: 0, width: webView.scrollView.frame.size.width, height: webView.scrollView.contentSize.height);

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+0.3) {
            let scrollView = self.webView.scrollView

            UIGraphicsBeginImageContextWithOptions(self.webView.scrollView.contentSize,false, UIScreen.main.scale)

            scrollView.layer.render(in: UIGraphicsGetCurrentContext()!)

            let image = UIGraphicsGetImageFromCurrentImageContext()

            let pngData = UIImagePNGRepresentation(image!);

            let dstPath = NSHomeDirectory()+"/Documents/test.png"
            let dstUrl = URL(fileURLWithPath: dstPath)
            do{
                try  pngData?.write(to: dstUrl, options: .atomicWrite)
            }catch{

            }

            print("dest is %@",dstUrl);

            UIGraphicsEndImageContext()
       }

    }
    

下面是结果的截图,一切正常:

那么,如果网页更长,0.3秒一定也不够用,我们怎么知道该延时多少呢?

这时候我又发现了一个函数,是属于UIView的,drawHierarchy,根据api描述,第二个参数好像和渲染有关,能不能解决我们的问题呢,继续测试:

 @IBAction func takeScreenshot(){

        webView.frame = CGRect(x: 0, y: 0, width: webView.scrollView.frame.size.width, height: webView.scrollView.contentSize.height);

            let scrollView = self.webView.scrollView

            UIGraphicsBeginImageContextWithOptions(self.webView.scrollView.contentSize,false, UIScreen.main.scale)

            self.webView.drawHierarchy(in: CGRect(x: 0, y: 0, width: self.webView.scrollView.frame.size.width, height: self.webView.scrollView.contentSize.height), afterScreenUpdates: true)

            let image = UIGraphicsGetImageFromCurrentImageContext()

            let pngData = UIImagePNGRepresentation(image!);

            let dstPath = NSHomeDirectory()+"/Documents/test.png"
            let dstUrl = URL(fileURLWithPath: dstPath)
            do{
                try  pngData?.write(to: dstUrl, options: .atomicWrite)
            }catch{

            }

            print("dest is %@",dstUrl);

            UIGraphicsEndImageContext()

    }

结果还是不行,效果和使用layer的render方法一样!看来afterScreenUpdates这个参数跟网页的渲染无关了。

那么把Webview frame直接扩大为html内容的大小并截图的方式其实是很有问题的,截图时机不好掌握, 内存和cpu的占用也会很大。

这里要推荐一个github上的项目,https://github.com/startry/SwViewCapture, 它的解决思路如下:

1. 截图时机的掌握:每次通过调整视图frame,只渲染一屏的截图,速度很快,只需稍为延迟,即可保证完美截图。

2.内存和cpu:由于每次只处理一屏幕的截图,内容很少,对cpu和内存的冲击都很小。

下面贴出其中的关键代码:

 fileprivate func swContentPageDraw (_ targetView: UIView, index: Int, maxIndex: Int, drawCallback: @escaping () -> Void) {

        // set up split frame of super view
        let splitFrame = CGRect(x: 0, y: CGFloat(index) * targetView.frame.size.height, width: targetView.bounds.size.width, height: targetView.frame.size.height)
        // set up webview frame
        var myFrame = self.frame
        myFrame.origin.y = -(CGFloat(index) * targetView.frame.size.height)
        self.frame = myFrame

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(0.3 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in

            targetView.drawHierarchy(in: splitFrame, afterScreenUpdates: true)

            if index < maxIndex {
                self.swContentPageDraw(targetView, index: index + 1, maxIndex: maxIndex, drawCallback: drawCallback)
            }else{
                drawCallback()
            }
        }
    }
时间: 2025-01-15 09:11:15

用WKWebView 截取整个Html页面的相关文章

iOS WKWebview 网页开发适配指南

iOS WKWebview 网页开发适配指南 微信iOS客户端将于2017年3月1日前逐步升级为WKWebview内核,需要网页开发者提前做好网站的兼容检查和适配.如有问题,可参考文末联系方式,向我们咨询. 背景 WKWebView 是苹果在iOS 8中引入的新组件,目的是提供一个现代的支持最新Webkit功能的网页浏览控件,摆脱过去 UIWebView的老.旧.笨,特别是内存占用量巨大的问题.它使用与Safari中一样的Nitro JavaScript引擎,大大提高了页面js执行速度. 切换方

iOS 8 WKWebView

首先看看这篇文章,写得很好:http://nshipster.cn/wkwebkit/ 再推荐去看看 iOS_8_by_Tutorials 这本书里的 WKWebView相关章节! 我这里说下自己的简单体会: 1.对比UIWebView ,网上说WKWebView的效率要高,到底高多少,不清楚. 2.WKWebView将javascript的注入,以及javascript传回数据的方法标准化了.在UIWebView时代,执行javascript没什么问题,但是从javascript传回数据就麻烦

Python+selenium之截图图片并保存截取的图片

本文转载:http://blog.csdn.net/u011541946/article/details/70141488 http://www.cnblogs.com/timsheng/archive/2012/09/05/2672651.html 介绍如何利用Selenium的方法进行截图,在测试过程中,是有必要截图,特别是遇到错误的时候进行截图.在selenium for Python中主要有三个截图方法,我们挑选其中最常用的一种. 截图技能对于测试人员来说应该是较为重要的一个技能. 在自

iOS-JavaScript向WKWebView传值

一.本地代码所需操作 1.创建viewController并遵守协议 @interface ViewController ()<WKNavigationDelegate,WKScriptMessageHandler,WKUIDelegate> 2.注册ScriptMessageHandler WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; [configuration.userCont

EL表达式处理字符串 是否 包含 某字符串 截取 拆分...............

EL表达式处理字符串 是否 包含 某字符串 截取 拆分............... JSP页面页头添加<%@ taglib uri="/WEB-INF/taglib/c.tld" prefix="c"%><%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>  两个标签页面内容如下: <c:if test=&q

网易严选的wkwebview测试之路

本文来自网易云社区 作者:孙娇 UIWebView是苹果继承于UIView封装的一个加载web内容的类,它可以加载任何远端的web数据展示在你的页面上,你可以像浏览器一样前进后退刷新等操作.不过苹果在iOS8以后推出了WKWebView来加载Web.UIWebView自iOS2就有,WKWebView从iOS8才有,毫无疑问WKWebView是将会逐步取代笨重的UIWebView.且UIWebView存在占用过多内存,js执行效率低等问题.而WKWebView网页加载速度大有提升,占用更少内存.

web端,qq互联以及微信登录接入流程(内嵌页面)总结

前言 实习过程中,我参与了web版相册管家的开发,负责登陆页面的前后端逻辑. 需要在登陆页接入QQ互联和微信扫码登陆,而且是用页面内嵌方式.回头来看其实两者都有文档指导,步骤清楚,并不复杂.但是第一次接触难免踩坑,在此梳理如下,方便今后开发参考. QQ互联 开发文档 https://wiki.connect.qq.com/%E7%BD%91%E7%AB%99%E5%BA%94%E7%94%A8%E6%8E%A5%E5%85%A5%E6%B5%81%E7%A8%8B 应用申请 申请appid和ap

JQuery的用途和功能

jQuery库为Web脚本编程提供了通用的抽象层,使得它几乎适用于任何编程的情形.由天它容易扩展而且不断有新插件面世增强它的功能,所以这里无法涵盖它所有可能的用途和功能.抛开这些就其核心特性而言,jQuery能够满足下列需求:    一.取得页面中的元素. 如果不使用JavaScript库,遍历DOM树,以及查找HTML文档结构中某个特殊的部分,必需编写很多代码.jQuery为准确获取需要操纵的文档元素,提供了可靠而富有效率的选择符机制.    二.修改页面的外观. CSS虽然为呈现方式提供了一

api.openWin

打开window 若 window 已存在,则会把该 window 显示到最前面,如果 url 和之前的 url 有变化,或者 reload 为 true 时,页面会刷新,但是该 window 里面已经打开的 frame 等不会移除 若当前正在进行 openWin.closeWin 等带动画过渡的 window 操作,调用此方法会失效 openWin({params}) params name: 类型:字符串 默认值:无 描述:window 名字,不能为空字符串 url: 类型:字符串 默认值: