iOS - Previous screen flashing when coming from background - ios

This is my situation: I push a ViewController that is in landscape mode, then go to the home screen. When I go back in the app, the previous views in the back stack flash for just a moment before going to my ViewController. This doesn't happen for portrait ViewControllers.
Has anyone seen this before or know of a workaround? Thanks!
For the record, I am simply pushing the ViewController via:
self.navigationController!.pushViewController(viewController, animated: true);
and then forcing the view into landscape mode, not sure if that's relevant.

What solved this problem for me was calling
window?.makeKeyAndVisible();
in the AppDelegate file

Related

Forcing orientation on a full screen modal doesn't work on parent controller

iOS 16 introduced a new API for forcing orientation changes, which implies using the requestGeometryUpdate(_:errorHandler:).
It seems that it's not working as expected when using a full screen modal.
For example, let's say we have an app that locks the orientation in portrait mode except for a modally presented controller, a parent controller A and a modal controller B :
A is displayed
We put the device in landscape mode - A stays in portrait mode
B is opened modally fullscreen from A
B is displayed in landscape
B has a button to go back to portrait mode using the requestGeometryUpdate(_:errorHandler:)
B is dismissed through a button
A ends up in landscape
In the app delegate, we used supportedInterfaceOrientationsFor to force the app in portait mode except for the controller B.
We tried to call setNeedsUpdateOfSupportedInterfaceOrientations every time we call requestGeometryUpdate(_:errorHandler:).
We also tried to call it on the viewWillAppear from the controller A.
We finally tried to call requestGeometryUpdate(_:errorHandler:) from the controller A's viewWillAppear, without any luck as well.
Is this a bug in iOS 16 or are we missing something ?
It seems to be working as expected when displaying the modal over the current context, but it's not what we want in this case.
I can provide an example project if needed.

How to display lock sreen in task switcher and resume correctly

for the app I'm developing, I implemented a lock screen that allows the user to unlock the App by manual-pin or touch/Face-ID.
Everything is working OK during the normal use.
However, I need to show the lock screen when the app is resumed from background and even in the task switcher to avoid "peeking" at the content without having unlocked properly.
As recommended by Apple in this (old) article, I present the lock view controller in applicationDidEnterBackground:
func applicationDidEnterBackground(_ application: UIApplication) {
let lockVC = LoginViewController()
lockVC.loginType = LoginViewController.LoginType.resumeApp
if let topViewController = UIApplication.topViewController() {
topViewController.present(lockVC, animated: false, completion: nil)
}
}
where topViewControler is a useful extension to determnine the topmost view controller: Get top most UIViewController
.
The lockVC.loginType = ... is just to let the ViewController what type of login I need and customize its view a little bit
The results I get are a bit weird, both on simulator and real devices:
the task switcher preview for my app is completely black
when the app is resumed, the screen remains black as in preview and unresponsive. Only way to exit is to kill the app.
before obtaining the weird results above, I had to access all outlets as optional to avoid termination... that's fine for viewDidLoad stuff (I didn't expect the need for this when entering background, since the view had been loaded before - outlet wired) but the strange thing is that I had the same error for an IBAction in viewDidAppear (IBAction for touch-id button called automatically if touch/face-id is available - just a requirement).
I believe I'm missing something big here... but no other hints found.
No one of the ready-made lock screen solutions come with an example for the background/taskSwicth/resume case).
Note that the black/unresponsive screen seems to be same both if I use the mentioned extension for the topmost view controller to present or if I simply try to present it by
self.window?.rootViewController?.present(lockVC, animated: false)
(which I believe is wrong, but tried anyway)
Any help would be apreciated
I found a temporary workaround:
Display the lock screen when the app becomes active from background, as suggested by Dev_Tandel
Hide information in the task switcher by adding a blur effect on the current screen where the app is sent to background (applicationWillResignActive) and removing it when the app comes active again (applicationDidBecomeActive), as suggested here
As said, it's a temporary workaround that i wanted to share, but I don't like this 100%. It is required to show the lock screen in the task swtcher and Ive seen apps doing it (e.g. "oneSafe").
Still looking for help.
Solved, thanks to this post.
Apparently I was naive in trying to present a view controller with just its object instance.
If I use
let lockVC = topViewController.storyboard?.instantiateViewController(withIdentifier: "IDLoginViewController") as! LoginViewController
everything works, the lock screen is shown also in the task switcher, no need to blur!

Launch Screen only showing once

I have used the LaunchScreen.storyboard file in my swift file to create a launch screen, however I only see the launch screen when I load the app onto my phone. After that, even when I kill the app I don't see the launchscreen again. I want it so that it shows every time the app is booted, so after it's been removed from the background like most other apps that exist. I there a setting that i need to toggle, or am I doing something wrong?
What you want can be achieved from the initial ViewController instead of Launch Screen.
Reason: Launch Screen timing is not fixed and can have a very short appearance if the app has recently been in the memory.
I would recommend you to use the welcome graphic/animation on the initial View Controller and move to the intended View Controller after a set timer by using a segue.
Edit: Additionally, in case of a graphic, you can put that on the Launch screen as well, then on the initial View Controller. That will get you continuity.
Hope this helps.

UIAlertViews, UIActionSheets and keyWindow problems

I created an iOS 7 passcode replica and I have this problem I can't seem to solve. I need the lock screen view to be on top of everything else, so the app is covered in iOS' multitasking view, so I add it directly to the keyWindow. Everything fine so far.
The problem arises if there's an alertView or actionSheet (will only mention alertViews in this post, to keep it simple) open when I have to display the lock screen. It has been answered several times that there are no references to alertViews in iOS 7, which is true, and the window in which they are displayed is _UIModalItemHostingWindow, which has 2 UIViews, indeed with no reference to the alertView.
This _UIModalItemHostingWindow also becomes the new keyWindow, so it's on top of everything else, but it can not be found in [UIApplication sharedApplication].windows meaning if I add the lock screen to my former keyWindow (the default keyWindow, if you will), it will be beneath the alertView and its dimmed background, so the user can't interact with the lock screen before dismissing the alertView. The other option is detailed a bit further below.
The lock screen works like this: on applicationDidEnterBackground it checks if the passcode is enabled; if it is enabled and the passcode duration is 0 (user selected to lock the app immediately), it adds the lock screen now, so it covers the app in the multitasking view. Now, the option I mentioned above is to add the alertView to this _UIModalItemHostingWindow window, but when returning to the app, the lock screen view is displayed with a 1+ second delay (even though I added it before I went to background!) and the app isn't covered by anything in the multitasking view. (Currently it's displayed in the wrong position too, if you go ahead and download it, that is fixed, but I didn't pushed the commit yet).
I tried hiding and removeFromSuperview this _UIModalItemHostingWindow, but when coming back to the app, the alertView animation still runs as if it was just fired. I suspect the delay mentioned above also happens due to how Apple handles alertViews when coming back to foreground.
I also tried creating a new window and to make that the new keyWindow, but same thing happens.
Here's a small discussion about this, covering all the stuff I tried, maybe I missed something in this post.
https://github.com/rolandleth/LTHPasscodeViewController/issues/16
Any ideas? Except creating manual references to every alertView and actionSheet inside my app, because I'm trying to find a fix for the passcode library, not my own apps; I can find dirty workarounds for that, no problem :)
Update: The window is _UIAlertOverlayWindow if an actionSheet is used instead of an alertView, but it behaves the same as far as I can tell.
The simplest solution is to have a lockscreen window instead of a lockscreen view.
Create a new UIWindow, set its frame to UIScreen bounds, put a simple rootViewController there that should handle rotation and display your "lock screen" views and set the windowLevel to UIWindowLevelAlert + 1.
Then set window's hidden to YES. Whenewer you want to show the lockscreen, just set hidden to NO.
I guess that adding a view to keyWindow also doesn't work when a popover/action sheet is displayed and also when a keyboard is displayed (keyboard has its own window on top of the key window).

How to make UIPopoverController visible at startup in portrait orientation?

I'm making an iPad application using a UISplitViewController. I want the masterView visible in a UIPopoverController when the app starts (and only when it starts) in portrait mode. If I use the presentPopoverFromBarButtonItem:permittedArrowDirections:animated: method in the splitViewController:willHideViewController:withBarButtonItem:forPopoverController:
delegate function, I get the following error, when I start the app in portait mode:
Popovers cannot be presented from a view which does not have a window.
Can anybody help me?
The particular error says that you must add the view to a window before showing the popover, not the other way round. Try sending presentPopover… from the application delegate's -application:didFinishLaunchingWithOptions: after adding the view to your app's window.

Resources