Prevent iOS from taking screen capture of app before going into background
Asked Answered
G

10

38

You all might know that iOS takes a screen shot of your application before throwing it into the background. This is usually for a better User experience like quick animation to bring the app back and so on. I don't want my app screen shot to be stored on the device, but I want the multitasking to still exist.

I came out with a solution but I'm not sure if I'm heading in the right direction. So, when the applicationDidEnterBackground is called -- I put in an overlay image that will be captured by the OS, and once the app enters foreground, I will remove the overlay. I'm not sure if this is going to work but I'm on my way to implement this. Meanwhile, any other thoughts on this will help me figure out the optimal way of attacking this issue.

Garrulous answered 22/9, 2011 at 19:7 Comment(3)
any reason why you dont want iOS to do this? As yourself said, screenshot is taken to perform quick animations...Buffet
I have confidential data of the user.. so there are some 3rd party tools like iPhone explorer where u can go into the iOS file system and extract the images. I don't want to compromise with this data... Hence i m planing on implementing this approach.Garrulous
Where this screenshot will store in iPhone which taken by OS? @GarrulousSatang
V
37

You are on the right track. This is Apple's recommended way to do this as noted in the iOS Application Programming Guide:

Remove sensitive information from views before moving to the background. When an application transitions to the background, the system takes a snapshot of the application’s main window, which it then presents briefly when transitioning your application back to the foreground. Before returning from your applicationDidEnterBackground: method, you should hide or obscure passwords and other sensitive personal information that might be captured as part of the snapshot.

Vespertine answered 22/9, 2011 at 19:28 Comment(5)
Do you know where on the device these screenshots are temporarily stored?Denesedengue
/Library/Caches/Snapshots/$(BUNDLE_IDENTIFIER)/ is the path inside the apps sandbox.Alleris
By the way, you can download your apps sandbox-container using Xcode's DeviceManager.Alleris
Updated LinkHeuristic
Isn't it supposed to be applicationWillResignActive now?Subspecies
R
16

Need to write the code in Application life cycle methods, here we are putting an imageView while the app animate to background :

-(void)applicationWillResignActive:(UIApplication *)application
{
    imageView = [[UIImageView alloc]initWithFrame:[self.window frame]];
    [imageView setImage:[UIImage imageNamed:@"Splash_Screen.png"]];
    [self.window addSubview:imageView];
}

Here is the code to remove the imageView:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    if(imageView != nil) {
        [imageView removeFromSuperview];
        imageView = nil;
    }
}

It is working and properly tested.

Razo answered 29/10, 2014 at 11:41 Comment(3)
But the image is not alligned for iPad.Procaine
Be careful 'applicationWillResignActive' is also called when an alert dialog is shown. Might not be when you want to show this imageview.Paranymph
tested this in iOS 11... it's not working intermittentlyGynecologist
N
12

I came across the same issue, and my research has lead me to the following answers:

  • set a blurry screen overlay before the app goes in the background and once the app becomes active remove this overlay

  • if it is iOS 7 or later you can use the function ignoreSnapshotOnNextApplicationLaunch

See in apple documentation: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/instm/UIApplication/ignoreSnapshotOnNextApplicationLaunch

I hope this helps somebody.

Nabataean answered 12/11, 2013 at 16:44 Comment(5)
ignoreSnapshotOnNextApplicationLaunch sounds interesting but this is not preventing iOS of taking a screenshot in any case, right?Hotien
I haven't tried this function in iOS 8 but in iOS 7 didn't prevent from taking the screenshot.Nabataean
I'm having issues here. No matter what I do, I can't stop the app snapshotting an incorrect window. In this page, It Sayeth: "...call this method to let UIKit know that it should use your app’s default launch image instead of the snapshot. You must call this method from within the code you use to preserve your app’s state." (To be continued)Pease
(Continued from Above) Now, that last line is the kicker. Simply calling this in my applicationWillResignActive callback doesn't work. However, I'm not exactly sure what Apple means by "the code you use to preserve your app’s state."Pease
It sounds like they're referring to the code you use for persisting your state beyond restartsLatvina
T
10

Working methods in AppDelegate, swift 4.2:

func blurScreen(style: UIBlurEffect.Style = UIBlurEffect.Style.regular) {
    screen = UIScreen.main.snapshotView(afterScreenUpdates: false)
    let blurEffect = UIBlurEffect(style: style)
    let blurBackground = UIVisualEffectView(effect: blurEffect)
    screen?.addSubview(blurBackground)
    blurBackground.frame = (screen?.frame)!
    window?.addSubview(screen!)
}

func removeBlurScreen() {
    screen?.removeFromSuperview()
}

Where is:

weak var screen : UIView? = nil // property of the AppDelegate

Call these methods in needed delegate methods:

func applicationWillResignActive(_ application: UIApplication) {
    blurScreen()
}

func applicationDidBecomeActive(_ application: UIApplication) {
    removeBlurScreen()
}
Trencher answered 27/11, 2018 at 16:13 Comment(1)
There's an error in your style: UIBlurEffect.Style = UIBlurEffect.Style.regular clause. Style is not a member type of UIBlurEffect.Tenor
E
6

Your approach is exactly the correct and only way to do it. Place an overlay view and remove it later. It is valid to do this if your app shows sensitive data that you don't want to be cached in image format anywhere.

Eddra answered 22/9, 2011 at 19:28 Comment(0)
W
3

Apple Doc https://developer.apple.com/library/archive/qa/qa1838/_index.html

Note: Your implementation of -applicationDidEnterBackground: should not start any animations (pass NO to any animated: parameter). The snapshot of your application's window is captured immediately upon returning from this method. Animations will not complete before the snapshot is taken.

Converted Apple code in swift 4.2 App delegate i declared

func applicationDidEnterBackground(_ application: UIApplication) {
    // Your application can present a full screen modal view controller to
    // cover its contents when it moves into the background. If your
    // application requires a password unlock when it retuns to the
    // foreground, present your lock screen or authentication view controller here.

    let blankViewController = UIViewController()
    blankViewController.view.backgroundColor = UIColor.black

    // Pass NO for the animated parameter. Any animation will not complete
    // before the snapshot is taken.
    window.rootViewController?.present(blankViewController, animated: false)
}

func applicationWillEnterForeground(_ application: UIApplication) {
    // This should be omitted if your application presented a lock screen
    // in -applicationDidEnterBackground:
    window.rootViewController?.dismiss(animated: false) false
}
Whenever answered 23/4, 2018 at 21:18 Comment(5)
it is still working can you send screenshot when app is in background?Whenever
It works in a way that it really creates a sub view and etc but the size of the window is already small by the time I can add it thus leading to a rectangle in the middle on my view appearing on the snapshot but not covering the whole screen. I ended up pushing a launch screen controller as the recommend in the docs and removing it later...Diclinous
btw i am using launch screen image in this.Whenever
it says "The page you’re looking for can’t be found."Whenever
This is close, but not gonna work when UIAlertController is presented. Going with : // enterBackground [self.window addSubview:self.splashView]; // enterForeground [self.splashView removeFromSuperview]; will work with UIAlertControllerNo
E
1

Improvement in Depak Kumar post : Make a property UIImage *snapShotOfSplash;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] ignoreSnapshotOnNextApplicationLaunch];
snapShotOfSplash =[UIImage imageNamed:@"splash_logo"];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {


    self.overlayView = [[UIImageView alloc]initWithFrame:[self.window frame]];
    self.overlayView.backgroundColor = [UIColor whiteColor];
    [self.overlayView setImage:snapShotOfSplash];
    [self.overlayView setContentMode:UIViewContentModeCenter];
    [self.window addSubview:self.overlayView];
    [self.window bringSubviewToFront:self.overlayView]; }

- (void)applicationDidBecomeActive:(UIApplication *)application {
if(self.overlayView != nil) {
        [self.overlayView removeFromSuperview];
        self.overlayView = nil;
    }
}
Edva answered 14/12, 2017 at 8:27 Comment(0)
P
1

Implementation with some animation while going in background and reverse action

   - (void)applicationWillResignActive:(UIApplication *)application
{
     //     fill screen with our own colour
        UIView *colourView = [[UIView alloc]initWithFrame:self.window.frame];
        colourView.backgroundColor = [UIColor blackColor];
        colourView.tag = 1111;
        colourView.alpha = 0;
        [self.window addSubview:colourView];
        [self.window bringSubviewToFront:colourView];

        // fade in the view
        [UIView animateWithDuration:0.5 animations:^{
            colourView.alpha = 1;
        }];

}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // grab a reference to our coloured view
    UIView *colourView = [self.window viewWithTag:1111];
    // fade away colour view from main view
    [UIView animateWithDuration:0.5 animations:^{
        colourView.alpha = 0;
    } completion:^(BOOL finished) {
        // remove when finished fading
        [colourView removeFromSuperview];
    }];

 }
Proficiency answered 30/1, 2019 at 17:59 Comment(0)
A
1

swift 4.0 version.

for use custom icon

first add this line at top of AppDelegate

var imageView: UIImageView?

and add this:

func applicationDidEnterBackground(_ application: UIApplication) {
    imageView = UIImageView(frame: window!.frame)
    imageView?.image = UIImage(named: "AppIcon")
    window?.addSubview(imageView!)
}

func applicationWillEnterForeground(_ application: UIApplication) {
    if imageView != nil {
        imageView?.removeFromSuperview()
        imageView = nil
    }
}

background with black color

func applicationDidEnterBackground(_ application: UIApplication) {
    let blankViewController = UIViewController()
    blankViewController.view.backgroundColor = UIColor.black
    window?.rootViewController?.present(blankViewController, animated: false)
}

func applicationWillEnterForeground(_ application: UIApplication) {
    window?.rootViewController?.dismiss(animated: false)
}
Aubarta answered 2/5, 2019 at 18:46 Comment(0)
M
-1

In iOS 7 you could use the allowScreenShot to stop the ability all together.

See: Apple Developer: Configuration Profile Reference:

allowScreenShot


Boolean
Optional. If set to false, users can’t save a screenshot of the display and are prevented from capturing a screen recording; it also prevents the Classroom app from observing remote screens. Defaults to true.

Availability: Updated in iOS 9.0 to include screen recordings.

Mallissa answered 7/7, 2014 at 15:15 Comment(2)
@ParikksitBhisay (I realized it's very old, but I wanted to mention since I'm here to deal with spam anyway) This is a short, possibly bad answer, but it is an answer; it mentions the property required.Schorl
This is only available if the device is under configuration management - eg in an Enterprise environment, it is not available for regular AppStore apps.Vanish

© 2022 - 2024 — McMap. All rights reserved.