| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- #include "SplashScreen.h"
- #include "UnityViewControllerBase.h"
- #include "OrientationSupport.h"
- #include "Unity/ObjCRuntime.h"
- #include "UI/UnityView.h"
- #include <cstring>
- #include "Unity/UnitySharedDecls.h"
- #include <utility>
- static SplashScreen* _splash = nil;
- static SplashScreenController* _controller = nil;
- @implementation SplashScreen
- {
- UIImageView* m_ImageView;
- UIView* m_XibView;
- }
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame: frame];
- return self;
- }
- - (void)createUI
- {
- NSString* launchScreen = [[NSBundle mainBundle].infoDictionary[@"UILaunchStoryboardName"] stringByDeletingPathExtension];
- const bool hasXIB = [[NSBundle mainBundle] pathForResource: launchScreen ofType: @"nib"] != nil;
- if (hasXIB)
- {
- self->m_XibView = [[[NSBundle mainBundle] loadNibNamed: launchScreen owner: nil options: nil] objectAtIndex: 0];
- [self addSubview: self->m_XibView];
- }
- else
- {
- #if !PLATFORM_TVOS
- NSAssert(NO, @"no storyboard/xib was provided.");
- #endif
- // we still support launch images on tvos, but unlike iOS there are only two options and no orientations
- UIImage* launchImage = nil;
- if ([UIScreen mainScreen].scale > 1.0)
- launchImage = [UIImage imageNamed: @"LaunchImage@2x"];
- if (!launchImage)
- launchImage = [UIImage imageNamed: @"LaunchImage@"];
- self->m_ImageView = [[UIImageView alloc] initWithImage: launchImage];
- [self addSubview: self->m_ImageView];
- }
- }
- - (void)updateOrientation:(ScreenOrientation)orient withSupportedOrientations:(const OrientationMask&)supportedOrientations
- {
- CGFloat scale = UnityScreenScaleFactor([UIScreen mainScreen]);
- UnityReportResizeView((unsigned)(self.bounds.size.width * scale), (unsigned)(self.bounds.size.height * scale), orient);
- ReportSafeAreaChangeForView(self);
- // for iOS only xib/storyboard are supported, for tvOS (launch images are supported) no orientation takes place at all
- }
- - (void)layoutSubviews
- {
- if (self->m_XibView)
- self->m_XibView.frame = self.bounds;
- else if (self->m_ImageView)
- self->m_ImageView.frame = self.bounds;
- }
- + (SplashScreen*)Instance
- {
- return _splash;
- }
- - (void)freeSubviews
- {
- m_ImageView = nil;
- m_XibView = nil;
- }
- @end
- @implementation SplashScreenController
- {
- OrientationMask _supportedOrientations;
- }
- - (id)init
- {
- self = [super init];
- if (self)
- {
- self->_supportedOrientations = { false, false, false, false };
- }
- return self;
- }
- - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
- {
- ScreenOrientation curOrient = UIViewControllerOrientation(self);
- ScreenOrientation newOrient = OrientationAfterTransform(curOrient, [coordinator targetTransform]);
- [_splash updateOrientation: newOrient withSupportedOrientations: self->_supportedOrientations];
- [super viewWillTransitionToSize: size withTransitionCoordinator: coordinator];
- }
- - (void)create:(UIWindow*)window
- {
- NSArray* supportedOrientation = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"UISupportedInterfaceOrientations"];
- // splash will be shown way before unity is inited so we need to override autorotation handling with values read from info.plist
- self->_supportedOrientations.portrait = [supportedOrientation containsObject: @"UIInterfaceOrientationPortrait"];
- self->_supportedOrientations.portraitUpsideDown = [supportedOrientation containsObject: @"UIInterfaceOrientationPortraitUpsideDown"];
- self->_supportedOrientations.landscapeLeft = [supportedOrientation containsObject: @"UIInterfaceOrientationLandscapeRight"];
- self->_supportedOrientations.landscapeRight = [supportedOrientation containsObject: @"UIInterfaceOrientationLandscapeLeft"];
- // special handling of devices/ios that do not support upside down orientation
- if (!UnityDeviceSupportsUpsideDown())
- {
- self->_supportedOrientations.portraitUpsideDown = false;
- OrientationMask om = self->_supportedOrientations;
- const bool anySupported = om.portrait || om.landscapeLeft || om.landscapeRight;
- if (!anySupported)
- {
- self->_supportedOrientations.portrait = true;
- printf_console("This device does not support UpsideDown orientation, so we switched to Portrait.\n");
- }
- }
- _splash = [[SplashScreen alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
- _splash.contentScaleFactor = UnityScreenScaleFactor([UIScreen mainScreen]);
- _splash.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- _splash.autoresizesSubviews = YES;
- [_splash createUI];
- window.rootViewController = self;
- self.view = _splash;
- [window addSubview: _splash];
- [window bringSubviewToFront: _splash];
- ScreenOrientation orient = UIViewControllerOrientation(self);
- [_splash updateOrientation: orient withSupportedOrientations: self->_supportedOrientations];
- OrientView([SplashScreenController Instance], _splash, orient);
- }
- #if PLATFORM_IOS
- - (BOOL)shouldAutorotate
- {
- return YES;
- }
- - (NSUInteger)supportedInterfaceOrientations
- {
- NSUInteger ret = 0;
- if (self->_supportedOrientations.portrait)
- ret |= (1 << UIInterfaceOrientationPortrait);
- if (self->_supportedOrientations.portraitUpsideDown)
- ret |= (1 << UIInterfaceOrientationPortraitUpsideDown);
- if (self->_supportedOrientations.landscapeLeft)
- ret |= (1 << UIInterfaceOrientationLandscapeRight);
- if (self->_supportedOrientations.landscapeRight)
- ret |= (1 << UIInterfaceOrientationLandscapeLeft);
- return ret;
- }
- #endif
- + (SplashScreenController*)Instance
- {
- return _controller;
- }
- @end
- void ShowSplashScreen(UIWindow* window)
- {
- NSString* launchScreen = [[NSBundle mainBundle].infoDictionary[@"UILaunchStoryboardName"] stringByDeletingPathExtension];
- #if PLATFORM_IOS
- // since launch images are no longer supported on ios we MUST have UILaunchStoryboardName filled
- assert(launchScreen != nil && "UILaunchStoryboardName key is missing from info.plist");
- #endif
- const bool hasStoryboard = launchScreen != nil && [[NSBundle mainBundle] pathForResource: launchScreen ofType: @"storyboardc"] != nil;
- if (hasStoryboard)
- {
- UIStoryboard *storyboard = [UIStoryboard storyboardWithName: launchScreen bundle: [NSBundle mainBundle]];
- // on ios13 we can finally tweak initial storyboard view controller: use unity base view controller
- // this way we can handle orientations/status-bar/whatever-we-want-to-tweak uniformly
- // as we still support xcode pre-11 we must do this weird dance of checking for both sdk and runtime version
- // otherwise it fails to compile (due to unknown selector)
- #if (PLATFORM_IOS && defined(__IPHONE_13_0)) || (PLATFORM_TVOS && defined(__TVOS_13_0))
- if (@available(iOS 13.0, tvOS 13.0, *))
- {
- _controller = [storyboard instantiateInitialViewControllerWithCreator:^(NSCoder *coder) {
- return [AllocUnityViewController() initWithCoder: coder];
- }];
- }
- else
- #endif
- {
- _controller = [storyboard instantiateInitialViewController];
- }
- window.rootViewController = _controller;
- }
- else
- {
- _controller = [[SplashScreenController alloc] init];
- [_controller create: window];
- }
- [window makeKeyAndVisible];
- }
- void HideSplashScreen()
- {
- if (_splash)
- {
- [_splash removeFromSuperview];
- [_splash freeSubviews];
- }
- _splash = nil;
- _controller = nil;
- }
|