4

I'm looking for the proper way to snapshot the entire iPhone screen including the keyboard.

i found some code to snapshot the screen:

CGRect screenCaptureRect = [UIScreen mainScreen].bounds;
UIView *viewWhereYouWantToScreenCapture = [[UIApplication sharedApplication] keyWindow];
//screen capture code
UIGraphicsBeginImageContextWithOptions(screenCaptureRect.size, NO, [UIScreen mainScreen].scale);
[viewWhereYouWantToScreenCapture drawViewHierarchyInRect:screenCaptureRect afterScreenUpdates:NO];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

but it doesn't capture the keyboard as well. it looks like the keyWindow doesn't include the keyboard view.

btw I need UIImage as final result, not UIView, so I can't use other snapshot API's.

Any ideas of to do that and with best performance?

Eyal
  • 10,777
  • 18
  • 78
  • 130

3 Answers3

9

Keyboard is placed in other window. And in iOS9 keyboard accessory placed in different one. So the best solution is to render all windows.

Here is working code:

- (UIImage*)fullScreenShot {
    CGSize imgSize = [UIScreen mainScreen].bounds.size;
    UIGraphicsBeginImageContextWithOptions(imgSize, NO, 0);
    for (UIWindow* window in [UIApplication sharedApplication].windows) {
        if (![window respondsToSelector:@selector(screen)] || window.screen == [UIScreen mainScreen]) {
            [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
        }
    }
    UIImage* img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}
zxcat
  • 2,054
  • 3
  • 26
  • 40
2

You are right, the keyboard is displayed in another window. So instead of getting only one window using [[UIApplication sharedApplication] keyWindow], you should get all windows using [[UIApplication sharedApplication] windows] and for each of them call [viewWhereYouWantToScreenCapture drawViewHierarchyInRect:screenCaptureRect afterScreenUpdates:NO] so that all of them are drawn inside one image context.

bzz
  • 5,556
  • 24
  • 26
1

iOS renders keyboard under a window with the description UITextEffectsWindow.

You can iterate all windows using and find the right one using:

for (UIWindow *window in [[UIApplication sharedApplication] windows]) { if ([window.class.description isEqualToString:@"UITextEffectsWindow"]) { return window; } }

When you're done, you can render it into your context using renderInContext or drawViewHierarchyInRect. renderInContext might be slower but safer (because it's done on the main thread,) and drawViewHierarchyInRect is faster (doesn't affect the main thread,) but might crash due to a bug in iOS code.

gilm
  • 7,690
  • 3
  • 41
  • 41
  • is this using a private api? – matteok Dec 13 '16 at 13:49
  • Taking a screenshot of the keyboard is not using private api. However, you won't be seeing custom keyboard (such as Swiftkey) in your screenshot. The window is not from your process. – gilm Dec 13 '16 at 19:11