I am seeing a strange issue with autorotation on iOS 16 that is not seen in other iOS versions. And worse, the issue is NOT seen if I connect device to XCode and debug. It is ONLY seen when I directly launch the app on device by touching the app icon, and that's the reason I am unable to identify any fix. What I do is I disable autorotation on app startup (by returning only .landscape in supportedInterfaceOrientations
) and then very shortly after say 0.2 seconds, I force autorotation to current interface orientation of device (using self.setNeedsUpdateOfSupportedInterfaceOrientations
). But autorotation fails if app is directly launched by touching the app icon (as opposed to launching from debugger)!
Here is a sample code that fully reproduces the issue. When running the app, make sure iPhone is held in portrait mode. The function viewWillTransition(to size:, with coordinator:)
is not called and all the subviews are not autorotated. Please suggest me a workaround!
import UIKit
class ViewController: UIViewController {
public var windowOrientation: UIInterfaceOrientation {
return view.window?.windowScene?.interfaceOrientation ?? .unknown
}
private var disableAutoRotation = true
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
var orientations:UIInterfaceOrientationMask = .landscapeRight
if !self.disableAutoRotation {
orientations = .all
}
return orientations
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.systemGreen
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
self.autoRotateNotification()
})
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let orientation = windowOrientation
coordinator.animate(alongsideTransition: {_ in
}, completion: { [unowned self] (UIViewControllerTransitionCoordinatorContext) -> Void in
let orient = self.windowOrientation
if orient.isLandscape {
self.view.backgroundColor = UIColor.systemGreen
} else {
self.view.backgroundColor = UIColor.systemOrange
}
})
}
func autoRotateNotification() {
DispatchQueue.main.asyncAfter(deadline: .now(), execute: {
/*
* HELP::: This code does something only when debug directly from XCode,
* not when directly launching the app on device!!!!
*/
self.disableAutoRotation = false
if #available(iOS 16.0, *) {
UIView.performWithoutAnimation {
self.setNeedsUpdateOfSupportedInterfaceOrientations()
}
} else {
// Fallback on earlier versions
UIViewController.attemptRotationToDeviceOrientation()
}
})
}
}
EDIT: Someone mentioned moving the autorotateNotification to viewDidAppear
fixes the issue, but it does not. As already stated, there is no issue if app is launched via XCode debugger. The issue is observed only when app is directly launched by touching the app icon! Here is sample code for every one's reference that also fails.
import UIKit
class ViewController: UIViewController {
public var windowOrientation: UIInterfaceOrientation {
return view.window?.windowScene?.interfaceOrientation ?? .unknown
}
private var disableAutoRotation = true
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
var orientations:UIInterfaceOrientationMask = .landscapeRight
if !self.disableAutoRotation {
orientations = .all
}
return orientations
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeLeft
}
private var autoRotated = false
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !autoRotated {
autoRotated = true
self.autoRotateNotification()
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: {_ in
}, completion: { [unowned self] (UIViewControllerTransitionCoordinatorContext) -> Void in
let orient = self.windowOrientation
if orient.isLandscape {
self.view.backgroundColor = UIColor.systemGreen
} else {
self.view.backgroundColor = UIColor.systemOrange
}
})
}
func autoRotateNotification() {
self.disableAutoRotation = false
if #available(iOS 16.0, *) {
self.setNeedsUpdateOfSupportedInterfaceOrientations()
} else {
// Fallback on earlier versions
UIViewController.attemptRotationToDeviceOrientation()
}
}
}