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!
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've used this code to force an orientation change back to portrait when the user is finished watching the video (it allows viewing in landscape mode), before popping the video view controller off the navigation controller:
//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];
//present/dismiss viewcontroller in order to activate rotating.
UIViewController *mVC = [[[UIViewController alloc] init] autorelease];
[self presentModalViewController:mVC animated:NO];
[self dismissModalViewControllerAnimated:NO];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
This worked perfectly until iOS 5.1.1. I've even tried to use the new present/dismiss methods after reading in another post that those should be used now:
[self presentViewController:mVC animated:NO completion:NULL];
[self dismissViewControllerAnimated:NO completion:NULL];
The problem is it doesn't work at all. After I rotated the video viewer to landscape and then pop it, my settings view (table view controller) comes back, but also in landscape mode.
I've even tried the tip from Here
"The setStatusBarOrientation:animated: method is not deprecated outright. However it now works only if the supportedInterfaceOrientations method of the topmost full screen view controller returns 0. This puts the responsibility of ensuring that the status bar orientation is consistent into the hands of the caller."
So I've experimented with setting a flag to force supportedInterfaceOrientations to return 0 (before calling the first code block above) but it doesn't work either.
Does anybody have a solution for this?
Thanks for your time and effort.
setStatusBarOrientation method has changed behaviour a bit. According to Apple documentation:
The setStatusBarOrientation:animated: method is not deprecated
outright. It now works only if the supportedInterfaceOrientations
method of the top-most full-screen view controller returns 0
Your root view controller should answer false to the method shouldAutorotate in order that your app responds to setStatusBarOrientation:animated
From Apple Documentation: "if your application has rotatable window content, however, you should not arbitrarily set status-bar orientation using this method"
To understand that, put a breakpoint in the shouldAutorotate method and you will see that it is called juste after setting the status bar orientation.
Here is how I fixed.
https://stackoverflow.com/a/14530123/1901733
The current question is linked with the question from the url above.
The statusBarOrientation is a real problem in ios6.
i have a button in my app a button that submit score to gamecenter and works.
this is the code:
-(void)subScore{
GKScore *scoreRepoter = [[[GKScore alloc] initWithCategory:#"123456"] autorelease];
scoreRepoter.value=100;
[scoreRepoter reportScoreWithCompletionHandler:^(NSError *error) {
if (error!=nil) {
NSLog(#"errr submitting");
}else
NSLog(#"ok!");
}];
now i'd like to submit score before app is closed with home button.
i thought to customize an action of home button (if it is possible)
or perhaps i make the same line of code in viewDidUload...or something like that...
will i be sure that that action will be performed before unloading the app?
i should make that code in dealloc method?
thanks
You can't customize behaviour of Home button directly, but iOS provides some methods in your application's delegate, by which you can control lifecycle of the application.
Method called right before the application goes to background is applicationWillResignActive: in your application's delegate (usually this method is located in AppDelegate.m file).
I think you can get needed effect by calling your method like that:
- (void)applicationWillResignActive:(UIApplication *)application {
[mygame subScore];
}
Also please note that iOS has time limit of execution for this method: you must do all saving-the-game work in less that five seconds or your application will be killed.
When the home button gets pressed I want to hide the keyboard and restore my view to a sane state, so that when the app is started/foregrounded again, there is no textfield selected and the keyboard is hidden.
My app delegate has this implementation of the method:
- (void)applicationDidEnterBackground:(UIApplication *)application {
[tabBarController.view endEditing:YES];
}
The keyboard does indeed get removed, but what I don't get is this: Apple's docs say that a snapshot of the app is taken after the method returns. However this poses a problem with the keyboard slide-down animation. Sometimes when the app is started again for a short moment it shows the keyboard half-way down. I assume the screenshot is taken before the animation was finished.
What would I do to solve this, introduce a short timer in the applicationDidEnterBackground: method? I wonder if there is a "cleaner" solution.
I've not tried this but what about turning animations off just before you resign the keyboard:
- (void)applicationDidEnterBackground:(UIApplication *)application {
[UIView setAnimationsEnabled:NO];
[tabBarController.view endEditing:YES];
}
If this works you need to turn them back on in applicationWillEnterForeground
I'm having problems getting my iPad app to detect its interfaceOrientation in the first UIViewController I initialize (in code). In fact, if I trace for application.statusBarOrientation, that too returns 1 (UIInterfaceOrientationPortrait) even if I launched in landscape.
If I trace self.interfaceOrientation in my first UIViewController, it remains 1 until it gets to viewWillDisappear... Which is unfortunately too late!
Here's some code (even though there's not much to see):
In my appDelegate I have this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// show loading screen first
[window addSubview:loadingScreenViewController.view];
[window makeKeyAndVisible];
NSLog(#"applicationDidBecomeActive:statusBarOrientation = %d", application.statusBarOrientation);
return YES;
}
which traces 1 (portrait), even though I clearly see the status bar is landscape... and in the first view controller I have this:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"self.interfaceOrientation = %d", self.interfaceOrientation);
}
which also traces 1, even in landscape mode.
Any ideas? Stumped here!
Thanks :)
:-Joe
Here is the answer... Somewhat: (from Apple Dev Forums): ....
"The app is always loaded as if the device is portrait, and then if the device is really landscape the app is told that the device has rotated. This is done so that nibs and code only need to create their UI in one orientation. Otherwise it might be necessary to have two UI layouts for each nib." .... it's not the answer I'd have liked, but that's how iOS works unfortunately!
What does the app delegate report in applicationDidFinishLaunching? Because if it reports the correct value, you can always access the delegate to check the orientation.