Handling push notifications when app is not running (App is Killed) - ios

My problem seems to be duplicate of this one,but it's not. While application is killed and not running in the background, if I receive push notification and clicked the notification banner, it works fine. "userInfo" isn't empty and application handles the notification. BUT if i dismiss the notification banner and open the app via clicking the application icon, this "userInfo" returns nil.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
NSDictionary* userInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(userInfo != nil){
//Handling notification
}
}
and also
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
if([application applicationState] == UIApplicationStateActive) {
NSLog(#"...1");
}else if([application applicationState] == UIApplicationStateInactive){
NSLog(#"...2");
}else if([application applicationState] == UIApplicationStateBackground){
NSLog(#"...2");
}
completionHandler(UIBackgroundFetchResultNoData);
}
Is there any way to handle these notifications or should I handle them by my own ?

No your app is only informed about the notification that is used to open/launch your app.
There is no way to detect of there are any notification in the notification center for your app. You need to build this yourself in your apps server.

Related

about "didReceiveRemoteNotification" delegate function

For system upper than iOS 10 version, within UNUserNotificationCenterDelegate, there are two methods to clarify whether the APNS message method was called from user clicked or system received the message:
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler
While for system under iOS 10 version, there was an issue for the application delegate method - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo, there are 3 ways to call this method:
1:Click a notification message when App was running in background, will call this method.
2:Click App icon wether App was running in background or was killed, before App really launched(about 1~3 seconds), during these seconds if received an APNS message, this method will be called too.
3: App was running, pull down the notification bar to make application become inactive, at this state if received an APNS message, this method will be called too.
Now here is the question, how to judge these 3 kind of clicks? Generally if user did't click message to enter app(2 and 3's click), app shouldn't execute this message(like open a new page base on the message info). But how to know it is from 2 and 3?
From below answers, found that kind-2 has been resolved with the applicationState, while kind-3 still has left no answer, anyone knows how to fix it?
Check the app state in the application didReceiveRemoteNotification
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground )
{
//app was on background
}
}
You can check that using UIApplication state as the following:
 
///- if app is running in foreground
     if (application.applicationState == UIApplicationStateActive) {
         [self pushNotificationReceivedWhileActiveWithInfo:userInfo];
///- if app was running in background
     } else if (application.applicationState == UIApplicationStateBackground) {
if (self.pushReceivedWhileClosed != YES) {
         [self pushNotificationReceivedWhileInBackgroundWithInfo:userInfo];
}
     }
Also you’ll need to handle the notification when the app was fully closed by getting it from didFinishLaunchingWithOptions when opened from a notification by saving the notification data and execute it when the user reaches the home screen let’s say:
     ///- when receiving push notification while [app closed]
     if (launchOptions != nil) {
         NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
         if (dictionary != nil) {
             NSLog(#"[AppDelegate]##########################AppDelegate######################### Received notification while app CLOSED");
             ///- save the dictionary data and execute it when the app loads for example.
             self.pushReceivedWhileClosed = YES;
         }
     }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSMutableDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo != nil)
{
comingFromNotification = YES;
}else{
comingFromNotification = NO;
}
}

didReceiveRemoteNotification is not being called in background mode until I do not tap on notification in ios

I have searched for hours but somewhere is saying that,
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandlerNotification
is called, regardless of application is in active state or inactive state. Somewhere it says when application is not active it push notification calls your didFinishLaunchingWithOptions and there you can detect notification like this :
NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]`
In my case, both are working if user tap on notification and everything is fine, but the problem occurs when user does not tap on notification and direct open app from its icon, then neither didFinishLaunchingWithOptions detect it has notification nor didReceiveRemoteNotification get called. I need to save messages in database, received from push notification, but without tapping on notification how to call method?
to get notification data in didFinishLaunchingWithOptions do this code
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if(launchOptions != nil)
{
NSDictionary *remoteNotif = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
if(remoteNotif != nil){
[UIApplication sharedApplication].applicationIconBadgeNumber = [[[remoteNotif objectForKey:#"aps"] objectForKey: #"badge"] integerValue];
//do something here to process notification
}
}
}

App doesn't receive remote notification when it is not running

My app doesn't receive push notifications when it's not running.
I am trying to handle remote notification sent as JSON and update data in my app using data from given JSON.
All is going well when app is active or in background.
But when app is not running, app is processing notifications only when I open my app by tapping on notification, but not when I open app by tapping on icon.
Here is the code from appDelegate class:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[Parse setApplicationId:appId
clientKey:clKey];
if (application.applicationState != UIApplicationStateBackground) {
BOOL preBackgroundPush = ![application respondsToSelector:#selector(backgroundRefreshStatus)];
BOOL oldPushHandlerOnly = ![self respondsToSelector:#selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)];
BOOL noPushPayload = ![launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (preBackgroundPush || oldPushHandlerOnly || noPushPayload) {
[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];
}
}
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge|
UIRemoteNotificationTypeAlert|
UIRemoteNotificationTypeSound|
UIRemoteNotificationTypeNewsstandContentAvailability];
NSDictionary *notificationPayload = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
[self processPushNotification:notificationPayload foreground:YES];
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
TFLog(#"didRegisterForRemoteNotificationsWithDeviceToken");
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:deviceToken];
[currentInstallation saveInBackground];
TFLog(#"deviceToken: %#, currentInstallation.badge: %ld", currentInstallation.deviceToken, (long)currentInstallation.badge);
TFLog(#"deviceToken: %#, deviceType: %#", currentInstallation.deviceToken, currentInstallation.deviceType);
TFLog(#"installationId: %#", currentInstallation.installationId);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
TFLog(#"didFailToRegisterForRemoteNotificationsWithError %#", error);
if (error.code == 3010) {
TFLog(#"Push notifications are not supported in the iOS Simulator.");
} else {
// show some alert or otherwise handle the failure to register.
TFLog(#"application:didFailToRegisterForRemoteNotificationsWithError: %#", error);
}
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
TFLog(#"%#", userInfo);
[PFPush handlePush:userInfo];
[self processPushNotification:userInfo foreground:YES];
[PFAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
TFLog(#"didReceiveRemoteNotification2");
[self processPushNotification:userInfo foreground:YES];
[PFAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo];
}
As result, app is receiving remote notification in all states, excepting when it is not running.
What have I missed?
You have missed the bit in the Local and Push Notification Programming Guide where it says -
If the action button is tapped (on a device running iOS), the system
launches the application and the application calls its delegate’s
application:didFinishLaunchingWithOptions: method (if implemented); it
passes in the notification payload (for remote notifications) or the
local-notification object (for local notifications).
If the application icon is tapped on a device running iOS, the
application calls the same method, but furnishes no information about
the notification
Also, this note from Apple -
Important: Delivery of notifications is a “best effort”, not
guaranteed. It is not intended to deliver data to your app, only to
notify the user that there is new data available.
If your application is launched from the app icon rather than the notification you need to check for updated content independent of any push notification that may have been received. This enables an application to behave differently when it opens from a notification and when it is opened from the app icon.
For example, the Facebook app opens directly to the item in the notification when launched from the notification alert but not when launched from the app icon - which is the "correct" behaviour from a user point of view. If I interact with the notification then I am interested in its content. If I launch the app from the icon then I just want to use the app - I can then access the notifications in the app if I want.
There's no way you can get the information about your push notification JSON payload when you launch the app by explicitly tapping the app icon.
That's as per Apple's design. When you open the application from any push notification action, then you can retrieve the push notification in application: didFinishLaunchingWithOptions: delegate method. Typically you look up for the UIApplicationLaunchOptionsRemoteNotificationKey key in your launchOptions dictionary.
But, when you open the app by explicitly tapping the application icon, though still the application: didFinishLaunchingWithOptions: delegate will be called, the UIApplicationLaunchOptionsRemoteNotificationKey key will return nil.

UINotification ios not received when app is in background

I am using notification in one of my app ,when app is active , notification is received , i process data and everything is fine , but I do not receive any notification when app is in background or killed.What is the issue can any one plz help me ?
Thank you!
Here is what I doing so far
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
tokenstring = [[NSString alloc] initWithFormat:#"%#",deviceToken];
tokenstring = [tokenstring stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
tokenstring = [[NSString alloc]initWithFormat:#"%#",[tokenstring stringByReplacingOccurrencesOfString:#" " withString:#""]];
NSLog(#"TokeinID:>> %#",tokenstring);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"didReceiveRemoteNotification: %#",userInfo);
AudioServicesPlaySystemSound(1002);
//Some code or logic
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(#"didFailToRegisterForRemoteNotificationsWithError: %#",err.description);
}
When you receive remote notifications, -application:didReceiveRemoteNotification: is only called when your app is in the foreground. If your app is in the background or terminated, then the OS may display an alert or play a sound (depending on the aps dictionary in the notification), but the delegate method is not called.
The remote notification received in the background will only passed to your application if it is launched with that notification's action button, and then you need to look at the launch options dictionary on -application:didFinishLaunchingWithOptions: to see the content of the notification.
If you're looking at new content fetching/remote notification background support with iOS7, check Will iOS launch my app into the background if it was force-quit by the user? and see if that helps, as there are very specific circumstances that those functions work in.
little code ..
When app is not running
(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
is called ..
where u need to check for push notification
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
NSLog(#"app recieved notification from remote%#",notification);
[self application:application didReceiveRemoteNotification:(NSDictionary*)notification];
}else{
}

Remote Notifications in "Not running" State

i implemented the Remote Notifications in my application! if my App is in Background and a Push Message was send to my Device, i react with this method:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
...Do Stuff
}
This is working great when App is in Foreground or in Background State! But what if my App is not running at all?! Can´t i react to Push Messages when the app is not running?I mean WhatsApp can do this, right?!
If user clicks on push notification from notification center you will have information in launchOptions with the push notification content and you can use below code to check if application was launched clicking push notification or it was there as well,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
NSLog(#"LaunchOptions->%#",launchOptions);
NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo) {
[self performNotificationAction:userInfo];
}
return YES;
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
// NSLog(#"userInfo->%#",userInfo);
[self performNotificationAction:userInfo];
}
-(void)performNotificationAction:(NSDictionary*)userInfo{
//Do the stuf whatever you want.
//i.e. fetch the message or whatever extra information sent in push notification
}

Resources