Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I can't capture the screenshot of a WKWebView

I'm trying to capture a screenshot of a WKWebView but my method doesn't work properly, it returns a solid color as if the layer tree was empty, while it seems to work on other views.

- (UIImage *)screenshot
{
    UIImage *screenshot;

    UIGraphicsBeginImageContext(self.frame.size);

    [self.layer renderInContext:UIGraphicsGetCurrentContext()];

    screenshot = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return screenshot;
}
like image 805
Vulkan Avatar asked Nov 10 '14 12:11

Vulkan


5 Answers

This Stackoverflow answer solved it for me on iOS 8 with a WKWebView where [view snapshotViewAfterScreenUpdates:] and [view.layer renderInContext:] either returned solid black or white:

UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, 0);
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
UIImage* uiImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
like image 148
user2067021 Avatar answered Oct 28 '22 08:10

user2067021


There's still a bug with the WKWebView but you can work your way around it by using another function:

[webView snapshotViewAfterScreenUpdates:NO or YES];

It works.

like image 38
Vulkan Avatar answered Oct 28 '22 08:10

Vulkan


Please refer to this answer

iOS 11.0 and above, Apple has provided following API to capture snapshot of WKWebView.

@available(iOS 11.0, *)
    open func takeSnapshot(with snapshotConfiguration: WKSnapshotConfiguration?, completionHandler: @escaping (UIImage?, Error?) -> Swift.Void)

Sample usage:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

        if #available(iOS 11.0, *) {
            webView.takeSnapshot(with: nil) { (image, error) in
                //Do your stuff with image
            }
        }
    }
like image 2
Maverick Avatar answered Oct 28 '22 07:10

Maverick


The drawViewHierarchyInRect method will work, but will cause the screen to briefly flash.

If you need high performance (capturing many frames quickly), I suggest adding the WKWebView to your window somewhere (even if you push it out of the visible area with the frame offset or make it transparent). I found that renderInContext is much faster, and works fine as long as the view is in the view hierarchy of the window.

like image 1
scosman Avatar answered Oct 28 '22 08:10

scosman


Here are my two points. Before the iOS 10.3.1 renderInContext used to work well for the WKWebView. But only if a WKWebView is included in a presented view hierarchy. In other words, the system is drawing it on the screen.

In the iOS 10.3.1, renderInContext doesn't work for me. In the same moment, drawViewHierarchyInRect works fine in the iOS 10.3.1. But only if it's in the view hierarchy! Even worse. When I was trying to get a snapshot of the WKWebView, which wasn't presented on the current screen, the original view became invalidated. Thus taking screenshot can break a WKWebView.

Here is my workaround.

  1. I save a snapshot (UIImage) with drawViewHierarchyInRect every time when I need it. But only if the WKWebView is on the screen.
  2. If the WKWebView isn't in the view hierarchy I use a saved snapshot.
like image 1
Vladimir Vlasov Avatar answered Oct 28 '22 08:10

Vladimir Vlasov