{"_id":"5603fe3490ee490d004404c2","parentDoc":null,"project":"5540ce1b31827a0d007ab1cc","category":{"_id":"55a4ff5b2e70c0250038050f","pages":["55a4ff7d750a9a23005332af","55a4ff8b750a9a23005332b1","55a4ff9b750a9a23005332b3","55a60bfcaaf9cf1900114efb","55a6184880c8a30d00b32526","55a61ba780c8a30d00b32532","55a61c97aaf9cf1900114f40","55a61ea9aaf9cf1900114f48","55a6206580c8a30d00b32544","55a64277aaf9cf1900114fc2","55a694d1aaf9cf1900115102","55a6a23eaaf9cf19001151e2","55a6a9b389c9da1900e2a41d","55a6aba45f88a70d0065b255","55a90687c8bd450d000dd157","55af84f3aa902f1700300daa","55afa3e3902fd51700f5f858","55b0cc5cb3171b3700b153fa","56015bdc3aa0520d00da0ced","5603fe3490ee490d004404c2","5633dd18d28a340d004004f5","56448c697a8cb50d00a3ea3f","56d7a2ec5208281500a2506c","56d859b8b159f10b00304577","56d9822add90610b002708a1","56ef44c6e8d6fa17006f244f"],"version":"5540ce1c31827a0d007ab1cf","project":"5540ce1b31827a0d007ab1cc","__v":26,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-07-14T12:23:55.603Z","from_sync":false,"order":2,"slug":"features","title":"Features"},"user":"5540cdbf5cf9682100d61a97","__v":4,"version":{"_id":"5540ce1c31827a0d007ab1cf","project":"5540ce1b31827a0d007ab1cc","__v":31,"createdAt":"2015-04-29T12:27:08.390Z","releaseDate":"2015-04-29T12:27:08.390Z","categories":["5540ce1c31827a0d007ab1d0","5540d91bbb9e762d00f594ad","5540e5f131827a0d007ab212","5540e5febb9e762d00f594d3","5540e61331827a0d007ab213","5540e6195cf9682100d61afa","5540e62631827a0d007ab214","5540e63031827a0d007ab215","5540e63531827a0d007ab216","5540e63e5cf9682100d61afc","5540e6445cf9682100d61afd","5540e64a5cf9682100d61afe","55a4ff5b2e70c0250038050f","55acb28318eefd0d0071d504","55ae1abe8576b92300291c80","55ae453ef302af23000ac109","55af586d555b900d0036d296","55af91dac8a85321007a53c3","55b9fee204775a2f00628071","55b9ff0e04775a2f00628072","55b9ff4604775a2f00628073","55b9ff5fd72d1e1900276a38","55b9ff7f04775a2f00628074","55b9ff90eb08801900f833e5","55b9ffa5d72d1e1900276a39","55b9ffca04775a2f00628075","55b9fffdd72d1e1900276a3a","56bc2f033ee9e70d008b46af","56c2f6efbbf9ec2d00e0fe4f","57595bbb18760817001e8bbe","57d8d9793916800e003dde53"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-09-24T13:44:20.924Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":26,"body":"[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Overview\"\n}\n[/block]\nAs you know it is not possible to delete a push notification on iOS after it has been received on the device. However, you might have noticed that Facebook app can do that – you receive a push notification about a new message from a friend on your device, but it’s cleared automatically if you read it on your desktop without any interaction with an iOS app. How is this possible?\n\nIn this article we’d like to shed some light on how you can achieve the same and explain the method to make push notifications deletable.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Guide\"\n}\n[/block]\nThe problem here is that iOS does not have an API method to delete push notification from the notification center. On the other hand it does provide a method to delete local notifications!\n\nHow push notification could be converted to local notification so it could be deleted later?\n\nThe key to this technique is to use a silent push notification that does not display any alert, and then to create a local notification based on the push notification payload.\n\nThe very first step is to add “Required background modes” into Info.plist file with the value “App downloads content in response to push notifications”.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/5aWjYMdQz6h0HBOkikvZ_1%20-%20PushNotificationsApp-Info_plist.png\",\n        \"1 - PushNotificationsApp-Info_plist.png\",\n        \"1700\",\n        \"68\",\n        \"#7d401f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThis allows iOS to launch your app in background when a silent push notification is received.\n\nAs we want push notification to be silent we cannot put any text in the notification’s title otherwise it would be presented by iOS itself. Therefore, we need to pass title as custom data.\n\nLet’s assume the following push notifications payload:\n- To create a notification we send: `{\"crt”:NOTIFICATION_ID, \"title”:TITLE_TEXT}`\nExample: `{\"crt”:1, \"title\":\"hello there”}`\n- To delete a notification: `{\"dlt”:NOTIFICATION_ID}`\nExample: `{\"dlt\":1}`\n\nThe code below handles these two payloads. Add this in your AppDelegate.m file:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {\\n     \\n    //get custom data from push notification\\n    NSDictionary *userdata = [[PushNotificationManager pushManager] getCustomPushDataAsNSDict:userInfo];\\n \\n    //check if this is deletable push (check user info for key \\\"dlt\\\":dict)\\n    //if this is not null - the dict is the deletable push\\n    NSString * dltPushId = [userdata objectForKey::::at:::\\\"dlt\\\"];\\n    if(dltPushId)\\n    {\\n        //if push is to delete notification \\\"dlt\\\":string\\\"\\n        //load notif and delete\\n        NSString * pushNotificationId = [NSString stringWithFormat:@\\\"com.pushwoosh.notification.%@\\\", dltPushId];\\n        NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:pushNotificationId];\\n        if(data)\\n        {\\n            UILocalNotification *notification = [NSKeyedUnarchiver unarchiveObjectWithData:data];\\n            NSLog(@\\\"Remove localnotification %@\\\", notification);\\n             \\n            //delete it\\n            [[UIApplication sharedApplication] cancelLocalNotification:notification];\\n            [[NSUserDefaults standardUserDefaults] removeObjectForKey:pushNotificationId];\\n            return;\\n        }\\n    }\\n \\n    //should we create new push notification\\n    NSString * createPushId = [userdata objectForKey:@\\\"crt\\\"];\\n    if(createPushId)\\n    {\\n        //create local notification of the push\\n        //save it\\n        UILocalNotification *note = [[UILocalNotification alloc] init];\\n \\n        //we don't need to care about sound or badge as this would be handled already by iOS itself\\n        NSString *title = [userdata objectForKey:@\\\"title\\\"];\\n        note.alertBody = title;\\n        note.userInfo = userInfo;\\n         \\n        //present notification now\\n        [[UIApplication sharedApplication] presentLocalNotificationNow:note];\\n         \\n        //serialize it and store so we can delete it later\\n        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:note];\\n        NSString * pushNotificationId = [NSString stringWithFormat:@\\\"com.pushwoosh.notification.%@\\\", createPushId];\\n        [[NSUserDefaults standardUserDefaults] setObject:data forKey:pushNotificationId];\\n    }\\n     \\n    NSLog(@\\\"Push notification fetch :%@\\\", userInfo);\\n     \\n    completionHandler(UIBackgroundFetchResultNewData);\\n}\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nAs we have converted push notification to local notification we also need to add extra handlers to our AppDelegate:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {\\n    NSLog(@\\\"Local notification :%@\\\", notification);\\n}\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nAnd another one to handle local notification on start:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\\n     \\n    NSDictionary * localNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];\\n    if(localNotification)\\n    {\\n        NSLog(@\\\"Started with local notification %@\\\", localNotification);\\n    }\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Time to Test It\"\n}\n[/block]\nMake sure you:\n- don’t put any text in the **Push message** field\n- select only iOS platform (otherwise push notification would not be created)\n- enable the Silent Push checkbox in iOS platform settings\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/pdIy8kDRTiWlj00DAK20_Silent_push.png\",\n        \"Silent_push.png\",\n        \"844\",\n        \"904\",\n        \"#229fb5\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nGo to **Action** tab, and in the **Custom Data** field add extra payload. In this example it'll be `{\"crt\":1, \"title\":\"hello there\"}`.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/8Dtau39GQYqqJV1zbsCx_Pushwoosh___Applications___Pushwoosh_Demo_App___Send_Push.png\",\n        \"Pushwoosh___Applications___Pushwoosh_Demo_App___Send_Push.png\",\n        \"853\",\n        \"303\",\n        \"#07aceb\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n**Woosh!**\nAlso, for this example we’ve sent another notification with the following custom data: `{\"crt\":2, \"title\":\"hello there again\"}`:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/8NKsDgqR0e6YBAnGE5XA_5%20-%204IMG_6585.png\",\n        \"5 - 4IMG_6585.png\",\n        \"640\",\n        \"1136\",\n        \"#195630\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Deleting the Push\"\n}\n[/block]\nNow let’s delete the first notification – we’ll have to send another push with **Custom Data** set to: `{\"dlt\":1}`:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/NAhTgZRAukljdrT5RfgD_Pushwoosh___Applications___Pushwoosh_Demo_App___Send_Push.png\",\n        \"Pushwoosh___Applications___Pushwoosh_Demo_App___Send_Push.png\",\n        \"852\",\n        \"286\",\n        \"#06adec\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n**Woosh!**\nLet's take a look at the notification center on the device – the first notification that we've sent is gone without user interaction:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/w0OXVorURBuSrRhw0biN_7%20-%206IMG_6586.png\",\n        \"7 - 6IMG_6586.png\",\n        \"640\",\n        \"1136\",\n        \"#195630\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThe drawback is that your application drains a little bit more battery as iOS needs to launch the app every time a notification is received and/or it may delay push notification delivery to your app if your device is low on battery.","excerpt":"Delete iOS push notifications remotely just like Facebook does","slug":"deletable-ios-push","type":"basic","title":"Deletable iOS Push"}

Deletable iOS Push

Delete iOS push notifications remotely just like Facebook does

[block:api-header] { "type": "basic", "title": "Overview" } [/block] As you know it is not possible to delete a push notification on iOS after it has been received on the device. However, you might have noticed that Facebook app can do that – you receive a push notification about a new message from a friend on your device, but it’s cleared automatically if you read it on your desktop without any interaction with an iOS app. How is this possible? In this article we’d like to shed some light on how you can achieve the same and explain the method to make push notifications deletable. [block:api-header] { "type": "basic", "title": "Guide" } [/block] The problem here is that iOS does not have an API method to delete push notification from the notification center. On the other hand it does provide a method to delete local notifications! How push notification could be converted to local notification so it could be deleted later? The key to this technique is to use a silent push notification that does not display any alert, and then to create a local notification based on the push notification payload. The very first step is to add “Required background modes” into Info.plist file with the value “App downloads content in response to push notifications”. [block:image] { "images": [ { "image": [ "https://files.readme.io/5aWjYMdQz6h0HBOkikvZ_1%20-%20PushNotificationsApp-Info_plist.png", "1 - PushNotificationsApp-Info_plist.png", "1700", "68", "#7d401f", "" ] } ] } [/block] This allows iOS to launch your app in background when a silent push notification is received. As we want push notification to be silent we cannot put any text in the notification’s title otherwise it would be presented by iOS itself. Therefore, we need to pass title as custom data. Let’s assume the following push notifications payload: - To create a notification we send: `{"crt”:NOTIFICATION_ID, "title”:TITLE_TEXT}` Example: `{"crt”:1, "title":"hello there”}` - To delete a notification: `{"dlt”:NOTIFICATION_ID}` Example: `{"dlt":1}` The code below handles these two payloads. Add this in your AppDelegate.m file: [block:code] { "codes": [ { "code": "- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {\n \n //get custom data from push notification\n NSDictionary *userdata = [[PushNotificationManager pushManager] getCustomPushDataAsNSDict:userInfo];\n \n //check if this is deletable push (check user info for key \"dlt\":dict)\n //if this is not null - the dict is the deletable push\n NSString * dltPushId = [userdata objectForKey:@\"dlt\"];\n if(dltPushId)\n {\n //if push is to delete notification \"dlt\":string\"\n //load notif and delete\n NSString * pushNotificationId = [NSString stringWithFormat:@\"com.pushwoosh.notification.%@\", dltPushId];\n NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:pushNotificationId];\n if(data)\n {\n UILocalNotification *notification = [NSKeyedUnarchiver unarchiveObjectWithData:data];\n NSLog(@\"Remove localnotification %@\", notification);\n \n //delete it\n [[UIApplication sharedApplication] cancelLocalNotification:notification];\n [[NSUserDefaults standardUserDefaults] removeObjectForKey:pushNotificationId];\n return;\n }\n }\n \n //should we create new push notification\n NSString * createPushId = [userdata objectForKey:@\"crt\"];\n if(createPushId)\n {\n //create local notification of the push\n //save it\n UILocalNotification *note = [[UILocalNotification alloc] init];\n \n //we don't need to care about sound or badge as this would be handled already by iOS itself\n NSString *title = [userdata objectForKey:@\"title\"];\n note.alertBody = title;\n note.userInfo = userInfo;\n \n //present notification now\n [[UIApplication sharedApplication] presentLocalNotificationNow:note];\n \n //serialize it and store so we can delete it later\n NSData *data = [NSKeyedArchiver archivedDataWithRootObject:note];\n NSString * pushNotificationId = [NSString stringWithFormat:@\"com.pushwoosh.notification.%@\", createPushId];\n [[NSUserDefaults standardUserDefaults] setObject:data forKey:pushNotificationId];\n }\n \n NSLog(@\"Push notification fetch :%@\", userInfo);\n \n completionHandler(UIBackgroundFetchResultNewData);\n}", "language": "objectivec" } ] } [/block] As we have converted push notification to local notification we also need to add extra handlers to our AppDelegate: [block:code] { "codes": [ { "code": "- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {\n NSLog(@\"Local notification :%@\", notification);\n}", "language": "objectivec" } ] } [/block] And another one to handle local notification on start: [block:code] { "codes": [ { "code": "- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n \n NSDictionary * localNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];\n if(localNotification)\n {\n NSLog(@\"Started with local notification %@\", localNotification);\n }", "language": "objectivec" } ] } [/block] [block:api-header] { "type": "basic", "title": "Time to Test It" } [/block] Make sure you: - don’t put any text in the **Push message** field - select only iOS platform (otherwise push notification would not be created) - enable the Silent Push checkbox in iOS platform settings [block:image] { "images": [ { "image": [ "https://files.readme.io/pdIy8kDRTiWlj00DAK20_Silent_push.png", "Silent_push.png", "844", "904", "#229fb5", "" ] } ] } [/block] Go to **Action** tab, and in the **Custom Data** field add extra payload. In this example it'll be `{"crt":1, "title":"hello there"}`. [block:image] { "images": [ { "image": [ "https://files.readme.io/8Dtau39GQYqqJV1zbsCx_Pushwoosh___Applications___Pushwoosh_Demo_App___Send_Push.png", "Pushwoosh___Applications___Pushwoosh_Demo_App___Send_Push.png", "853", "303", "#07aceb", "" ] } ] } [/block] **Woosh!** Also, for this example we’ve sent another notification with the following custom data: `{"crt":2, "title":"hello there again"}`: [block:image] { "images": [ { "image": [ "https://files.readme.io/8NKsDgqR0e6YBAnGE5XA_5%20-%204IMG_6585.png", "5 - 4IMG_6585.png", "640", "1136", "#195630", "" ] } ] } [/block] [block:api-header] { "type": "basic", "title": "Deleting the Push" } [/block] Now let’s delete the first notification – we’ll have to send another push with **Custom Data** set to: `{"dlt":1}`: [block:image] { "images": [ { "image": [ "https://files.readme.io/NAhTgZRAukljdrT5RfgD_Pushwoosh___Applications___Pushwoosh_Demo_App___Send_Push.png", "Pushwoosh___Applications___Pushwoosh_Demo_App___Send_Push.png", "852", "286", "#06adec", "" ] } ] } [/block] **Woosh!** Let's take a look at the notification center on the device – the first notification that we've sent is gone without user interaction: [block:image] { "images": [ { "image": [ "https://files.readme.io/w0OXVorURBuSrRhw0biN_7%20-%206IMG_6586.png", "7 - 6IMG_6586.png", "640", "1136", "#195630", "" ] } ] } [/block] The drawback is that your application drains a little bit more battery as iOS needs to launch the app every time a notification is received and/or it may delay push notification delivery to your app if your device is low on battery.