iOS: Added support for iOS 8 LaunchScreen NIBs.

iOS 8 introduces LaunchScreen NIBs which use autolayout to handle all devices and orientations with a single NIB instead of multiple launch images. This is also the only way to get the App Store badge "Optimized for iPhone 6 and iPhone 6 Plus". So if the application is running on iOS 8 or greater AND has specified a LaunchScreen in their Info.plist, this patch will use the NIB as the launch screen. Otherwise, the code falls back to the legacy code path.

Note: Upon audit of the legacy path, it appears that it does not properly handle the UILaunchImages Info.plist convention. I've added comments inline to the code about this. However, in about a year from now, nobody is going to care about this path since everybody should be using LaunchScreen NIBs.
main
Eric Wing 2014-11-02 20:55:13 -08:00
parent ecc014740a
commit ef559ddb4c
1 changed files with 83 additions and 4 deletions

View File

@ -75,6 +75,62 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa
[UIApplication sharedApplication].idleTimerDisabled = disable; [UIApplication sharedApplication].idleTimerDisabled = disable;
} }
@interface SDL_launchscreenviewcontroller : UIViewController {
}
@end
@implementation SDL_launchscreenviewcontroller
- (id)init
{
self = [super init];
if (self == nil) {
return nil;
}
NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
if(launch_screen_name) {
// TODO: If the NIB is not in the bundle, this will throw an exception. We might consider a pre-emptive check, but returning a useless viewcontroller isn't helpful and the check should be outside.
UIView* launch_screen = [[[NSBundle mainBundle] loadNibNamed:launch_screen_name owner:self options:nil] objectAtIndex:0];
CGSize size = [UIScreen mainScreen].bounds.size;
CGRect bounds = CGRectMake(0, 0, size.width, size.height);
[launch_screen setFrame:bounds];
[self setView:launch_screen];
[launch_screen release];
}
return self;
}
- (NSUInteger)supportedInterfaceOrientations
{
NSUInteger orientationMask = UIInterfaceOrientationMaskAll;
/* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
}
return orientationMask;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
{
NSUInteger orientationMask = [self supportedInterfaceOrientations];
return (orientationMask & (1 << orient));
}
@end
@interface SDL_splashviewcontroller : UIViewController { @interface SDL_splashviewcontroller : UIViewController {
UIImageView *splash; UIImageView *splash;
UIImage *splashPortrait; UIImage *splashPortrait;
@ -98,6 +154,13 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa
CGSize size = [UIScreen mainScreen].bounds.size; CGSize size = [UIScreen mainScreen].bounds.size;
float height = SDL_max(size.width, size.height); float height = SDL_max(size.width, size.height);
/* FIXME: Some where around iOS 7, UILaunchImages in the Info.plist was introduced which explicitly maps image names to devices and orientations.
This gets rid of the hardcoded magic file names and allows more control for OS version, orientation, retina, and device.
But this existing code needs to be modified to look in the Info.plist for each key and act appropriately for the correct iOS version.
But iOS 8 superscedes this process and introduces the LaunchScreen NIB which uses autolayout to handle all orientations and devices.
Since we now have a LaunchScreen solution, this may never get fixed,
but this note is here for anybody trying to debug their program on iOS 7 and doesn't understand why their Info.plist isn't working.
*/
self->splashPortrait = [UIImage imageNamed:[NSString stringWithFormat:@"Default-%dh.png", (int)height]]; self->splashPortrait = [UIImage imageNamed:[NSString stringWithFormat:@"Default-%dh.png", (int)height]];
if (!self->splashPortrait) { if (!self->splashPortrait) {
self->splashPortrait = [UIImage imageNamed:@"Default.png"]; self->splashPortrait = [UIImage imageNamed:@"Default.png"];
@ -207,10 +270,26 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa
/* Keep the launch image up until we set a video mode */ /* Keep the launch image up until we set a video mode */
launch_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; launch_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIViewController *splashViewController = [[SDL_splashviewcontroller alloc] init]; /* iOS 8 introduces LaunchScreen NIBs which use autolayout to handle all devices and orientations with a single NIB instead of multiple launch images.
launch_window.rootViewController = splashViewController; This is also the only way to get the App Store badge "Optimized for iPhone 6 and iPhone 6 Plus".
[launch_window addSubview:splashViewController.view]; So if the application is running on iOS 8 or greater AND has specified a LaunchScreen in their Info.plist, we should use the LaunchScreen NIB.
[launch_window makeKeyAndVisible]; Otherwise, we should fallback to the legacy behavior of launch screen images.
*/
NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
if( ([[UIDevice currentDevice].systemVersion intValue] >= 8) && (nil != launch_screen_name) ) {
// iOS 8.0 and above uses LaunchScreen.xib
SDL_launchscreenviewcontroller* launch_screen_view_controller = [[SDL_launchscreenviewcontroller alloc] init];
launch_window.rootViewController = launch_screen_view_controller;
[launch_window addSubview:launch_screen_view_controller.view];
[launch_window makeKeyAndVisible];
} else {
// Anything less than iOS 8.0
UIViewController *splashViewController = [[SDL_splashviewcontroller alloc] init];
launch_window.rootViewController = splashViewController;
[launch_window addSubview:splashViewController.view];
[launch_window makeKeyAndVisible];
}
/* Set working directory to resource path */ /* Set working directory to resource path */
[[NSFileManager defaultManager] changeCurrentDirectoryPath: [[NSBundle mainBundle] resourcePath]]; [[NSFileManager defaultManager] changeCurrentDirectoryPath: [[NSBundle mainBundle] resourcePath]];