iOS 7 / Xcode 5: Access device launch images programmatically

22,219

Solution 1

You can use the launch images without having to include them twice. The key is that when you use an asset catalog, the file names of the images that are included in the app bundle are (sort of) standardized and may not be related to what you've named the original files.

In particular, when you use the LaunchImage image set, the files that end up in the application bundle have names like

etc. Note, in particular, they are not named Default.png or any variation of that. Even if that's what you called the files. Once you've dropped them in one of the wells in the asset catalog, they come out the other end with a standard name.

So [UIImage imageNamed:@"Default"] won't work because there is no such file in the app bundle. However, [UIImage imageNamed:@"LaunchImage"] will work (assuming you've filled either the iPhone Portrait 2x well or the pre iOS7 iPhone Portrait 1x well).

The documentation indicates that the imageNamed: method on UIImage should auto-magically select the correct version, but I think this only applies to image sets other than the launch image--at least I've not gotten it to work quite correctly (could just be me not doing something right).

So depending on your exact circumstances, you might need to do a little trial and error to get the correct file name. Build and run the app in the simulator and then you can always look in the appropriate subdirectory of ~/Library/Application Support/iPhone Simulator to verify what the actual file names in the app bundle are.

But again, the main point is that there is no need to include duplicates of the image files and you don't need to make any adjustments to the Copy Bundle Resources build phase.

Solution 2

You can copy/paste the following code to load your app's launch image at runtime:

// Load launch image
NSString *launchImageName;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
    if ([UIScreen mainScreen].bounds.size.height == 480) launchImageName = @"[email protected]"; // iPhone 4/4s, 3.5 inch screen
    if ([UIScreen mainScreen].bounds.size.height == 568) launchImageName = @"[email protected]"; // iPhone 5/5s, 4.0 inch screen
    if ([UIScreen mainScreen].bounds.size.height == 667) launchImageName = @"[email protected]"; // iPhone 6, 4.7 inch screen
    if ([UIScreen mainScreen].bounds.size.height == 736) launchImageName = @"[email protected]"; // iPhone 6+, 5.5 inch screen
}
else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
    if ([UIScreen mainScreen].scale == 1) launchImageName = @"LaunchImage-700-Portrait~ipad.png"; // iPad 2
    if ([UIScreen mainScreen].scale == 2) launchImageName = @"LaunchImage-700-Portrait@2x~ipad.png"; // Retina iPads
}
self.launchImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:launchImageName]];

Solution 3

Most answers require to create an image name depending on device type, scale, size etc. But as Matthew Burke pointed out, each image inside the launch image catalog will be renamed to "LaunchImage*" and therefore we are able to iterate through our launch images and find the (for the current device) appropriate image. In Objective-C it could look like this:

NSArray *allPngImageNames = [[NSBundle mainBundle] pathsForResourcesOfType:@"png"
                                        inDirectory:nil];

for (NSString *imgName in allPngImageNames){
    // Find launch images
    if ([imgName containsString:@"LaunchImage"]){
        UIImage *img = [UIImage imageNamed:imgName];
        // Has image same scale and dimensions as our current device's screen?
        if (img.scale == [UIScreen mainScreen].scale && CGSizeEqualToSize(img.size, [UIScreen mainScreen].bounds.size)) {
            NSLog(@"Found launch image for current device %@", img.description);
            break;
        }
    }
}

(Please note that this code uses the "containsString" method introduced with iOS 8. For previous iOS versions use "rangeOfString")

Solution 4

A Swift version of the excellent answer by Daniel Witurna that doesn't require checking against a list of all known device types or orientations.

func appLaunchImage() -> UIImage? {

        let allPngImageNames = Bundle.main.paths(forResourcesOfType: "png", inDirectory: nil)

        for imageName in allPngImageNames
        {
            // make sure that the image name contains the string 'LaunchImage' and that we can actually create a UIImage from it.

            guard
                imageName.contains("LaunchImage"), 
                let image = UIImage(named: imageName) 
                else { continue }

            // if the image has the same scale AND dimensions as the current device's screen...

            if (image.scale == UIScreen.main.scale) && (image.size.equalTo(UIScreen.main.bounds.size))
            {
                return image
            }
        }

        return nil
    }

Solution 5

Below is the result when I test in iOS 7.0+, only portrait oritation:

3.5 inch screen: [email protected]
4.0 inch screen: [email protected]
4.7 inch screen: [email protected]
5.5 inch screen: [email protected]
iPad2          : LaunchImage-700-Portrait~ipad.png
Retina iPads   : LaunchImage-700-Portrait@2x~ipad.png
Share:
22,219
Timm
Author by

Timm

Updated on July 17, 2022

Comments

  • Timm
    Timm almost 2 years

    Is there any way to use the apps LaunchImage as a background in an universal iOS app without putting the same image resources in multiple places?

    I wasn't able to access the LaunchImage files in Images.xcassets, so I created two new Image Sets "Background Portrait" and "Background Landscape" (since there seems to be no way to put landscape and portrait images into the same set).

    While this workaround does the jobs, I would hate to include every image into the app twice. This also has a high maintenance cost.

    Any advice on how to access the LaunchImage for the current device is appreciated.

    GCOLaunchImageTransition must have done the job for iOS < 7.

  • Timm
    Timm over 10 years
    While "Images.xcassets" is already in the "Copy Bundle Resources" section, I can't see it when clicking + to add individual files. And currently "[UIImage imageNamed:@"Default"];" does not work for me.
  • Peter Segerblom
    Peter Segerblom over 10 years
    You need to click first '+' then "add other" then navigate to your Images.xcassets->LaunchImage.launchimage. Images.xcassets is just a folder.
  • john.k.doe
    john.k.doe over 10 years
    i've upvoted this answer … but i'm also interested in being able to see the image in my .xib, and choosing "LaunchImage" in my .xib works on the device (and probably on the simulator), but just shows the big blue question mark in the .xib . any easy resolution to this part of it?
  • Alex Sorokoletov
    Alex Sorokoletov over 9 years
    So, did anyone made [UIImage imageNamed:@"LaunchImage"] work?
  • Rolleric
    Rolleric over 9 years
    I would think that, in order to avoid searching every time, the resulting imgName (or its lastPathComponent) could be stored as a local User Default.
  • Daniel Witurna
    Daniel Witurna over 9 years
    @Rolleric I thought about your suggestion and probably you are right. The defined launch image will always have the same name, even if you change it, and the user defaults are device bound so this should be fine too. However, I am not sure how costly the search is. Probably it's just a trade-off between speed and storage.
  • Alex Sorokoletov
    Alex Sorokoletov over 9 years
    For my tamarin app it, unfortunately, didn't
  • Rober
    Rober over 9 years
    This solution is not answering the question since it is asked to access the LaunchImage without duplicated assets.
  • bshirley
    bshirley over 9 years
    My answer is No. You should not try to access the launch image. If you figure out how to access it now, Apple is likely to change it out from under you. If one image the size of the screen is killing your app size, something else is wrong.
  • AlexD
    AlexD over 9 years
    imageNamed didn't work for me on iOS 7 - instead you can use imageWithContentsOfFile
  • Daniel Witurna
    Daniel Witurna over 9 years
    @AlexD I am actually using the function with deployment target iOS 7 but compiling against the iOS 8 SDK. According to Apple's documentation "imageNamed" is available since iOS 2.0 (developer.apple.com/library/ios/documentation/UIKit/Referen‌​ce/…). The only difference is, that "imageNamed" caches the image in background and "imageWithContentsOfFile" doesn't, which "will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app." (Apple Doc)
  • Tom
    Tom almost 9 years
    This is by far the best solution
  • alexburtnik
    alexburtnik over 8 years
    Thanks. This solution worked for me, unlike the accepted answer from Matthew Burke
  • AsifHabib
    AsifHabib over 8 years
    Which one is for which device ?
  • Dan Rosenstark
    Dan Rosenstark over 8 years
    Wow this annoying, but thanks for sharing your answer. Confirmed that this works...
  • Simo
    Simo almost 8 years
    Much prefer this solution over any others here. Just added a Swift version of this answer to help anyone needing one.
  • Ryan H.
    Ryan H. over 7 years
    This solution made me realize that the name used to reference the image has nothing to do with the actual filenames in the catalogue. It's a combination of the collection name (Brand Assets in my case) plus some "magic" suffixes. This solution would be more foolproof from future changes made by Apple, since the actual image name syntax is undocumented.
  • Ryan H.
    Ryan H. over 7 years
    One easy optimization is to break out of the for loop when the match is found.
  • Apex
    Apex over 6 years
    Though xcode (thankfully) modernized a bunch of naming conventions, this foundation is spectacular in xcode 9, swift 3, iOS 10.3 (for maintaining a seamless 'book cover' from app launch LaunchImage to user's first tap). Thank you!! :)
  • SDW
    SDW over 6 years
    Use [email protected] for iPhone X
  • Dimitris
    Dimitris over 6 years
    @SebastiaandeWeert on the latest Xcode/SDK it seems that the iPhone X splash screen is named LaunchImage-1100-Portrait-2436h.
  • Ryno C.
    Ryno C. over 4 years
    Swift 4: This works for Portrait, but not for landscape. You need to change the screenSize to the following line: let screenSize = UIScreen.main.fixedCoordinateSpace.bounds.size. Added Swift 5 with fix