iDevice app orientation before and after interstitial ads - ios

Hi I have an app (SpriteKit) that I have set it to only portrait under Target > General > Deployment Info. Also in my info.plist, I have supported interface orientations set to Portrait (bottom home button) and supported interface orientations (iPad) set to Portrait (bottom home button) and Portrait (top home button). This works for most part, however when an interstitial ad is shown, and the device is rotated to landscape mode, the ad rotates too. When the ad is closed, the app stays in landscape mode, and it is not displayed right (i.e. zoomed in so that the width of the app fits the width of the screen and top and bottom is cut off).
I played with the settings a little and found that setting this code makes it work fine, for now at least. I was just wondering if this is the right way to do it? Will there be an issue during the official app review? What are your suggestions? Any comments?
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .Portrait // used to be return .AllButUpsideDown, changed this and everything works for now
} else {
return .Portrait // used to be return .All
}
}

Related

How to turn on/off Portrait Orientation Lock iPhone in Swift

I've used my code to set the screen's brightness.
UIScreen.main.brightness = CGFloat(0.5)
Can I use the code to enable and disable the screen orientation lock of my iPhone?
Thanks for all the help!
• Set the shouldAutorotate to False
override open var shouldAutorotate: Bool {
return false
}
• Specify the orientation.
override open var supportedInterfaceOrientations:UIInterfaceOrientationMask {
return .portrait
}
P.S : You can do this for in a screen in your app, not on the system (iPhone).
You can use this to update device orientation:
UIDevice.current.setValue(UIDeviceOrientation.portrait.rawValue, forKey: "orientation")
Or
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
3rd party applications can't manipulate all system settings or other app settings as it is likely going to cause security breaches. It's called sandboxing. Every app has it's own "Sandbox" or to put it simply, a prison where it cannot access/manipulate system settings or other app settings, which make the Apple devices really secure.
Although you can manipulate the orientation of you application using
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}

youtube iFrame in iOS application causes half screen to go black after full screen

I have a WKWebView in my UIViewController and I'm embedding a youtube video (using an iFrame) into the html along with text. When I launch the video it performs as intended, it opens in full screen, I can rotate either landscape orientations, plays fine etc. The problem lies when I close the video. My application is locked to portrait and when returning from the video the application is half black screen, half my application and the view that is still half my application looks to be in landscape (too larger for the width).
My application is locked portrait within the Info.plist for the whole application. I am fine with the video rotating it just causes this interesting outcome.
1. Launch WKWebView with youtube iframe
2. Click to launch video (video plays full screen)
3. Rotate device to either landscape rotations.
4. Close the player
This is where you notice that half the application is black and the other half looks to be portrait orientation in landscape layout.
When I inspect the views before and after it mimics as if the app has rotated to landscape mode but the device is in portrait. (View starts at 414x862. After viewing and rotating with the video and returning to the view it shows as 862x414)
I'm not really sure what's going on here. Thoughts?
Thanks in advance
I was able to find a workaround/hack/solution to this. I kept my application locked to portrait but overrode the AppDelegate method for allowed orientations.
class AppDelegate: UIResponder, UIApplicationDelegate {
...
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return OrientationManager.allowedOrientations
}
...
}
I created an OrientationManager which was just a helper class to allow me to force rotations and alter the allowed orientations.
class OrientationManager {
/// The currently allowed orientations of the application (default: .portrait)
static var allowedOrientations: UIInterfaceOrientationMask = .portrait
/**
* Method to force the current orientation of the device.
*
* - Parameter orientation: The orientation to change to.
*
* - Warning: This method uses setValue(_, forKey:) which accesses values that may change in the future
*/
static func forceOrientation(_ orientation: UIInterfaceOrientation) {
let orientationRawValue = orientation.rawValue
UIDevice.current.setValue(orientationRawValue, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
}
}
The last thing I needed to do was figure out when the video was going in and out of full screen. I found some notifications that seemed to reliably fire when the video goes in and out of full screen. When this happens I enable the ability for the view to rotate, which allows it to go to Landscape behind the full screen video. Once the video is closed my view is now (unfortunately) showing in landscape which I can then force the orientation and re-lock it to portrait.
In the UIViewController with the webview:
class WebViewWithVideoViewController: UIViewController {
...
// MARK: Properties
var videoDidFullScreenNotification: NSObjectProtocol?
var videoDidMinimizeNotification: NSObjectProtocol?
...
// MARK: Lifecycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.beginObserving()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.endObserving()
}
// MARK: Observers
func beginObserving() {
// This is a solution to the video causing a half black screen when the device is rotated to landscape.
// The outline of the solution is that when the video is put into full screen mode, we update the
// available orientations to include both landscape directions. Upon the video being closed,
// we force the device orientation back to portrait and then lock it back to portrait only.
// This seems to work because the UIViewController is actually in landscape once complete
// and then it animates back to the portrait orientation and seems to keep the proper ratios
// and sizes.
if self.videoDidFullScreenNotification == nil {
self.videoDidFullScreenNotification = NotificationCenter.default.addObserver(
forName: UIWindow.didBecomeVisibleNotification,
object: self.view.window,
queue: nil
) { notification in
OrientationManager.allowedOrientations = .allButUpsideDown
}
}
if self.videoDidMinimizeNotification == nil {
self.videoDidMinimizeNotification = NotificationCenter.default.addObserver(
forName: UIWindow.didBecomeHiddenNotification,
object: self.view.window,
queue: nil
) { notification in
OrientationManager.forceOrientation(.portrait)
OrientationManager.allowedOrientations = .portrait
}
}
}
func endObserving() {
if let videoDidFullScreenNotification = self.videoDidFullScreenNotification {
NotificationCenter.default.removeObserver(videoDidFullScreenNotification)
}
if let videoDidMinimizeNotification = self.videoDidMinimizeNotification {
NotificationCenter.default.removeObserver(videoDidMinimizeNotification)
}
}
...
}
This seemed to have solved the screen showing half black after going in and out of full screen with embedded videos. Unfortunately there is a slight animation when you return from the full screen video, but it's a small sacrifice for a very weird bug.
Hope this helps anyone else with this (or similar issues) and happy coding!

Locking to Portrait on app launching rotates from Landscape to Portrait (iOS)

I want to lock the orientation of the first screen of the app to portrait. In some screens, I need landscape orientation. I am using the react-native-orientation plugin. But when I launch the application, I see landscape orientation for a while and then quickly rotating to portrait orientation. The next screens are ok.
Here is my code:
componentDidMount() {
Orientation.lockToPortrait();
}
Is it possible to solve this performance issue?
Add below code in your page where orientation lock is delayed:
componentWillMount(){
Orientation.lockToPortrait();
Orientation.addOrientationListener(this._orientationDidChange);
}
_orientationDidChange(orientation) {
Orientation.lockToPortrait();
}
componentWillUnmount() {
// remove listener
Orientation.removeOrientationListener(this._orientationDidChange);
}
react-native-orientation no longer seems maintained.
I encourage you to use react-native-orientation-locker which also provides Orientation.lockToPortrait()
It was my error.
I used in one class redundant code:
const setLandscapeRightOrientation = Platform.select({
ios: Orientation.lockToLandscapeRight(),
android: Orientation.lockToLandscapeLeft(),
});

Orientation does not rotate in iOS 10 but does rotate in iOS 11

I don't have a physical device with iOS 10 to test this on but in any device running iOS 10 in the simulator, the app doesn't rotate, it stays in portrait. However, in iOS 11, it rotates fine. All of the orientation boxes are checked in the Info.plist and whether I use or omit (which is the only bit of code in the entire app that deals with orientations):
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.allButUpsideDown
}
in any view controller (root or otherwise), it has no affect in iOS 10. The app is entirely constraint based and there are navigation controllers, which I've read can cause issues. But everything that has been suggested in those answers didn't work for me. Something is preventing the app from rotating in iOS 10 and I cannot figure it out.
This method also returns nothing in iOS 10 (but works in iOS 11):
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if size.width > size.height {
print("orientation: \(UIDevice.current.orientation)")
} else {
print("orientation: \(UIDevice.current.orientation)")
}
}
I've disabled everything in the app and still nothing in iOS 10.
This is issue which is seen only in iPhone 6 plus simulator. It works fine when we run in device or other simulators iPhone 6, iPhone 7, SE. And also this issue is not seen in iPhone 6 plus device .

In Swift, how to get the device orientation correctly right after it's launched?

I use following code to see if the device is in landscape mode or not:
UIDevice.currentDevice().orientation.isLandscape.boolValue
It works BUT if I put my device in landscape mode before the app is launched, and after viewDidLoad, I call this line of code, it always returns false.
If I use this instead:
interfaceOrientation.isLandscape
it returns true, which is correct, but the compiler is showing a warning that interfaceOrientation was deprecated in iOS 8.0.
What is the correct way to get the device orientation right after the app is launched?
DeviceOrientation vs. ScreenSize vs StatusBar.isLandscape?
iOS 11, Swift 4 and Xcode 9.X
Regardless of using AutoLayout or not, there are several ways to get the right device orientation, and they could be used to detect rotation changes while using the app, as well as getting the right orientation at app launch or after resuming from background.
This solutions work fine in iOS 11 and Xcode 9.X
1. UIScreen.main.bounds.size:
If you only want to know if the app is in landscape or portrait mode, the best point to start is in viewDidLoad in the rootViewController at launch time and in viewWillTransition(toSize:) in the rootViewController if you want to detect rotation changes while the app is in background, and should resume the UI in the right orientation.
let size = UIScreen.main.bounds.size
if size.width < size.height {
print("Portrait: \(size.width) X \(size.height)")
} else {
print("Landscape: \(size.width) X \(size.height)")
}
This also happens early during the app/viewController life cycles.
2. NotificationCenter
If you need to get the actual device orientation (including faceDown, faceUp, etc). you want to add an observer as follows (even if you do it in the application:didFinishLaunchingWithOptions method in the AppDelegate, the first notifications will likely be triggered after the viewDidLoad is executed
device = UIDevice.current
device?.beginGeneratingDeviceOrientationNotifications()
notificationCenter = NotificationCenter.default
notificationCenter?.addObserver(self, selector: #selector(deviceOrientationChanged),
name: Notification.Name("UIDeviceOrientationDidChangeNotification"),
object: nil)
And add the selector as follows. I split it in 2 parts to be able to run inspectDeviceOrientation() in viewWillTransition
#objc func deviceOrientationChanged() {
print("Orientation changed")
inspectDeviceOrientation()
}
func inspectDeviceOrientation() {
let orientation = UIDevice.current.orientation
switch UIDevice.current.orientation {
case .portrait:
print("portrait")
case .landscapeLeft:
print("landscapeLeft")
case .landscapeRight:
print("landscapeRight")
case .portraitUpsideDown:
print("portraitUpsideDown")
case .faceUp:
print("faceUp")
case .faceDown:
print("faceDown")
default: // .unknown
print("unknown")
}
if orientation.isPortrait { print("isPortrait") }
if orientation.isLandscape { print("isLandscape") }
if orientation.isFlat { print("isFlat") }
}
Note that the UIDeviceOrientationDidChangeNotification may be posted several times during launch, and in some cases it may be .unknown. What I have seen is that the first correct orientation notification is received after the viewDidLoad and viewWillAppear methods, and right before viewDidAppear, or even applicationDidBecomeActive
The orientation object will give you all 7 possible scenarios(from the enum UIDeviceOrientation definition):
public enum UIDeviceOrientation : Int {
case unknown
case portrait // Device oriented vertically, home button on the bottom
case portraitUpsideDown // Device oriented vertically, home button on the top
case landscapeLeft // Device oriented horizontally, home button on the right
case landscapeRight // Device oriented horizontally, home button on the left
case faceUp // Device oriented flat, face up
case faceDown // Device oriented flat, face down
}
Interestingly, the isPortrait read-only Bool variable is defined in an extension to UIDeviceOrientation as follows:
extension UIDeviceOrientation {
public var isLandscape: Bool { get }
public var isPortrait: Bool { get }
public var isFlat: Bool { get }
public var isValidInterfaceOrientation: Bool { get }
}
3. StatusBarOrientation
UIApplication.shared.statusBarOrientation.isLandscape
This also works fine to determine if orientation is portrait or landscape orientation and gives the same results as point 1. You can evaluate it in viewDidLoad (for App launch) and in viewWillTransition(toSize:) if coming from Background. But it won't give you the details of top/bottom, left/right, up/down you get with the notifications (Point 2)
This worked for me:
if UIScreen.main.bounds.width > UIScreen.main.bounds.height{
print("Portraitmode!")
}
It works on all devices based on the display dimensions:
https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html
I have tested many times about orientation, so I have summed up some experience.
In all iPhone devices, except iPhone6(s) plus, the only interface orientation is .portrait. If App is launched in landscape mode, there must be a change of orientation. One will receive the UIDeviceOrientationDidChangeNotification. It's an appropriate time to get the orientation.
Regarding the launching when in landscape with iPhone6, the orientation after the launch will change once:
The launching when in landscape with iPhone6 plus, after launch the orientation never changed:
Two different screenshot with the same app,
So before the app does change orientation, the orientation is still like in the home page.
In viewDidLoad, the orientation has not changed yet, the log will be the wrong direction.
The isValidInterfaceOrientation should be detected before checking the orientation isLandscape. Don't process the flat message with isValidInterfaceOrientation == false (when it has any value of isLandscape).
I had a hazzel with this until I read the topic more carefully. With consideration of the isValidInterfaceOrientation it works fine.
#objc func rotated() {
if (UIDevice.current.orientation.isValidInterfaceOrientation) {
if (UIDevice.current.orientation.isLandscape) {
if(!bLandscape) {
bLandscape = true
setupTabBar() // Repaint the app
}
} else { // Portait
if(bLandscape) {
bLandscape = false
setupTabBar() // Repaint the app
}
}
}
}
I had a problem to detect which orientation was before isFlat so I put this in my view controller
let orientation = UIDevice.current.orientation
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if orientation.isPortrait {
return .portrait
} else if orientation.isFlat{
if UIScreen.main.bounds.width < UIScreen.main.bounds.height{
return .portrait
} else {
return .landscape
}
} else {
return .landscape
}
}

Resources