iOS.Lover
iOS.Lover

Reputation: 6051

Changing alternate icon for iPad

I have a problem with changing app's icon on iPad. Everything is working fine on iPhone but on iPad I get this error :

[default] Failed to set preferredIconName to AI-Gorgosaurus for ...:0> error: Error Domain=NSCocoaErrorDomain Code=4 "The file doesn’t exist." UserInfo={NSUnderlyingError=0x600000248a30 {Error Domain=LSApplicationWorkspaceErrorDomain Code=-105 "iconName not found in CFBundleAlternateIcons entry" UserInfo={NSLocalizedDescription=iconName not found in CFBundleAlternateIcons entry}}} App icon failed to due to The file doesn’t exist.

I searched ad found that I need to add ~ipad in CFBundleIconFiles but still get the same error!.

Here is the code:

  func changeIcon(to name: String?) {
        //Check if the app supports alternating icons
        guard UIApplication.shared.supportsAlternateIcons else {
            return;
        }

        //Change the icon to a specific image with given name
        UIApplication.shared.setAlternateIconName(name) { (error) in
            //After app icon changed, print our error or success message
            if let error = error {
                print("App icon failed to due to \(error.localizedDescription)")
            } else {
                print("App icon changed successfully.")
            }
        }
    }

enter image description here

I just tested on another project and works fine !!! but not on my current project why ?! have you any idea?

Upvotes: 25

Views: 7438

Answers (7)

D1mers0n
D1mers0n

Reputation: 470

With Xcode 13+ no need to work with files/plist manually anymore. You just need to set to YES the “Include All App Icon Assets” setting under build settings. Or click on "Your Target" - General - App Icons and Launch Screen - Include All App Icon Assets.

Include app icon assets

After that just add icons to xcassets catalog. (For some reason it doesn't always work on iPad with a Single Size icons, so you should better use Icon Set with all icon sizes).

Better avoid using symbols in the name of icons. It didn't work for me on iPad with icon name "Icon-Red", but it worked fine with "IconRed"

Use the code provided in the previous answers.

Swift sample

UIApplication.shared.setAlternateIconName("IconRed", completionHandler: nil)

Obj-C sample

[[UIApplication sharedApplication] setAlternateIconName:@"IconRed" completionHandler:nil];

Upvotes: 3

Confused Vorlon
Confused Vorlon

Reputation: 10466

Attempting to give a more re-useable (easy to copy/paste) version of this answer.

1) You need images of the following names and sizes added as regular .png files (no asset catalogues)

.../AppIcon-Dark/iPad-app.png
  pixelWidth: 76
.../AppIcon-Dark/[email protected]
  pixelWidth: 152
.../AppIcon-Dark/[email protected]
  pixelWidth: 167
.../AppIcon-Dark/[email protected]
  pixelWidth: 120
.../AppIcon-Dark/[email protected]
  pixelWidth: 180

you can then add/insert the following in your info.plist

<key>CFBundleIcons</key>
<dict>
    <key>CFBundleAlternateIcons</key>
    <dict>
        <key>AppIcon-Dark</key>
        <dict>
            <key>CFBundleIconFiles</key>
            <array>
                <string>iPhone-app</string>
            </array>
        </dict>
    </dict>
    <key>CFBundlePrimaryIcon</key>
    <dict>
        <key>CFBundleIconFiles</key>
        <array>
            <string>AppIcon</string>
        </array>
    </dict>
</dict>
<key>CFBundleIcons~ipad</key>
<dict>
    <key>CFBundleAlternateIcons</key>
    <dict>
        <key>AppIcon-Dark</key>
        <dict>
            <key>CFBundleIconFiles</key>
            <array>
                <string>iPad-app</string>
                <string>iPad-pro</string>
            </array>
        </dict>
    </dict>
    <key>CFBundlePrimaryIcon</key>
    <dict>
        <key>CFBundleIconFiles</key>
        <array>
            <string>AppIcon</string>
        </array>
    </dict>
</dict>

I then set my icon with the following

func updateIcon() {
    if #available(iOS 13.0, *) {
        let dark = window?.traitCollection.userInterfaceStyle == .dark

        let currentIconName = UIApplication.shared.alternateIconName
        let desiredIconName:String? = dark ? "AppIcon-Dark" : nil

        if currentIconName != desiredIconName {
            UIApplication.shared.setAlternateIconName(desiredIconName) {
                (error) in
                print("failed: \(String(describing: error))")
            }
        }
    }
}

Upvotes: 24

Dave Wood
Dave Wood

Reputation: 13353

Your info.plist is structured incorrectly.

You have:

- CFBundleIcons
  - CFBundleAlternateIcons
    - Icon Name
      - CFBundleIconFiles
      - CFBundleIconFiles~ipad

But it should be:

- CFBundleIcons
  - CFBundleAlternateIcons
    - Icon Name
      - CFBundleIconFiles
- CFBundleIcons~ipad
  - CFBundleAlternateIcons
    - Icon Name
     - CFBundleIconFiles

Basically, once you have it working with iPhone icons, CFBundleIcons, duplicate the entire tree as CFBundleIcons~ipad. The iPad files shouldn't be nested under CFBundleIcons at all.

You're mixing up CFBundleIcons~ipad and CFBundleIconFiles~ipad (which isn't a valid key).

Screenshot

Upvotes: 45

Rizwan Shaikh
Rizwan Shaikh

Reputation: 271

Please make these changes to your plist file for setting alternate icons for iPhone and iPad.

enter image description here

Upvotes: 5

AD Progress
AD Progress

Reputation: 5146

What I have noticed is that your plist has UIPrerenderedIcon set to NO

Change it to YES

It might be that the issue is with the rendering

Edit 1: add the .png extension to see if it helps

EDIT 2: Try changing the new icon's filename to ipadAlternate.png. Then change to the same name in the plist as it looks like there is some kind of mismatch with your plist and the icon file itself

EDIT 3: Have you cleaned the DerivedData folder? I had an issue a while ago and nothing helped including cleaning the project etc. But I tried deleting everything in the /Users/YOURUSERNAME/Library/Developer/Xcode/DerivedData/ folder and it started working again. It is worth giving it a go.

EDIT 4: Try doing step from EDIT 3. Then restart your project and delete all the alternative icon files from it. Choose move to trash and then CMD+SHIFT+K to clean. Then select CMD+B to build. Next add the icons back where they were. Check that the target is selected correctly and copy items if needed to be selected. For some reason Xcode lost track of your file and it is showing an error, no file.

If that will not help then try the above steps. But first try moving the whole project to a different folder.

EDIT 5: There is one more idea which you might try for yourself. Try deleting the plist file in the current project (keep a backup copy of it before deleting) then start a new project where the icon changing works fine. Add the plist from that project to this one. Check if the icon changing works. If yes then add all the missing keys you had in the previous project.

WARNING: This is a last resort but this may work. Start a new project and set it up with the icons which you want alternating. Check if they work first then add all the code and dependencies from the project where it doesn't work. Just don't override the PLIST files.

EDIT 6: Try deleting the app from the simulator or the device you are trying it on and reinstall it. The whole issue might be with the update and the leftovers from the previous version of the app.

EDIT 7: Try copying the project to another mac and see if the problem persists. Which xcode version are you using?? If it is Xcode 9, perhaps try using the Xcode 10 beta.

Upvotes: 0

Brian Nezhad
Brian Nezhad

Reputation: 6276

The error is showing a different file name than the one in .plist CFBundleAlternateIcons. Make sure you assign a correct Filename in and it actually exists in the project folder.

Error Shows AI-Gorgosaurus as the file name. .plist screenshot shows AI-Diabloceratops~ipad, also please remove ~ symbol from the file name.

Do a clean and build the project after you're sure file is correct. Make sure you have @2x and @3x version of your Icons in your project folder.

Read Kaiyuan Xu answer for a more clear picture on how to use CFBundleAlternateIcons.

Upvotes: -1

iVarun
iVarun

Reputation: 6631

With below structure i'm able to change icon in iPad:

    if #available(iOS 10.3, *) {
        let newAppIconName = "Icon2"

        guard UIApplication.shared.alternateIconName != newAppIconName else { return }

        UIApplication.shared.setAlternateIconName(newAppIconName)
    }
}

Plist Code:

<key>CFBundleIcons</key>
<dict>
    <key>CFBundlePrimaryIcon</key>
    <dict>
        <key>CFBundleIconFiles</key>
        <array>
            <string>AppIcon</string>
        </array>
        <key>UIPrerenderedIcon</key>
        <true/>
    </dict>
    <key>CFBundleAlternateIcons</key>
    <dict>
        <key>Icon2</key>
        <dict>
            <key>CFBundleIconFiles</key>
            <array>
                <string>icon60</string>
            </array>
            <key>CFBundleIcons~ipad</key>
            <array>
                <string>iTunesArtwork80.png</string>
            </array>
            <key>UIPrerenderedIcon</key>
            <true/>
        </dict>
    </dict>
</dict>

enter image description here

Upvotes: -2

Related Questions