From b444df630bdf204c2cb124cb261e51d73f33abbb Mon Sep 17 00:00:00 2001 From: oofaish Date: Mon, 12 Dec 2022 00:55:43 +0000 Subject: [PATCH] feat(ios): add support for ios 16 (#107) * Include iOS 16 Support * Fix the unlock/lock issue by always calling setSupportedOrientations but only call setNeedsUpdateOfSupportedInterfaceOrientations at the end to avoid refreshing orientation twice --- src/ios/CDVOrientation.m | 123 +++++++++++++++++++++++++++++---------- 1 file changed, 93 insertions(+), 30 deletions(-) diff --git a/src/ios/CDVOrientation.m b/src/ios/CDVOrientation.m index ff718f8..b481114 100644 --- a/src/ios/CDVOrientation.m +++ b/src/ios/CDVOrientation.m @@ -28,6 +28,97 @@ @implementation CDVOrientation + +-(void)handleBelowEqualIos15WithOrientationMask:(NSInteger) orientationMask viewController: (CDVViewController*) vc result:(NSMutableArray*) result selector:(SEL) selector +{ + NSValue *value; + if (orientationMask != 15) { + if (!_isLocked) { + _lastOrientation = [UIApplication sharedApplication].statusBarOrientation; + } + UIInterfaceOrientation deviceOrientation = [UIApplication sharedApplication].statusBarOrientation; + if(orientationMask == 8 || (orientationMask == 12 && !UIInterfaceOrientationIsLandscape(deviceOrientation))) { + value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; + } else if (orientationMask == 4){ + value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight]; + } else if (orientationMask == 1 || (orientationMask == 3 && !UIInterfaceOrientationIsPortrait(deviceOrientation))) { + value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait]; + } else if (orientationMask == 2) { + value = [NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown]; + } + } else { + if (_lastOrientation != UIInterfaceOrientationUnknown) { + [[UIDevice currentDevice] setValue:[NSNumber numberWithInt:_lastOrientation] forKey:@"orientation"]; + ((void (*)(CDVViewController*, SEL, NSMutableArray*))objc_msgSend)(vc,selector,result); + [UINavigationController attemptRotationToDeviceOrientation]; + } + } + if (value != nil) { + _isLocked = true; + [[UIDevice currentDevice] setValue:value forKey:@"orientation"]; + } else { + _isLocked = false; + } +} + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" +// this will stop it complaining about new iOS16 APIs being used. +-(void)handleAboveEqualIos16WithOrientationMask:(NSInteger) orientationMask viewController: (CDVViewController*) vc result:(NSMutableArray*) result selector:(SEL) selector +{ + NSObject *value; + // oritentationMask 15 is "unlock" the orientation lock. + if (orientationMask != 15) { + if (!_isLocked) { + _lastOrientation = [UIApplication sharedApplication].statusBarOrientation; + } + UIInterfaceOrientation deviceOrientation = [UIApplication sharedApplication].statusBarOrientation; + if(orientationMask == 8 || (orientationMask == 12 && !UIInterfaceOrientationIsLandscape(deviceOrientation))) { + value = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:UIInterfaceOrientationMaskLandscapeLeft]; + } else if (orientationMask == 4){ + value = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:UIInterfaceOrientationMaskLandscapeRight]; + } else if (orientationMask == 1 || (orientationMask == 3 && !UIInterfaceOrientationIsPortrait(deviceOrientation))) { + value = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:UIInterfaceOrientationMaskPortrait]; + } else if (orientationMask == 2) { + value = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:UIInterfaceOrientationMaskPortraitUpsideDown]; + } + } else { + ((void (*)(CDVViewController*, SEL, NSMutableArray*))objc_msgSend)(vc,selector,result); + } + if (value != nil) { + _isLocked = true; + UIWindowScene *scene = (UIWindowScene*)[[UIApplication.sharedApplication connectedScenes] anyObject]; + [scene requestGeometryUpdateWithPreferences:(UIWindowSceneGeometryPreferencesIOS*)value errorHandler:^(NSError * _Nonnull error) { + NSLog(@"Failed to change orientation %@ %@", error, [error userInfo]); + }]; + } else { + _isLocked = false; + } +} +#pragma clang diagnostic pop + +-(void)handleWithOrientationMask:(NSInteger) orientationMask viewController: (CDVViewController*) vc result:(NSMutableArray*) result selector:(SEL) selector +{ + if (@available(iOS 16.0, *)) { + [self handleAboveEqualIos16WithOrientationMask:orientationMask viewController:vc result:result selector:selector]; + // always double check the supported interfaces, so we update if needed + // but do it right at the end here to avoid the "double" rotation issue reported in + // https://github.com/apache/cordova-plugin-screen-orientation/pull/107 + [self.viewController setNeedsUpdateOfSupportedInterfaceOrientations]; + } else { + [self handleBelowEqualIos15WithOrientationMask:orientationMask viewController:vc result:result selector:selector]; + } + +} +#else +-(void)handleWithOrientationMask:(NSInteger) orientationMask viewController: (CDVViewController*) vc result:(NSMutableArray*) result selector:(SEL) selector +{ + [self handleBelowEqualIos15WithOrientationMask:orientationMask viewController:vc result:result selector:selector]; +} +#endif + + -(void)screenOrientation:(CDVInvokedUrlCommand *)command { CDVPluginResult* pluginResult; @@ -47,43 +138,15 @@ if(orientationMask & 8) { [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]]; } - SEL selector = NSSelectorFromString(@"setSupportedOrientations:"); if([vc respondsToSelector:selector]) { if (orientationMask != 15 || [UIDevice currentDevice] == nil) { ((void (*)(CDVViewController*, SEL, NSMutableArray*))objc_msgSend)(vc,selector,result); } - + if ([UIDevice currentDevice] != nil){ - NSNumber *value = nil; - if (orientationMask != 15) { - if (!_isLocked) { - _lastOrientation = [UIApplication sharedApplication].statusBarOrientation; - } - UIInterfaceOrientation deviceOrientation = [UIApplication sharedApplication].statusBarOrientation; - if(orientationMask == 8 || (orientationMask == 12 && !UIInterfaceOrientationIsLandscape(deviceOrientation))) { - value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; - } else if (orientationMask == 4){ - value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight]; - } else if (orientationMask == 1 || (orientationMask == 3 && !UIInterfaceOrientationIsPortrait(deviceOrientation))) { - value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait]; - } else if (orientationMask == 2) { - value = [NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown]; - } - } else { - if (_lastOrientation != UIInterfaceOrientationUnknown) { - [[UIDevice currentDevice] setValue:[NSNumber numberWithInt:_lastOrientation] forKey:@"orientation"]; - ((void (*)(CDVViewController*, SEL, NSMutableArray*))objc_msgSend)(vc,selector,result); - [UINavigationController attemptRotationToDeviceOrientation]; - } - } - if (value != nil) { - _isLocked = true; - [[UIDevice currentDevice] setValue:value forKey:@"orientation"]; - } else { - _isLocked = false; - } + [self handleWithOrientationMask:orientationMask viewController:vc result:result selector:selector]; } pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];