34

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];
}
Ashok
  • 6,034
  • 1
  • 34
  • 50
Tancrede Chazallet
  • 6,547
  • 3
  • 35
  • 59
  • 1
    AFAIK, you need to do your action inside `applicationWillResignActive` and undo the same action `applicationDidBecomeActive` of `UIApplicationDelegate` methods. – Ashok Nov 05 '13 at 16:11
  • 2
    Problem is, if i do display my splashscreen in `applicationWillResignActive` then it's displayed whenever the user just look at his control panel or double tap on home button... – Tancrede Chazallet Nov 05 '13 at 16:14
  • `Paypal` iOS app does something similar, they blur their last active view when app enters into background (to secure user info). I would recommend you to study that or some other apps. EDIT: I just noticed that paypal doesn't blur when control panel open up so I believe there is some way so what you are trying to achieve should be feasible. Will keep a watch on this thread. – Ashok Nov 05 '13 at 16:18
  • It's kinda what I want to do (since my app also deals with bank informations), but i'm not sure paypal let me see its code :/ – Tancrede Chazallet Nov 05 '13 at 16:23
  • I guess that @Ashok solution is probably the best. When a user double tap, receive a call, call the control panel, is resigning the app., most probably it will not care about what your app is showing since it does in a "smooth&cool" way. – Andrea Nov 05 '13 at 18:41
  • 2
    @Andrea - But what he is looking for should be feasible since many other financial (__security-seeking__) apps like `Paypal`, `BofA` does so. (Note - on iPad - control center, notification center etc partially cover the app). I think the solution is not hard but it's just not clicking to me. Let's voted up this question to bring right mind's attention here :). Also @AncAinu - u should give a try of your solution on actual device (not just simulator), if not already done. – Ashok Nov 05 '13 at 19:05
  • @Ashok's method is what I am looking for. The secure app method whereby switching apps in any way will hide the main view and show a splash screen instead. – jowie Jul 15 '15 at 08:42

8 Answers8

41

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.

Ashok
  • 6,034
  • 1
  • 34
  • 50
9

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()
    }

}
SteffenK
  • 425
  • 5
  • 11
4

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.

SharkBait
  • 41
  • 1
3

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];
}
Ertan D.
  • 812
  • 1
  • 6
  • 21
  • If alertview is being displayed, it will not be hidden, how can we hide the alertview on background mode – Arshad Shaik Aug 08 '19 at 09:39
  • Careful using this; if you have a modal presented on your current window and the presentViewController method doesn't complete, when you go back to the foreground your modal may be dismissed instead. – Huy-Anh Hoang Sep 05 '19 at 22:53
2

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.

Ertan D.
  • 812
  • 1
  • 6
  • 21
Deepak Kumar
  • 199
  • 1
  • 6
1

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()
        }
    }
0
@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
neoneye
  • 44,507
  • 23
  • 155
  • 143
  • what do you do in case that some system alert is shown on the screen. in this case MySplashView is also shown on the screen. can I avoid this? – Klemen Jun 14 '17 at 17:56
0

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);
}
shane
  • 415
  • 4
  • 18