Intercepting initial ViewController on applicationDidBecomeActive, before anything appears - ios

I'd like to display a custom View Controller immediately each time the user returns to the app. Currently I can do this easily with didFinishLaunchingWithOptions by simply choosing what the initial rootViewController will be before anything appears on the screen.
However if I put the intercept VC in applicationDidBecomeActive, then the previous VC is on screen for half a second, before I can load the intercept.
How can I make it so when the app is put back into foreground the VC immediately on screen is my custom intercept? That VC will then restore the foreground view on its own.
FYI: I am using this intercept to verify the user is within supported location, then allowing the app to return to state or display an unsupported screen.

There are two solutions to this problem.
Solution:1 You could write your interceptVC - functionality on the application's delegate method
func applicationWillEnterForeground(application: UIApplication)
instead of writing in
func applicationDidBecomeActive(application: UIApplication)
Solution:2
As you did the interceptVC - functionary on applicationDidBecomeActive can also be applied to while application went background,
func applicationDidEnterBackground(application: UIApplication)
so that, when the applicationDidBecomActive delay can be covered.
Note: Here the application once entered background will always has the interceptVC in the background.

Solution by OP.
A solution I used was to set a custom background image when the app resigns active. This is also the screen shown in the multitask selector. When the app resumes active it is the initial screen shown until my interceptVC loads. The image I used is the same background as my interceptVC so it appears instant. This was also easier than attempting to preload the intercept VC on resign of active. Some fade animations are also used on the imageview to make it smoother and non-jarring.
- (void)applicationWillResignActive:(UIApplication *)application {
// fill screen with our own imageView
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.window.frame];
if(IS_IPHONE_6P){
imageView.image = [UIImage imageNamed:#"splash_1242x2208.png"];
} else if(IS_IPHONE_6){
imageView.image = [UIImage imageNamed:#"splash_750x1334.png"];
} else if(IS_IPHONE_5){
imageView.image = [UIImage imageNamed:#"splash_640x1136.png"];
} else if(IS_IPHONE_4_OR_LESS){
imageView.image = [UIImage imageNamed:#"splash_640x960.png"];
} else {
// should not happen
imageView.image = [UIImage imageNamed:#"splash_750x1334.png"];
}
imageView.tag = 1234;
imageView.alpha = 0;
[self.window addSubview:imageView];
[self.window bringSubviewToFront:imageView];
// fade in the view
[UIView animateWithDuration:0.5 animations:^{
imageView.alpha = 1;
}];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// grab a reference to our imageView
UIView *imageView = [self.window viewWithTag:1234];
// fade away imageView view from main view
[UIView animateWithDuration:0.5 animations:^{
imageView.alpha = 0;
} completion:^(BOOL finished) {
// remove when finished fading
[imageView removeFromSuperview];
}];
}

Related

Overlay an image when app is inactive

I'm using these code to
1) overlay an image when the app is inactive (double tap the home button twice).
2) Remove the image when the app is active (reopen the app)
In appdelegate.h file:
#property (nonatomic, strong) UIImageView *splashScreenImageView;
In appdelegate.m file:
- (void)applicationWillResignActive:(UIApplication *)application
{
UIImage *splashScreenImage = [UIImage imageNamed:#"BackgroundScreenCaching"];
_splashScreenImageView = [[UIImageView alloc] initWithImage:splashScreenImage];
[self.window addSubview:_splashScreenImageView];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(_splashScreenImageView != nil) {
[_splashScreenImageView removeFromSuperview];
_splashScreenImageView = nil;
}
}
Problem:
However, SOMETIME when pressing the home button twice, the iOS still caches the app screen with sensitive information instead of the overlay image in iOS 11. Tested no issue in iOS10.
Updated
Issue still persist after changing to this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL result = [super application:application didFinishLaunchingWithOptions:launchOptions];
...
UIImage *splashScreenImage = [UIImage imageNamed:#"BackgroundScreenCaching"];
_splashScreenImageView = [[UIImageView alloc] initWithImage:splashScreenImage];
[_splashScreenImageView setFrame:self.window.bounds];
return result;
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
if(_splashScreenImageView != nil) {
[_splashScreenImageView removeFromSuperview];
}
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
[self.window addSubview:_splashScreenImageView];
}
I found a tricky way and it works with iOS 11 or iOS 10.
In Appdelegate.m file:
#implementation AppDelegate {
UIImageView *splashScreenImageView;
UIViewController *viewController;
}
Add this code in didFinishLaunchingWithOptions to set image and update frame
splashScreenImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
splashScreenImageView.image = [UIImage imageNamed:#"BackgroundScreenCaching"];
Implement this method for getting topmost view controller
- (UIViewController *)topViewController{
return [self topViewController:[UIApplicationsharedApplication].keyWindow.rootViewController];
}
- (UIViewController *)topViewController:(UIViewController *)rootViewController
{
if (rootViewController.presentedViewController == nil) {
return rootViewController;
}
if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self topViewController:lastViewController];
}
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
return [self topViewController:presentedViewController];
}
Now in applicationWillResignActive method first get the top viewController and set splashScreenImageView on that view as subview
- (void)applicationWillResignActive:(UIApplication *)application {
viewController = [self topViewController];
[viewController.view addSubview:splashScreenImageView];
}
Finally in applicationDidBecomeActive when app open first remove the overlay image and open app
- (void)applicationDidBecomeActive:(UIApplication *)application {
[splashScreenImageView removeFromSuperview];
}
This tricks will work.
Your code should work fine ,
May be your app didn't get time to alloc your imageView on time when applicationWillResignActive called
and you are re-creating object every time . with [UIImageView alloc] initWithImage
So my suggestion is put this code in didFinishLaunching
UIImage *splashScreenImage = [UIImage imageNamed:#"BackgroundScreenCaching"];
_splashScreenImageView = [[UIImageView alloc] initWithImage:splashScreenImage];
and just add subview on UIWindow and remove it when applicationDidBecomeActive
Also bring _splashScreenImageView to front !!
Hope it may solve your problem
Good Luck
UPDATE
to add in main queue
dispatch_async(dispatch_get_main_queue(), ^{
[self.window addSubview:_splashScreenImageView];
[self.window bringSubviewToFront:_splashScreenImageView];
});
to remove in main queue
dispatch_async(dispatch_get_main_queue(), ^{
[_splashScreenImageView removeFromSuperview];
});
UPDATE 2
according to https://developer.apple.com/library/content/qa/qa1838/_index.html
and
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html
Prepare for the App Snapshot
Shortly after an app delegate’s applicationDidEnterBackground: method returns, the system takes a snapshot of the app’s windows. Similarly, when an app is woken up to perform background tasks, the system may take a new snapshot to reflect any relevant changes. For example, when an app is woken to process downloaded items, the system takes a new snapshot so that can reflect any changes caused by the incorporation of the items. The system uses these snapshot images in the multitasking UI to show the state of your app.
If you make changes to your views upon entering the background, you can call the snapshotViewAfterScreenUpdates: method of your main view to force those changes to be rendered. Calling the setNeedsDisplay method on a view is ineffective for snapshots because the snapshot is taken before the next drawing cycle, thus preventing any changes from being rendered. Calling the snapshotViewAfterScreenUpdates: method with a value of YES forces an immediate update to the underlying buffers that the snapshot machinery uses.
Try to present temp view controller applicationDidEnterBackground as done in demo of Apple
I fix your bug like this:
#import "AppDelegate.h"
#interface AppDelegate () {
UIImageView *test ;
}
#end
#implementation AppDelegate
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIImage *splashScreenImage = [UIImage imageNamed:#"ic_target_black"];
test = [[UIImageView alloc] initWithImage:splashScreenImage];
[self.window addSubview:test];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
if (test) {
[test removeFromSuperview];
}
}
#end
Do this two simple steps to set your black image when double click the app and it is in recent apps list. And remove the black image when the application becomes active.
#interface AppDelegate (){
UIImageView *test ;
}
- (void)applicationWillResignActive:(UIApplication *)application {
UIImage *splashScreenImage = [UIImage imageNamed:#"ss.png"];
test = [[UIImageView alloc] initWithImage:splashScreenImage];
[self.window addSubview:test];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
if (test) {
[test removeFromSuperview];
}
}

iOS 11: Is it possible to block screen recording?

I have an app which plays video, and I don't want people to use the new iOS-11 feature to record these videos and make them public. That feature is described here.
I could not find any documentation regarding an option for my app to prevent users from recording it.
Can anybody please guide me to anything related to this?
Thank you!
I am publishing here the official response from Apple Developer Technical Support (DTS):
While there is no way to prevent screen recording, as part of iOS 11, there are new APIs on UIScreen that applications can use to know when the screen is being captured:
UIScreen.isCaptured Instance Property
UIScreenCapturedDidChange Notification Type Property
The contents of a screen can be recorded, mirrored, sent over AirPlay, or otherwise cloned to another destination. UIKit sends the UIScreenCapturedDidChange notification when the capture status of the screen changes.
The object of the notification is the UIScreen object whose isCaptured property changed. There is no userInfo dictionary. Your application can then handle this change and prevent your application content from being captured in whatever way is appropriate for your use.
HTH!
The feature is available on and above iOS11. Better keep it inside didFinishLaunchingWithOptions
Objective-C syntax
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (#available(iOS 11.0, *)) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(screenCaptureChanged) name:UIScreenCapturedDidChangeNotification object:nil];
}
return YES;
}
-(void)screenCaptureChanged{
if (#available(iOS 11.0, *)) {
BOOL isCaptured = [[UIScreen mainScreen] isCaptured];// will keep on checking for screen recorder if it is runnuning or not.
if(isCaptured){
UIView *colourView = [[UIView alloc]initWithFrame:self.window.frame];
colourView.backgroundColor = [UIColor blackColor];
colourView.tag = 1234;
colourView.alpha = 0;
[self.window makeKeyAndVisible];
[self.window addSubview:colourView];
// fade in the view
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 1;
}];
}else{
// 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];
}];
}
} else {
// Fallback on earlier versions
// grab a reference to our coloured view
UIView *colourView = [self.window viewWithTag:1234];
if(colourView!=nil){
// fade away colour view from main view
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 0;
} completion:^(BOOL finished) {
// remove when finished fading
[colourView removeFromSuperview];
}];
}
}
}

Display a view or splash screen before applicationDidEnterBackground (to avoid active view screenshot)

I have confidential informations in my app, so I would like to hide them with a splash screen when the app is about to be moved to background.
I do run the app on iOS6 and further.
I tried to display the view in applicationWillResignActive but the problem is it display the splash screen even when user swipe control panel for example. I want it to show only when the app is moved to background.
I tried to displayed my splashScreen in applicationDidEnterBackground but it takes the screenShot before so informations are displayed at restoration during the animation.
Here the spirit of what I want :
- (void)applicationDidEnterBackground:(UIApplication *)application {
[_window addSubview:__splashController.view];
}
I think the problem is that you are testing in simulator. On device, it should work fine.
I tested this and it worked. Add an imageview with your splash image when app enters in background -
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.window.bounds];
imageView.tag = 101; // Give some decent tagvalue or keep a reference of imageView in self
// imageView.backgroundColor = [UIColor redColor];
[imageView setImage:[UIImage imageNamed:#"Default.png"]]; // assuming Default.png is your splash image's name
[UIApplication.sharedApplication.keyWindow.subviews.lastObject addSubview:imageView];
}
And when app comes back in foreground -
- (void)applicationWillEnterForeground:(UIApplication *)application
{
UIImageView *imageView = (UIImageView *)[UIApplication.sharedApplication.keyWindow.subviews.lastObject viewWithTag:101]; // search by the same tag value
[imageView removeFromSuperview];
}
NOTE - On simulator (iOS 7.0), the added subview is not show when you check by pressing home button twice (Cmd + H), but on device it works as expected (like paypal, BofA apps)
EDIT: (Additional info)
In addition to obscuring/replacing sensitive information by adding subview / blur as explained above, iOS 7 provides you ability to ignore the screen snapshot via ignoreSnapshotOnNextApplicationLaunch of UIApplication inside applicationWillResignActive or applicationDidEnterBackground.
UIApplication.h
// Indicate the application should not use the snapshot on next launch, even if there is a valid state restoration archive.
// This should only be called from methods invoked from State Preservation, else it is ignored.
- (void)ignoreSnapshotOnNextApplicationLaunch NS_AVAILABLE_IOS(7_0);
Also, allowScreenShot flag can be explored in Restrictions Payload.
Swift 3.0 Answer for those who are to lazy to translate.
func applicationDidEnterBackground(_ application: UIApplication) {
let imageView = UIImageView(frame: self.window!.bounds)
imageView.tag = 101
imageView.image = ...
UIApplication.shared.keyWindow?.subviews.last?.addSubview(imageView)
}
func applicationWillEnterForeground(_ application: UIApplication) {
if let imageView : UIImageView = UIApplication.shared.keyWindow?.subviews.last?.viewWithTag(101) as? UIImageView {
imageView.removeFromSuperview()
}
}
Had the same issue, essentially I was using applicationDidEnterBackground to show a UIWindow on top of the content, but in iOS8 it didn't work as it did in iOS7.
The solution I found was to create the UIWindow in applicationWillResignActive but make it hidden securityWindow.hidden = YES; and then in applicationDidEnterBackground all I would do would be to change securityWindow.hidden = NO.
This seems to work exactly as iOS7 obscuring the content when multi tasking without affecting the view when using NotificationCenter or ControlPanel.
Don't know why, but none of the methods described here worked for me. I was simply trying to cover the screen for security reasons. So, what helped was a Technical Q&A from Apple: https://developer.apple.com/library/ios/qa/qa1838/_index.html
I guess the main difference is using a UIViewController? Anyways, the following code works perfectly for me on IOS 9.1:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIViewController *blankViewController = [UIViewController new];
blankViewController.view.backgroundColor = [UIColor blackColor];
[self.window.rootViewController presentViewController:blankViewController animated:NO completion:NULL];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[self.window.rootViewController dismissViewControllerAnimated:NO completion:NO];
}
Need to write the code as follows:
-(void)applicationWillResignActive:(UIApplication *)application
{
imageView = [[UIImageView alloc]initWithFrame:[self.window frame]];
[imageView setImage:[UIImage imageNamed:#"Portrait(768x1024).png"]];
[self.window addSubview:imageView];
}
Here to remove the imageview:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(imageView != nil) {
[imageView removeFromSuperview];
imageView = nil;
}
}
It is working and properly tested.
I think this will help for Swift 3.0
func applicationWillResignActive(_ application: UIApplication) {
let imageView = UIImageView(frame: self.window!.bounds)
imageView.tag = 101
imageView.backgroundColor = UIColor.white
imageView.contentMode = .center
imageView.image = #image#
UIApplication.shared.keyWindow?.subviews.last?.addSubview(imageView)
}
func applicationWillEnterForeground(_ application: UIApplication) {
ReachabilityManager.shared.stopMonitoring()
if let imageView : UIImageView = UIApplication.shared.keyWindow?.subviews.last?.viewWithTag(101) as? UIImageView {
imageView.removeFromSuperview()
}
}
#interface MyAppDelegate ()
#property (strong, nonatomic) MySplashView *splashView;
#end
#implementation MyAppDelegate
- (void)applicationWillResignActive:(UIApplication *)application {
// hide keyboard and show a splash view
[self.window endEditing:YES];
MySplashView *splashView = [[MySplashView alloc] initWithFrame:self.window.bounds];
[self.window addSubview:splashView];
self.splashView = splashView;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// remove the splash view
if (self.splashView) {
[self.splashView removeFromSuperview];
self.splashView = nil;
}
}
#end
This fixed it for me, sorry this is for Xamarin.Forms but you should get the idea. You need to call UIView.SnapshotView(true) in xamarin or UIView snapshotViewAfterScreenUpdates on iOS. Works in DidEnterBackground on iOS7, and iOS8:
public override void DidEnterBackground(UIApplication uiApplication)
{
App.Current.MainPage = new DefaultPage();
**UIApplication.SharedApplication.KeyWindow.SnapshotView(true);**
base.DidEnterBackground(uiApplication);
}

PhoneGap pause event, blur current screen to prevent sensitive data from being shown in snapshot

I am developing an iphone app with phonegap and jquery mobile. When the app is closed and enters the background mode, I am trying to blur the screen so that when the app is resumed, sensitive data on the screen will be blurred out.
I am trying to do this in the on pause event, but it looks like IOS is taking a screenshot of the app before the pause event, thus my blur code does not get captured in the screen shot that IOS shows when resuming the app.
Does anyone have any ideas on how to get this to work?
The pause event is triggered by UIApplicationDidEnterBackgroundNotification, which means that apps already in the background the screen shot has been taken. Is there event before this that I can hook into?
This will be even more important in ios7 when the screen shot is shown when you double click the home button. In ios6 it is only shown for a split second while the app resumes and is loaded.
Thanks!
Code that I have tried in pause and resume phonegap listeners.
// listen for events
document.addEventListener("resume", onResume, false);
document.addEventListener("pause", onPause, false);
// show passcode if enabled, maybe even re-fresh app to start new session and clean up memory issues?
function onResume() {
// unblur page
var filterVal = 'blur(0px)';
$('.ui-page').delay(1000).css('webkitFilter', filterVal);
}
function onPause() {
var filterVal = 'blur(10px)';
$('.ui-page').css('webkitFilter', filterVal);
}
The phonegap plugin cordova-plugin-privacyscreen does the trick - it replaces the view with the splash image prior to backgrounding and clears it afterwards.
https://www.npmjs.com/package/cordova-plugin-privacyscreen
I am facing the same problem here. If your app is enabled multitasking. You can change the native code in appdelegate by adding the current code
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"Application Did Enter Background");
self.viewController.webView.hidden = YES;
NSString *splashImage;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
splashImage = #"Default-Portrait~ipad.png";
}
else {
splashImage = #"Default~iphone.png";
}
UIImageView *splash = [[UIImageView alloc]initWithFrame:[self.window frame]];
[splash setImage:[UIImage imageNamed:splashImage]];
[self.window addSubview:splash];
}
- (void) applicationDidBecomeActive:(UIApplication *)application {
NSLog(#"Application Did Become Active");
if([[self.window subviews] count]>1) {
[NSThread sleepForTimeInterval:0.3];
[[[self.window subviews] lastObject] removeFromSuperview];
}
self.viewController.webView.hidden = NO;
}
- (void)applicationWillResignActive:(UIApplication *)application {
NSLog(#"Application Did Resign Active");
self.viewController.webView.hidden = YES;
NSString *splashImage;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
splashImage = #"Default-Portrait~ipad.png";
}
else {
splashImage = #"Default~iphone.png";
}
UIImageView *splash = [[UIImageView alloc]initWithFrame:[self.window frame]];
[splash setImage:[UIImage imageNamed:splashImage]];
[self.window addSubview:splash];
}
However, make sure your app is support Multitasking. Otherwise this won't work due to the applicationDidEnterBackground is NOT called when the multitasking feature is turned off. And the function(applicationWillTerminate) which should be called and it is NOT called neither.

iOS Security issue: Handle Automatic screenshot of sensitive data when Application going to Background in iOS? Side channel data leakage [duplicate]

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.
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.
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.
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.
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()
}
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.
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
}
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;
}
}
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];
}];
}
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)
}
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.

Resources