This is my scenario:
My application is not launched yet at that time app receives push notification from APN which delegate method get called;
what I read:
1. If app is in background or foreground DidReceiveRemoteNotification get called.
2. If app is not launch yet then the notification will be received in banner if i click on it. App will launch from didFinishLaunching with notification option.
You can try silent push notification. If app is in killed state, slient push notifications will be called.
Silent push will call delegate in any state.
you need pass: 'content-available' => '1' with the payload for silent notification.
Just the limit is it supports ios7 and higher.
if i understand your question correctly then solution below
when your application is not launched yet (not runnable state) that time there is not delegate method called (there is no delegate method available.)
if you want to do something after receiving push notification at that time (not runnable state or suspended state) IOS 7 provide two method
" setMinimumBackgroundFetchInterval: "
"application:performFetchWithCompletionHandler:"
Related
I did some research on lots of stackoverflow issues and websites in trying to figure out how do the iOS push notifications influence AppDelegate lifecycle methods and when is which method (not) getting triggered. Main focus of the research was on "standard" iOS push notifications (with alert field) and silent ones (with just content-available set to 1) and on AppDelegate's application:didReceiveRemoteNotification and application:didFinishLaunchingWithOptions methods.
I don't want to ask lots of questions for different scenarios, but would rather try to write down the statements about different test cases I tried and ask you after that:
Is there any statement that is wrong and if yes, which one and why?
Scenario 1: App has been used and put to background by tapping the home button.
If standard push notification is sent, in the moment of push notification arrival, none of the methods gets triggered, app remains inactive in background. Once push notification has been tapped and app got opened because of it, application:didReceiveRemoteNotification method got called and application:didFinishLaunchingWithOptions doesn't get called. I tested this scenario right after putting the app to background and also after an app being in background for more than an hour - same behaviour. I guess that if for some reason iOS decided to kill my app while being in background, this test case becomes like Scenario 2, statement 1 from below, right?
If silent push notification is sent, in the moment of the push notification arrival, application:didReceiveRemoteNotification method got called and application:didFinishLaunchingWithOptions doesn't get called.
Scenario 2: App has been used and killed by swiping it out of the list of running apps.
If standard push notification is sent, in the moment of push notification arrival, none of the methods get triggered, app remains killed. Once push notification has been tapped and app got opened because of it, application:didReceiveRemoteNotification method got called and application:didFinishLaunchingWithOptions doesn't get called.
If silent push notification is sent, none of the methods gets triggered since silent push notifications fail to be sent to the app that got killed. After opening an app after notification is sent, application:didFinishLaunchingWithOptions gets called as part of the normal flow and without any push notification information. application:didReceiveRemoteNotification doesn't get called.
If you can maybe think of some other real life scenarios that I maybe forgot to mention, I would be really grateful to find out about them and what happens in those cases.
Cheers
Update #1
Thanks to Sandeep Bhandari for the update and additional scenarios. I forgot to mention in my original question that I was exploring scenarios in which application is arriving to the app that is currently not in the foreground for whatever reason.
Adding Sandeep's scenarios to the list:
Scenario 3: App is being used and push notification arrives.
If standard push notification is sent application:didReceiveRemoteNotification method will get called. application:didFinishLaunchingWithOptions will not get called.
If silent push notification is sent application:didReceiveRemoteNotification method will get called. application:didFinishLaunchingWithOptions will not get called.
Scenario 4: App being alive in background.
If standard push notification is sent application:didReceiveRemoteNotification method will get called. application:didFinishLaunchingWithOptions will not get called.
If silent push notification is sent application:didReceiveRemoteNotification method will get called. application:didFinishLaunchingWithOptions will not get called.
From an experience and digging alot on the iOS push notification. App
being in foreground or alive in background. both situations triggers
same delegate methods. only didReceiveRemoteNotification.
The silent push notification have a different handler: (content-available 1 means silent notification)
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
}
When app is dead. didReceiveRemoteNotification never called for regular push notification. It must be handled in didFinishLaunchingWithOptions as following:
// handle notification when app is closed.
let notification = launchOptions?[.remoteNotification]
if notification != nil {
self.application(application, didReceiveRemoteNotification: notification as! [AnyHashable : Any])
}
Additional information:
To test receiving push notification when app is killed. remove from the list that appears when double tapping home button?
The proper way to see the logging and do debugging is by editting the run scheme and selecting Wait for executable to be launched:
Run the app from the xcode. Then send push notification from server and then tap the notification from notification center.
I don't see any issue in the statement you made there, but I believe you missed to iterate over two more scenarios that I can think of.
App is in foreground and receives the push notification : didReceiveRemoteNotification gets called as soon as APNS gets delievered to iOS and you can handle it by checking application state in didRecieveRemoteNotification Method.
App being alive in background : I believe you are aware of background modes of iOS. If app is making use of expiration handler, app will be alive even if you put it to background by tapping on home button. Duration the app lives in background depends on various factors (some tutorials say app remains alive for 3 mins which I can't guarantee) Even in this case didReceiveRemoteNotification gets called as soon as APNS gets delievered to iOS. Only this time app wont be in foreground but yet its alive!!!
How can I call the method didReceiveRemoteNotification in didfinishlaunchingwithoptions? I'm using swift language.
when the user directly opens the app, the notification cancelled and the operations performed in didReceiveRemoteNotification not called. How to handle this ?
I've reached upto here. But unable to complete
if let options = launchOptions, notification = options[UIApplicationLaunchOptionsRemoteNotificationKey] as? [NSObject : AnyObject] {
self.application(application, didReceiveRemoteNotification: notification, fetchCompletionHandler: _______)
}
As per docs,
The notification is delivered when the app isn’t running in the
foreground. In this case, the system presents the notification,
displaying an alert, badging an icon, perhaps playing a sound, and
perhaps displaying one or more action buttons for the user to tap.
The user taps a custom action button in an iOS 8 notification. In this
case, iOS calls either
application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
or
application:handleActionWithIdentifier:forLocalNotification:completionHandler:.
In both methods, you get the identifier of the action so that you can
determine which button the user tapped. You also get either the remote
or local notification object, so that you can retrieve any information
you need to handle the action.
The user taps the default button in the alert or taps (or clicks) the
app icon. If the default action button is tapped (on a device running
iOS), the system launches the app and the app calls its delegate’s
application:didFinishLaunchingWithOptions: method, passing in the
notification payload (for remote notifications) or the
local-notification object (for local notifications). Although
application:didFinishLaunchingWithOptions: isn’t the best place to
handle the notification, getting the payload at this point gives you
the opportunity to start the update process before your handler method
is called.
For remote notifications, the system also calls the
application:didReceiveRemoteNotification:fetchCompletionHandler:
method of the app delegate.
If the app icon is clicked on a computer running OS X, the app calls
the delegate’s applicationDidFinishLaunching: method in which the
delegate can obtain the remote-notification payload. If the app icon
is tapped on a device running iOS, the app calls the same method, but
furnishes no information about the notification.
The notification is delivered when the app is running in the
foreground. The app calls the
application:didReceiveRemoteNotification:fetchCompletionHandler: or
application:didReceiveLocalNotification: method of the app delegate.
(If application:didReceiveRemoteNotification:fetchCompletionHandler:
isn’t implemented, the system calls
application:didReceiveRemoteNotification:.) In OS X, the system calls
application:didReceiveRemoteNotification:.
You can find the link for the same in here :
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/IPhoneOSClientImp.html#//apple_ref/doc/uid/TP40008194-CH103-SW1
Summary :
You have to handle APNS in 3 situations :
App is in Foreground/App is in background (but not suspended) : application:didReceiveRemoteNotification: method of the app delegate is called and payload is handed over to you.
2.App is suspended/killed and user taps on notification or Alert: application:didFinishLaunchingWithOptions: of app delegate gets called and you can access payload from launchOption.
3.App is suspended/killed and user taps on App Icon : You will not receive any info about APNS. Simplest solution you can do is once the app becomes active make a web service call to web server fetch all the updated info and update your UI and application badge count :)
Hope it helps :)
I'm facing a problem with push notifications, I'm using Google Cloud Messaging,
My problem is that my app works with some cached data, and I refresh that cache with the data coming from push notificacions, so when the app is killed by the user (home button + swipe-up) and the app receive a push notification it doesn't call the method didReceiveRemoteNotification, so the app can't access to the payload of that notification and update the cached data.
So, is there a way to achieve this?
Only when the user taps the notifications and the app gets it through the application:didFinishLaunchingWithOptions method?
If the user opens the app by clicking the application icon I can't get the notificaton's payload?
PD: If the app is in foreground or background (not killed) it works perfectly
If you wish your app to receive the push notification even when it is killed, add the key "content-available":"1" to the push payload.
Look here
EDIT:
After digging some more, I found out that silent push (e.g content-available:1), does not wake the app if it was killed by the user:
However, the system does not automatically launch your app if the user has force-quit it
I must say, I can't really understand why the OS does not let my app wake up when silent push arrives when it's dead. What's the point then???
This is the expected behavior. didReceiveRemoteNotification will not be called if the user killed the app, unless your app has VoIP permissions.
In case of killed application. both application:didFinishLaunchingWithOptionsandapplication:didReceiveRemoteNotification:fetchCompletionHandler:are called. In the prior one. The key of notification either remote or local is passed in options parameter. And the later one is called in only case when remote notification. The process is explained in detail in Apple Docs Here. The snapshot is pasted here as well.
Handling an Actionable Notification
If your app is not running in the foreground, to handle the default action when a user just swipes or taps on a notification, iOS launches your app in the foreground and calls the UIApplicationDelegate method application:didFinishLaunchingWithOptions: passing in the local notification or the remote notification in the options dictionary. In the remote notification case, the system also calls application:didReceiveRemoteNotification:fetchCompletionHandler:.
If your app is already in the foreground, iOS does not show the notification. Instead, to handle the default action, it calls one of the UIApplicationDelegate methods application:didReceiveLocalNotification: or application:didReceiveRemoteNotification:fetchCompletionHandler:. (If you don’t implement application:didReceiveRemoteNotification:fetchCompletionHandler:, iOS calls application:didReceiveRemoteNotification:.)
Finally, to handle the custom actions available in iOS 8 or newer , you need to implement at least one of two new methods on your app delegate, application:handleActionWithIdentifier:forRemoteNotification:completionHandler: or application:handleActionWithIdentifier:forLocalNotification:completionHandler:. In either case, you receive the action identifier, which you can use to determine what action was tapped. You also receive the notification, remote or local, which you can use to retrieve any information you need to handle that action. Finally, the system passes you the completion handler, which you must call when you finish handling the action. Listing 2-8 shows an example implementation that calls a self-defined action handler method. Reference Apple Docs
Edit:
The user taps the default button in the alert or taps (or clicks) the app icon. If the default action button is tapped (on a device running iOS), the system launches the app and the app calls its delegate’s application:didFinishLaunchingWithOptions: method, passing in the notification payload (for remote notifications) or the local-notification object (for local notifications). Although application:didFinishLaunchingWithOptions: isn’t the best place to handle the notification, getting the payload at this point gives you the opportunity to start the update process before your handler method is called.
Reference: Apple Docs
When the app is killed and the push notification triggered contains some actionable button. When we click on a Action Button of Push Notification then:
The first delegate that is executed is:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
But in here the launchOptions are nil.
The second delegate that is executed is:
-(void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(nonnull NSDictionary *)userInfo completionHandler:(nonnull void (^)())completionHandler
In this the variable userInfo contains all the payload of the Push Notification. With the help of identifier we can identify which action was invoked and then perform our respective operations.
add target of notification service extension in your project it contains two methods upper one method call in killed time and add a key "mutable_content" : true in server side of your notification payload
I have implemented the UIApplicationDelegate method -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler to handle push notifications, it works fine. In some situations, I need to retrieve the payload of the push notification. But sometimes this delegation method is not called.
I have a question about retrieving the payload (userInfo) in this scenario:
The app running either in background or not launched. The app received a push notification, a banner is shown, sound is played, and message is displayed, app icon badge increased, and the push notification can be seen in the iOS notification centers. If the user taps the notification when it's shown or in the notification center, the app launches, and the didReceiveRemoteNotification: method is called.
However, if the user just tap the app icon and launch the app in normal ways, the method is not called, and I can't retrieve the userInfo.
From Apple's documentation on handling push notifications:
The notification is delivered when the app isn’t running in the foreground. In this case, the system presents the notification, displaying an alert, badging an icon, perhaps playing a sound, and perhaps displaying one or more action buttons for the user to tap.
The user taps a custom action button in an iOS 8 notification. In this case, iOS calls either application:handleActionWithIdentifier:forRemoteNotification:completionHandler: or application:handleActionWithIdentifier:forLocalNotification:completionHandler:. In both methods, you get the identifier of the action so that you can determine which button the user tapped. You also get either the remote or local notification object, so that you can retrieve any information you need to handle the action.
The user taps the default button in the alert or taps (or clicks) the app icon. If the default action button is tapped (on a device running iOS), the system launches the app and the app calls its delegate’s application:didFinishLaunchingWithOptions: method, passing in the notification payload (for remote notifications) or the local-notification object (for local notifications). Although application:didFinishLaunchingWithOptions: isn’t the best place to handle the notification, getting the payload at this point gives you the opportunity to start the update process before your handler method is called.
If the notification is remote, the system also calls application:didReceiveRemoteNotification:fetchCompletionHandler:.
If the app icon is clicked on a computer running OS X, the app calls the delegate’s applicationDidFinishLaunching: method in which the delegate can obtain the remote-notification payload. If the app icon is tapped on a device running iOS, the app calls the same method, but furnishes no information about the notification.
The highlighted part kinda saying there is no obvious way to access the payload of the push notification in this way. So is there a way to work around this issue?
Thank you!
It is the default behavior of iOS. You will never know the payload unless user opens your app via tapping on the notification.
You can use silent push notifications if you want to send custom data (max 2048 bytes) or commands to your mobile app.
In the push notification set 'content-available' to 1 so you app gets some time to process data and also add your custom content to the notification.
I also use silent push notifications to trigger my apps to update by REST HTTP calls, since my data can be bigger than the max size... The only downside is that Apple might block your background activities if you are battery or processor intensive. Visual push notifications are always delivered.
Things I hate most are visual push notifications like 'you've got a new message' , on which I click sometimes when no data connection is available and the app will not show me the message... You can solve this by sending a silent push notification with data and only if the data could be fetched from the server, or
stored correctly in case you can send it all in the notification, you set a local notification.
Choose between visual and silent push notifications wisely is my only advise.
Check the following link for more official Apple info: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html
There's a way to capture the push notification in Ios? In order to receive a notification from an external app (for example an asp.net app) with some content and not display the push notification to the user and get the useful content?
If you also know of a way to do this in phonegap, it's useful to me as well.
Thanks!
If the app is in background or not running you can't capture the push notification.
Otherwise if the app is in foreground the method application:didReceiveRemoteNotification: of the AppDelegate will be called when the app receives a push notification and then you can do whatever you want with the information in the Push Notification.
Let’s review the possible scenarios when the system delivers a local notification or a remote notification for an application.
The notification is delivered when the application isn’t running in the foreground.
In this case, the system presents the notification, displaying an alert, badging an icon, perhaps playing a sound.
As a result of the presented notification, the user taps the action button of the alert or taps (or clicks) the application icon.
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 . If the application icon is clicked on a computer running OS X, the application calls the delegate’s applicationDidFinishLaunching: method in which the delegate can obtain the remote-notification payload.
The notification is delivered when the application is running in the foreground.
The application calls its delegate’s application:didReceiveRemoteNotification: method (for remote notifications) or application:didReceiveLocalNotification: method (for local notifications) and passes in the notification payload or the local-notification object.
Please see the documentation for more information.