react-native-orientation-locker icon indicating copy to clipboard operation
react-native-orientation-locker copied to clipboard

fix ios 16 Setting UIDevice.orientation

Open ceddybi opened this issue 3 years ago • 21 comments

BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:)

Source

#241

PS: Works on my end now, please update if you have any suggestions.

ceddybi avatar Sep 30 '22 03:09 ceddybi

@ceddybi In my case, this change does not help, the screen orientation changes if I turn the phone.

Shabanisimo avatar Sep 30 '22 14:09 Shabanisimo

This addresses the iOS 16 issue in our project, thanks for the fix!

jfspencerAngel avatar Oct 01 '22 04:10 jfspencerAngel

@jfspencerAngel @ceddybi Before iOS 16, device orientation change notifies when locktolandscape or portrait but it is not working now(iOS 16) until rotate the device. something to do with setNeedsUpdateOfSupportedInterfaceOrientations ? https://developer.apple.com/documentation/uikit/uiviewcontroller/4047535-setneedsupdateofsupportedinterfa?language=objc

venky145 avatar Oct 02 '22 12:10 venky145

@ceddybi Thank you for your PR I suggest to apply below code, because UIDeviceOrientationDidChangeNotification couldn't detect orientation change when orientation changed via lockTo** method.

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
        [self addListener:@"orientationDidChange"];

I know UIApplicationWillChangeStatusBarOrientationNotification is deprecated from iOS13 but this library already used deprecated API like UIApplication.statusBarOrientation, so I just suggest it. unfortunately I'm not a specialist of iOS dev🥲, If you know any alternative solution, I hope you feel free to use that

YangJonghun avatar Oct 06 '22 18:10 YangJonghun

useEffect(() => { Orientation.addLockListener(onOrientationDidChange); // ios16 can full screen when orientation lanspage // Orientation.addOrientationListener(onOrientationDidChange); // ios16 not full screen , only 1/2 screen

    return (() => {
        Orientation.removeOrientationListener(onOrientationDidChange);
    })
}, [])

nguyenhuynhdeveloper avatar Oct 21 '22 04:10 nguyenhuynhdeveloper

I applied this my app, but even when setting lockToPortrait() the device will still rotate, anyway to prevent this?

CoreyBovalina avatar Nov 17 '22 20:11 CoreyBovalina

can anyone please merge this changes.

VinothEI avatar Jan 12 '23 07:01 VinothEI

can anyone please merge this changes.

I merged this branch in my fork, you can use a temporary solution in your package.json "react-native-orientation-locker": "github:Soberones/react-native-orientation-locker",

Tested iOS 16.2 (simulator and real device)

Soberones avatar Jan 16 '23 10:01 Soberones

I applied this my app, but even when setting lockToPortrait() the device will still rotate, anyway to prevent this?

Try to use only portrait in Xcode Снимок экрана 2023-01-16 в 13 38 34

Soberones avatar Jan 16 '23 10:01 Soberones

Doesn't seem to fix anything if I patch the latest version (1.5.0) with this.

react-native-orientation-locker+1.5.0.patch

wouterds avatar Jan 19 '23 11:01 wouterds

patching 1.5.0 works for me.

if it's not working, check your installation.

PITFALL: this part is not a part of manual linking, all methods need to do this https://github.com/wonday/react-native-orientation-locker#configuration

utkuturunc avatar Jan 23 '23 00:01 utkuturunc

can anyone please merge this changes.

I merged this branch in my fork, you can use a temporary solution in your package.json "react-native-orientation-locker": "github:Soberones/react-native-orientation-locker",

Tested iOS 16.2 (simulator and real device)

not working with ios 15.5

VinothEI avatar Feb 09 '23 17:02 VinothEI

https://github.com/wonday/react-native-orientation-locker#configuration

Doing the fix in the mentioned PR as a patch (i.e. patch-package) + applying the fixes suggested here worked for me

patch for version 1.5.0:

diff --git a/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m b/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
index 6117764..849387a 100644
--- a/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
+++ b/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
@@ -125,13 +125,19 @@ - (void)lockToOrientation:(UIInterfaceOrientation) newOrientation usingMask:(UII
     UIInterfaceOrientation deviceOrientation = _lastDeviceOrientation;
     
     [Orientation setOrientation:mask];
-    UIDevice* currentDevice = [UIDevice currentDevice];
     
-    [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
-    [currentDevice setValue:@(newOrientation) forKey:orientation];
+    if (@available(iOS 16.0, *)) {
+        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
+        UIWindowScene *scene = (UIWindowScene *)array[0];    UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
+        [scene requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) { }];
+    } else {
+        UIDevice* currentDevice = [UIDevice currentDevice];
+        [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
+        [currentDevice setValue:@(newOrientation) forKey:orientation];
+        // restore device orientation
+        [currentDevice setValue:@(deviceOrientation) forKey:orientation];
+    }
     
-    // restore device orientation
-    [currentDevice setValue:@(deviceOrientation) forKey:orientation];
     
     [UIViewController attemptRotationToDeviceOrientation];
     

arthurgeron-work avatar Mar 13 '23 21:03 arthurgeron-work

Any update on merging the above PR

ajeetfancode avatar Mar 23 '23 10:03 ajeetfancode

I tried to apply this fix but nothing changes in my case. But even after this patch i am able to go back to portrait mode from landscape mode but unable to lock orientation to portrait If anybody can help kindly respond I used this patch and this works somehow

diff --git a/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m b/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
index 6117764..c2658c5 100644
--- a/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
+++ b/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
@@ -42,7 +42,8 @@ - (instancetype)init
         _lastDeviceOrientation = (UIInterfaceOrientation) [UIDevice currentDevice].orientation;
         _isLocking = NO;
         
-        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
+        // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
         [self addListener:@"orientationDidChange"];
     }
     return self;
@@ -116,6 +117,7 @@ - (NSString *)getOrientationStr: (UIInterfaceOrientation)orientation {
     }
     return orientationStr;
 }
+// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
 
 - (void)lockToOrientation:(UIInterfaceOrientation) newOrientation usingMask:(UIInterfaceOrientationMask) mask  {
     // set a flag so that no deviceOrientationDidChange events are sent to JS
@@ -125,13 +127,24 @@ - (void)lockToOrientation:(UIInterfaceOrientation) newOrientation usingMask:(UII
     UIInterfaceOrientation deviceOrientation = _lastDeviceOrientation;
     
     [Orientation setOrientation:mask];
-    UIDevice* currentDevice = [UIDevice currentDevice];
-    
-    [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
-    [currentDevice setValue:@(newOrientation) forKey:orientation];
+    // UIDevice* currentDevice = [UIDevice currentDevice];
+    
+    // [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
+    // [currentDevice setValue:@(newOrientation) forKey:orientation];
+    
+    if (@available(iOS 16.0, *)) {
+        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
+        UIWindowScene *scene = (UIWindowScene *)array[0];  
+        UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
+        [scene requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) { }];
+    } else {
+        UIDevice* currentDevice = [UIDevice currentDevice];
+        [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
+        [currentDevice setValue:@(newOrientation) forKey:orientation];
+    } 
 
     // restore device orientation
-    [currentDevice setValue:@(deviceOrientation) forKey:orientation];
+    // [currentDevice setValue:@(deviceOrientation) forKey:orientation];
     
     [UIViewController attemptRotationToDeviceOrientation];
     

also in ios/{projectName}/AppDelegate.mm i added

if (@available(iOS 16.0, *)) {
    NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
    UIWindowScene *scene = (UIWindowScene *)array[0];  
    UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
    [scene requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) { }];
} else {
    UIDevice* currentDevice = [UIDevice currentDevice];
    [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
    [currentDevice setValue:@(newOrientation) forKey:orientation];
}

but even after this patch i am able to go back to portrait mode from landscape mode but unable to lock orientation to portrait

ajayranga avatar Mar 23 '23 10:03 ajayranga

https://github.com/wonday/react-native-orientation-locker#configuration

Doing the fix in the mentioned PR as a patch (i.e. patch-package) + applying the fixes suggested here worked for me

patch for version 1.5.0:

diff --git a/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m b/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
index 6117764..849387a 100644
--- a/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
+++ b/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
@@ -125,13 +125,19 @@ - (void)lockToOrientation:(UIInterfaceOrientation) newOrientation usingMask:(UII
     UIInterfaceOrientation deviceOrientation = _lastDeviceOrientation;
     
     [Orientation setOrientation:mask];
-    UIDevice* currentDevice = [UIDevice currentDevice];
     
-    [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
-    [currentDevice setValue:@(newOrientation) forKey:orientation];
+    if (@available(iOS 16.0, *)) {
+        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
+        UIWindowScene *scene = (UIWindowScene *)array[0];    UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
+        [scene requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) { }];
+    } else {
+        UIDevice* currentDevice = [UIDevice currentDevice];
+        [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
+        [currentDevice setValue:@(newOrientation) forKey:orientation];
+        // restore device orientation
+        [currentDevice setValue:@(deviceOrientation) forKey:orientation];
+    }
     
-    // restore device orientation
-    [currentDevice setValue:@(deviceOrientation) forKey:orientation];
     
     [UIViewController attemptRotationToDeviceOrientation];
     

This works. 👍🏻

yqz0203 avatar May 10 '23 08:05 yqz0203

https://github.com/wonday/react-native-orientation-locker#configuration

Doing the fix in the mentioned PR as a patch (i.e. patch-package) + applying the fixes suggested here worked for me patch for version 1.5.0:

diff --git a/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m b/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
index 6117764..849387a 100644
--- a/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
+++ b/node_modules/react-native-orientation-locker/iOS/RCTOrientation/Orientation.m
@@ -125,13 +125,19 @@ - (void)lockToOrientation:(UIInterfaceOrientation) newOrientation usingMask:(UII
     UIInterfaceOrientation deviceOrientation = _lastDeviceOrientation;
     
     [Orientation setOrientation:mask];
-    UIDevice* currentDevice = [UIDevice currentDevice];
     
-    [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
-    [currentDevice setValue:@(newOrientation) forKey:orientation];
+    if (@available(iOS 16.0, *)) {
+        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
+        UIWindowScene *scene = (UIWindowScene *)array[0];    UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
+        [scene requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) { }];
+    } else {
+        UIDevice* currentDevice = [UIDevice currentDevice];
+        [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
+        [currentDevice setValue:@(newOrientation) forKey:orientation];
+        // restore device orientation
+        [currentDevice setValue:@(deviceOrientation) forKey:orientation];
+    }
     
-    // restore device orientation
-    [currentDevice setValue:@(deviceOrientation) forKey:orientation];
     
     [UIViewController attemptRotationToDeviceOrientation];
     

This works. 👍🏻

I applied same changes.But still screen doesn't rotate to LANDSCAPE mode. Surprising thing is LANDSCAPE orientation is working as expected in debug mode without applying above changes. But not working in release mode even after applying above changes.

Am i missing anything here?

Yandamuri avatar Oct 06 '23 13:10 Yandamuri

Hi. This is 2024 and I still face error: BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:) on iOS I followed this pull request and updated Orientation.m in "react-native-orientation-locker": "^1.6.0" but it still isn't working? Does anyone have a solution for it?

@@ -138,10 +138,17 @@ static UIInterfaceOrientationMask _orientationMask = UIInterfaceOrientationMaskA
     UIInterfaceOrientation deviceOrientation = _lastDeviceOrientation;
     
     [Orientation setOrientation:mask];
-    UIDevice* currentDevice = [UIDevice currentDevice];
 
-    [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
-    [currentDevice setValue:@(newOrientation) forKey:orientation];
+    if (@available(iOS 16.0, *)) {
+        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
+        UIWindowScene *scene = (UIWindowScene *)array[0];
+        UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
+        [scene requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) { }];
+    } else {
+        UIDevice* currentDevice = [UIDevice currentDevice];
+        [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
+        [currentDevice setValue:@(newOrientation) forKey:orientation];
+    }
 
     [UIViewController attemptRotationToDeviceOrientation];
     
@@ -168,8 +175,7 @@ RCT_EXPORT_METHOD(configure:(NSDictionary *)options)

zhenguet avatar Apr 10 '24 10:04 zhenguet

Hi. This is 2024 and I still face error: BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:) on iOS I followed this pull request and updated Orientation.m in "react-native-orientation-locker": "^1.6.0" but it still isn't working? Does anyone have a solution for it?

@@ -138,10 +138,17 @@ static UIInterfaceOrientationMask _orientationMask = UIInterfaceOrientationMaskA
     UIInterfaceOrientation deviceOrientation = _lastDeviceOrientation;
     
     [Orientation setOrientation:mask];
-    UIDevice* currentDevice = [UIDevice currentDevice];
 
-    [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
-    [currentDevice setValue:@(newOrientation) forKey:orientation];
+    if (@available(iOS 16.0, *)) {
+        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
+        UIWindowScene *scene = (UIWindowScene *)array[0];
+        UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
+        [scene requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) { }];
+    } else {
+        UIDevice* currentDevice = [UIDevice currentDevice];
+        [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
+        [currentDevice setValue:@(newOrientation) forKey:orientation];
+    }
 
     [UIViewController attemptRotationToDeviceOrientation];
     
@@ -168,8 +175,7 @@ RCT_EXPORT_METHOD(configure:(NSDictionary *)options)

This has been implemented as of release 1.7.0, however, lockToPortrait() and lockToLandscape() do not rotate the view (at least in the simulator like it does for Android). I was expecting this to do so.

I still get

[UIKitCore] BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported.
Please use UIWindowScene.requestGeometryUpdate(_:)

Am I wrong in my expectation?

paul-rinaldi avatar Jul 05 '24 19:07 paul-rinaldi

Hi. This is 2024 and I still face error: BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:) on iOS I followed this pull request and updated Orientation.m in "react-native-orientation-locker": "^1.6.0" but it still isn't working? Does anyone have a solution for it?

@@ -138,10 +138,17 @@ static UIInterfaceOrientationMask _orientationMask = UIInterfaceOrientationMaskA
     UIInterfaceOrientation deviceOrientation = _lastDeviceOrientation;
     
     [Orientation setOrientation:mask];
-    UIDevice* currentDevice = [UIDevice currentDevice];
 
-    [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
-    [currentDevice setValue:@(newOrientation) forKey:orientation];
+    if (@available(iOS 16.0, *)) {
+        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
+        UIWindowScene *scene = (UIWindowScene *)array[0];
+        UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
+        [scene requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) { }];
+    } else {
+        UIDevice* currentDevice = [UIDevice currentDevice];
+        [currentDevice setValue:@(UIInterfaceOrientationUnknown) forKey:orientation];
+        [currentDevice setValue:@(newOrientation) forKey:orientation];
+    }
 
     [UIViewController attemptRotationToDeviceOrientation];
     
@@ -168,8 +175,7 @@ RCT_EXPORT_METHOD(configure:(NSDictionary *)options)

This has been implemented as of release 1.7.0, however, lockToPortrait() and lockToLandscape() do not rotate the view (at least in the simulator like it does for Android). I was expecting this to do so.

I still get

[UIKitCore] BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported.
Please use UIWindowScene.requestGeometryUpdate(_:)

Am I wrong in my expectation?

Same, I'm somewhat confused here. I could enable Landscape Left and Landscape Right, but lockToPortrait() is not working so the user is able to change orientation all across the application

akuul avatar Jul 11 '24 12:07 akuul