
Since iOS 7, when you double-tap the home button, little preview screens are shown above the app icon. Swipe them up and the app is closed. Those preview screens are not live though, they’re simple screenshots that iOS takes before sending an app into the background.
Sometimes it’s not desirable to display confidential information on those preview screens. There is no real way to prevent iOS from taking those screenshots, but it’s easy to detect when an app is sent to the background and quickly change our display before this happens. That way the screenshot is taken of something that we can control.
Method 1: crude yet simple
In its simplest form we could just hide the main window when this happens, and bring it back when the app enters the foreground. We’ll do this in our AppDelegate.m, in applicationWillResignActive and applicationDidBecomeActive respectively:
|
- (void)applicationWillResignActive:(UIApplication *)application { // hide main window self.window.hidden = YES; } - (void)applicationDidBecomeActive:(UIApplication *)application { // bring main window back self.window.hidden = NO; } |
This will result in our app showing a black screen instead of our “real” content.
Method 2: elegant and subtle
The problem with the above approach is that the transition between the black screen and our app’s content is a plain cut, and because everything else in iOS transitions nicely with fades and slides, the cut looks a little out of place.
One solution is to create our own UIView and overlay our interface with it. UIViews can be faded in and out thanks to their alpha values and a UIView singleton. As an added benefit we get to choose which colour we’d like our screen to be – just in case black isn’t desirable. Let’s use white instead:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
- (void)applicationWillResignActive:(UIApplication *)application { // fill screen with our own colour UIView *colourView = [[UIView alloc]initWithFrame:self.window.frame]; colourView.backgroundColor = [UIColor whiteColor]; colourView.tag = 1234; 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:1234]; // fade away colour view from main view [UIView animateWithDuration:0.5 animations:^{ colourView.alpha = 0; } completion:^(BOOL finished) { // remove when finished fading [colourView removeFromSuperview]; }]; } |
This looks more complicated than it really is: in the first method we’ll create a standard UIView called colourView and give it the colour of our choice. We’ll also set the alpha value to 0 so it’s transparent. Since we won’t have a reference to this view we’ll give it a tag so we can identify and fade it out again later. 1234 is completely arbitrary – pick your favourite integer here.
As we bring up the view and add it to the main window’s view it’s invisible. animateWithDuration will fade it in over the course of 0.5 seconds, resulting in a subtle fade in. Now we’ll see white and iOS takes a screenshot – no cuts, no popping.
When we get back from the background we’ll first grab a reference to our view – thanks to the arbitrary tag this is really easy. Next we’ll use the same animateWithDuration method and fade the alpha value back to 0 over the course of 0.5 seconds. Longer durations work fine here too, but anything over 2 seconds gives the impression of lag and slowness.
The animateWithDuration comes in two flavours, one of which gives us a completion block so we can execute code when the fade is done. We’ll take this opportunity to remove our view rather than let it linger there in its transparent appearance.
Method 3: bring your own picture
If a solid colour is not snazzy enough we can replace the UIView with a UIImageView and initialise it with a snazzy picture:
|
- (void)applicationWillResignActive:(UIApplication *)application { // let's use a picture instead UIImageView *colourView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"snazzy-picture.png"]]; [self.window addSubview:colourView]; [self.window bringSubviewToFront:colourView]; // fade in the view [UIView animateWithDuration:0.5 animations:^{ colourView.alpha = 1; }]; } |
The fade out method is the same. You may need to check device orientation and size here to provide a picture that covers the entire view, or use one that’s 2048×2048 to be on the safe side.
Many developers (including PayPal) choose to grab a screenshot of your app manually at this point and apply a blur effect as if the screenshot is presented through frosted glass.
Demo Project
I’ve added a sample project to GitHub so you can see the above in action: