I need a way to hide sensitive information in a react native app so if you minimize the app and leave your phone unlocked the snapshot of the app in the multitasking view would be blurred and the navigation stack would be switched back to login screen when the app becomes active again.
Even just showing the Login screen just before the app becomes inactive->background would be sufficient but it seems that the AppState's change event is called after the state is already changed from active to inactive and at this point the snapshot is already made and the screen changing occurs after the app is restored. This way the screen with the sensitive data is visible in the multitasking.
I know how to make this with ease in native iOS environment but it seems it's not quite that trivial in React Native.
You can't avoid here from the native code.
in iOS:
In your AppDelegate.m file these 2:
1.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// 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.
UIViewController *blankViewController = [UIViewController new];
blankViewController.view.backgroundColor = [UIColor blackColor];
// Pass NO for the animated parameter. Any animation will not complete
// before the snapshot is taken.
[self.window.rootViewController presentViewController:blankViewController animated:NO completion:NULL];
}
And this
2.
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// This should be omitted if your application presented a lock screen
// in -applicationDidEnterBackground:
[self.window.rootViewController dismissViewControllerAnimated:NO completion:NO];
}
Source:
https://developer.apple.com/library/content/qa/qa1838/_index.html
Found this also:
https://github.com/kayla-tech/react-native-privacy-snapshot
Related
This document: Preventing Sensitive Information From Appearing In The Task Switcher describes a way to present a view controller in applicationDidEnterBackground so as to hide critical information in the task switcher:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// 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.
UIViewController *blankViewController = [UIViewController new];
blankViewController.view.backgroundColor = [UIColor blackColor];
// Pass NO for the animated parameter. Any animation will not complete
// before the snapshot is taken.
[self.window.rootViewController presentViewController:blankViewController animated:NO completion:NULL];
}
Yet, in iOS 8, this exact code does not work, and the very simple, plain, black view controller is not shown until after the app becomes active again. The task switcher shows the sensitive information and nothing is hidden. There are no animations in this code, so I cannot understand - why is this happening?
In iOS 8 the app is not being given enough time to display the view controller before the screenshot is taken.
The fix that works for me is to just introduce a small run loop run at the end of applicationDidEnterBackground.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIViewController *blankViewController = UIViewController.new;
blankViewController.view.backgroundColor = UIColor.blackColor;
[self.window.rootViewController presentViewController:blankViewController animated:NO completion:NULL];
[NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
}
I have a simple spritekit app, SKView on intialization shows a splash screen(scene), the user clicks on a button they are taken to the main game scene.
Everything works fine, but wanted to add iads to it, so I instantiated an adview in the main scene, and assign its delegate to the main scene.
The add appears fine, and I click on it, it properly shows the ad, but then I dismiss the ad, and when I do that the app goes back and looks like it reinitializes the entire SKVIEW which displays the Splash Scene, not the main scene which was paused in the delegate calls.
So, when the IAD is dismissed, what exactly are the callbacks back into the parent app, because its clear its not just the delegate methods, its going back and reinitializing the view etc. Basically where in my view do I need to trap its returning from a canceled ad and handle this case properly.
Sounds like you're running the scene in viewWillLayoutSubviews without checking whether a scene is already running. Make sure the launch code looks like this, or it will relaunch the starting scene whenever the viewWillLayoutSubviews method runs (it can and will be called multiple times, for example when rotating the device and apparently also when dismissing an ad):
-(void)viewWillLayoutSubviews
{
SKView* skView = (SKView*)self.view;
// only create/launch first scene when SKView has no running scene
if (skView.scene == nil)
{
// create and present scene here ...
}
[super viewWillLayoutSubviews];
}
I am developing a banking application and the client requirement is not to show/save the screen snapshot when app goes in the background (i.e., when home button is clicked).
I have added an overlay view in background method and removed that view when app again comes in the foreground. Its working perfectly fine when I click home button, wait for 1 or 2 secs and then again click home button twice.
My problem is: If I click home button once, wait for some milliseconds (just before the app icons visible)and then again click home button twice, then the screen snapshot is visible (in multitasker view).
When I analysed the issue, I came to know that my background delegate method doesn't get called in this scenario and hence, no overlay view is added in this case.
Steps to Reproduce:
Add An overlay view (with while color, lets say) in appDidEnterBackground Method of your application.
Add code for removing that overlay view in willEnterForeground Method.
Now, run your application.
Press Home button once.
Just after pressing home button once (and just before your application icon is visible), click home button twice so that you are able to see the Multitasker view.
Instead of your overlay view, you would be seeing the application screenshot there.
Expected Results:
The While overlay view should have been added, and you should have seen that instead of app snapshot.
Actual Results:
You are able to see the application screen shot in Multi tasker view
Version:
iOS 7 and above
I've created an app that does exactly what you want. I throw up the shield image view in applicationWillResignActive:
- (void)applicationWillResignActive:(UIApplication *)application {
// ...
self.shieldImageView = [[UIImageView alloc] initWithFrame:self.window.frame];
self.shieldImageView.image = [UIImage imageNamed:#"shieldimage"];
self.shieldImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.window addSubview:self.shieldImageView];
// ...
}
and get rid of it in applicationDidBecomeActive:
- (void)applicationDidBecomeActive:(UIApplication *)application {
// ...
[self.shieldImageView removeFromSuperview];
self.shieldImageView = nil;
// ...
}
I am trying to prevent the Apple implemmntation of taking a screenshot of the current screen contents when an app suspends into the background. I have found a piece of code that sort of works but it comes with a catch. What it does is that it clears the keywindow on the screen so when the snapshot is taken, it is of a blank screen. This is the code snippet for the functionality:
- (void)applicationWillResignActive:(UIApplication *)application
{
[ UIApplication sharedApplication ].keyWindow.hidden = YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[ UIApplication sharedApplication ].keyWindow.hidden = YES;
}
The trouble with the above code is that when the app returns to the foreground, the view is gone as it has become hidden and i cannot unhide it with a simple
[ UIApplication sharedApplication ].keyWindow.hidden = NO;
in the applicationWillEnterForeground method of the app delegate. Does anyone know of a way to regain back the hidden view once i have hidden it in the background methods? Right now it is a black screen as the view has been hidden. What exactly happens when you hide a keywindow before going to background and then coming back. is that keywindow you hid before no longer the keywindow? Can anyone point me in the correct direction?
Thanks
Just made a demo project and was able to reproduce your issue. Indeed, the keyWindow property of the application is nil when applicationWillEnterForeground: is called.
Many times, your application's delegate will have a reference to its window - this is usually the Xcode default template for many applications. I was able to resolve the issue by calling
self.window.hidden = NO;
Instead of [UIApplication sharedApplication.keyWindow.hidden = NO;. Assuming that, like most of the templates, your application delegate has a window reference.
Another alternative that worked for me is to call [self.window makeKeyAndVisible];.
All this was done on the iOS 6 simulator.
Hope this helps!
I have a "Splash screen" ViewController extending UIViewController, set as the the initial app VC in my storyboard. This controller features a login form.
When the app starts, and before anything is displayed on the screen, I want this splash VC to check the user defaults to see if the user is already logged in. If so, I want the splash VC to redirect to the app's home VC, all before anything is displayed on the screen.
If the user is not logged in, I want the Splash VC to finish loading, displaying the login forms.
How would I go about implementing this? Would I place all of these checks in the init methods? I was having a hard time getting any code in the splash VC init methods to run at all, for some reason these methods don't get called.
Code in the viewDidLoad method runs fine, but running the code there would defeat the purpose of trying to allow the already-logged-in-user to start the app right into the home screen.
Suggestions? Thanks in advance.
My pick of the place to put this logic is in application didFinishLaunchingWithOptions: of application delegate. Here is how it would look :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
//////////////////////////////////////////////
// 1. do loading data etc.
// 2. check whether user is signed in or not
//////////////////////////////////////////////
if(already signed in)
{
dispatch_sync(dispatch_get_main_queue(), ^{
[self.window.rootViewController performSegueWithIdentifier:#"segue identifier to home VC" sender:self.window.rootViewController];
});
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
[self.window.rootViewController performSegueWithIdentifier:#"segue identifier to login VC" sender:self.window.rootViewController];
});
}
});
return YES;
}
And this is my quick storyboarding to assist the code. Hopefully you get the idea.