{"metadata":{"image":[],"title":"","description":""},"api":{"url":"","auth":"required","results":{"codes":[]},"settings":"","params":[],"apiSetting":null},"next":{"description":"","pages":[]},"title":"iOS: Changing Icons with Push Notifications","type":"basic","slug":"changing-icons-with-push-notifications","excerpt":"","body":"Starting in iOS 10.3, Apps are able to maintain a set alternate icons which can be switched by the user at runtime. Imagine being able to theme your App Icon based on your home team in a sports app? Or have an icon change to reflect a Sale or campaign, such as Halloween?\n\n## Setting up the icons\nFor this new API, you unfortunately cannot use your XCAssets folder. You instead have to import icon assets using an older technique, by creating a group under Resources. \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/6c9eb80-Screen_Shot_2017-06-29_at_9.24.03_AM.png\",\n        \"Screen Shot 2017-06-29 at 9.24.03 AM.png\",\n        259,\n        365,\n        \"#f0f0ef\"\n      ],\n      \"caption\": \"We've included a minimal set for brevity, you should include all icons for all size iPhones and iPads.\"\n    }\n  ]\n}\n[/block]\n## Configuring your Property List\nInside your App's `Info.plist` file, add the following config to declare your main icon and it's alternatives. The file name should not include the :::at:::2x/@3x and filetype suffix.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/0b36996-Screen_Shot_2017-06-29_at_9.28.55_AM.png\",\n        \"Screen Shot 2017-06-29 at 9.28.55 AM.png\",\n        666,\n        182,\n        \"#cedbec\"\n      ]\n    }\n  ]\n}\n[/block]\n## Triggering icon changes\n\nNow, the final step is to configure your app to change the icon in a reaction to a push. We'll use [Key-Value Payloads](doc:key-value-payloads) to send down the alternate icon's key (the key for the dictionary above) and use the standard api for receiving pushes to react. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {\\n    NSString *iconName = userInfo[@\\\"icon_name\\\"];\\n    if (!iconName) {\\n        completionHandler(UIBackgroundFetchResultNoData);\\n        return;\\n    }\\n    \\n\\t  // We found this delay necessary in testing\\n    [self delay:1.0 closure:^{\\n        [self changeIcon:iconName];\\n        completionHandler(UIBackgroundFetchResultNewData);\\n    }];\\n}\\n\\n- (void)changeIcon:(NSString *)iconName {\\n    if (@available(iOS 10.3, *)) {\\n        if ([UIApplication sharedApplication].supportsAlternateIcons) {\\n            [[UIApplication sharedApplication] setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {\\n                if (error) {\\n                    NSLog(@\\\"Error setting icon: %@\\\", error);\\n                }\\n            }];\\n        }\\n        else {\\n            NSLog(@\\\"I cannot change icons\\\");\\n        }\\n    }\\n}\\n\\n- (void)delay:(double)delay closure:(void(^)())closure {\\n    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC);\\n    dispatch_after(when, dispatch_get_main_queue(), closure);\\n}\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {\\n    guard let iconName = userInfo[\\\"icon_name\\\"] as! String? else {\\n        completionHandler(.noData)\\n        return\\n    }\\n\\n    // We found this delay necessary in testing\\n    delay(1.0, closure: {\\n        self.changeIcon(iconName: iconName)\\n        completionHandler(.newData)\\n    })\\n}\\n\\nfunc changeIcon(iconName: String) {\\n    if #available(iOS 10.3, *) {\\n        if UIApplication.shared.supportsAlternateIcons {\\n            UIApplication.shared.setAlternateIconName(iconName) { (err:Error?) in\\n                print(\\\"Error setting icon: \\\\(String(describing: err))\\\")\\n            }\\n        } else  {\\n            print(\\\"I cannot change icons\\\")\\n        }\\n    }\\n}\\n\\nfunc delay(_ delay:Double, closure:@escaping ()->()) {\\n    let when = DispatchTime.now() + delay\\n    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)\\n}\",\n      \"language\": \"swift\"\n    }\n  ]\n}\n[/block]\n## Example\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/d6da21f-IconChangeGif.gif\",\n        \"IconChangeGif.gif\",\n        495,\n        880,\n        \"#38323f\"\n      ]\n    }\n  ]\n}\n[/block]","updates":[],"order":4,"isReference":false,"hidden":false,"sync_unique":"","link_url":"","link_external":false,"_id":"5e6156bf5e4a51006dcd816f","project":"55e67aaa9cc7c62b00c4a1ea","version":{"version":"1.5","version_clean":"1.5.0","codename":"ST Rebrand","is_stable":true,"is_beta":false,"is_hidden":false,"is_deprecated":false,"categories":["5e6156bf5e4a51006dcd8120","5e6156bf5e4a51006dcd8121","5e6156bf5e4a51006dcd8122","5e6156bf5e4a51006dcd8123","5e6156bf5e4a51006dcd8124","561c61b4ad272c0d00a892df","586c014c0abf1d0f000d04d4","58991d2ad207df0f0002186b","5e6156bf5e4a51006dcd8125","5e6156bf5e4a51006dcd8126","5af0fe494ca2730003cbc98a","5af0fe55ec80af0003804ca2","5e69868cbd5dcb006b35867b","5e6986ca2c6652006791b6e8"],"_id":"5e6156bf5e4a51006dcd818c","project":"55e67aaa9cc7c62b00c4a1ea","__v":2,"forked_from":"5b720760c44b7600034b7a08","createdAt":"2015-09-02T04:27:23.612Z","releaseDate":"2015-09-02T04:27:23.612Z"},"category":{"sync":{"isSync":false,"url":""},"pages":[],"title":"iOS Techniques","slug":"ios-techniques","order":9999,"from_sync":false,"reference":false,"_id":"5e6986ca2c6652006791b6e8","createdAt":"2020-03-12T00:48:10.039Z","version":"5e6156bf5e4a51006dcd818c","project":"55e67aaa9cc7c62b00c4a1ea","__v":0},"user":"55d29988486de50d00327118","createdAt":"2017-06-28T21:52:17.509Z","githubsync":"","__v":0,"parentDoc":null}

iOS: Changing Icons with Push Notifications


Starting in iOS 10.3, Apps are able to maintain a set alternate icons which can be switched by the user at runtime. Imagine being able to theme your App Icon based on your home team in a sports app? Or have an icon change to reflect a Sale or campaign, such as Halloween? ## Setting up the icons For this new API, you unfortunately cannot use your XCAssets folder. You instead have to import icon assets using an older technique, by creating a group under Resources. [block:image] { "images": [ { "image": [ "https://files.readme.io/6c9eb80-Screen_Shot_2017-06-29_at_9.24.03_AM.png", "Screen Shot 2017-06-29 at 9.24.03 AM.png", 259, 365, "#f0f0ef" ], "caption": "We've included a minimal set for brevity, you should include all icons for all size iPhones and iPads." } ] } [/block] ## Configuring your Property List Inside your App's `Info.plist` file, add the following config to declare your main icon and it's alternatives. The file name should not include the @2x/@3x and filetype suffix. [block:image] { "images": [ { "image": [ "https://files.readme.io/0b36996-Screen_Shot_2017-06-29_at_9.28.55_AM.png", "Screen Shot 2017-06-29 at 9.28.55 AM.png", 666, 182, "#cedbec" ] } ] } [/block] ## Triggering icon changes Now, the final step is to configure your app to change the icon in a reaction to a push. We'll use [Key-Value Payloads](doc:key-value-payloads) to send down the alternate icon's key (the key for the dictionary above) and use the standard api for receiving pushes to react. [block:code] { "codes": [ { "code": "- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {\n NSString *iconName = userInfo[@\"icon_name\"];\n if (!iconName) {\n completionHandler(UIBackgroundFetchResultNoData);\n return;\n }\n \n\t // We found this delay necessary in testing\n [self delay:1.0 closure:^{\n [self changeIcon:iconName];\n completionHandler(UIBackgroundFetchResultNewData);\n }];\n}\n\n- (void)changeIcon:(NSString *)iconName {\n if (@available(iOS 10.3, *)) {\n if ([UIApplication sharedApplication].supportsAlternateIcons) {\n [[UIApplication sharedApplication] setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {\n if (error) {\n NSLog(@\"Error setting icon: %@\", error);\n }\n }];\n }\n else {\n NSLog(@\"I cannot change icons\");\n }\n }\n}\n\n- (void)delay:(double)delay closure:(void(^)())closure {\n dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC);\n dispatch_after(when, dispatch_get_main_queue(), closure);\n}", "language": "objectivec" }, { "code": "func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {\n guard let iconName = userInfo[\"icon_name\"] as! String? else {\n completionHandler(.noData)\n return\n }\n\n // We found this delay necessary in testing\n delay(1.0, closure: {\n self.changeIcon(iconName: iconName)\n completionHandler(.newData)\n })\n}\n\nfunc changeIcon(iconName: String) {\n if #available(iOS 10.3, *) {\n if UIApplication.shared.supportsAlternateIcons {\n UIApplication.shared.setAlternateIconName(iconName) { (err:Error?) in\n print(\"Error setting icon: \\(String(describing: err))\")\n }\n } else {\n print(\"I cannot change icons\")\n }\n }\n}\n\nfunc delay(_ delay:Double, closure:@escaping ()->()) {\n let when = DispatchTime.now() + delay\n DispatchQueue.main.asyncAfter(deadline: when, execute: closure)\n}", "language": "swift" } ] } [/block] ## Example [block:image] { "images": [ { "image": [ "https://files.readme.io/d6da21f-IconChangeGif.gif", "IconChangeGif.gif", 495, 880, "#38323f" ] } ] } [/block]