assume I scheduled 3 local notifications and when users opens app, three notifications have following states:
a) not displayed yet
b) displayed
c) displayed and user taps on this notification and come back to app.
How do i detect each one?
iOS 10 has introduced the UIUserNotificationCenter, and deprecated the scheduling and delivery of local notifications via UIApplication, so there are some differences depending on which method you are using. The deprecated methods still work on iOS 10, so if you are targeting iOS earlier than iOS10 then you can continue to use these methods, but you will get deprecation warnings.
For case a, a notification that hasn't yet been delivered, details of this notification are available by calling getPendingNotificationRequests on an instance of UIUserNotificationCenter (iOS 10) or by accessing the scheduledLocalNotifications property on your app's UIApplication instance (Prior to iOS 10)
For case b, a notification that has been delivered but that the user didn't interact with, no information is available.
For case c, the notification that the user tapped to launch the app, it depends on the state of the application and how the user interacts with the notification.
If the app is not running in the foreground or suspended, then the application is launched and the notification payload is delivered to the application:didFinishLaunchingWithOptions: via the localNotification key in the options dictionary
If the app is suspended, then the notification is delivered to didReceiveLocalNotification delegate method is called.
If the notification has custom actions and the user taps one of those then the application:handleActionWithIdentifier:forLocalNotification:completionHandler: app delegate method is called
Related
I am working on a reminder app.The app will show notifications at particular times which is set by the user.I have used local notifications to show the reminder.
The problem is I want to run some codes when it receives the local notifications even if the user does not tap on the notification. Is there any way to do this in swift ?
I believe you should add method application(_ application: UIApplication, didReceive notification: UILocalNotification) inside your AppDelegate.swift. The code you want to be implemented should be there. The code will be executed even the user does not tap on the notification. But anyhow, the app should be running.
Here is an extract from apple docs:
If
the app is not active in the foreground when the notification fires,
the system uses the information in the UILocalNotification object to
determine whether it should display an alert, badge the app icon, or
play a sound. If the app is running in the foreground, the system
calls this method directly without alerting the user in any way.
You might implement this method in your delegate if you want to be
notified that a local notification occurred. For example, a calendar
app might use local notifications to alert the user to upcoming
events.
If the user chooses to open the app when a local notification occurs,
the launch options dictionary passed to the
application(:willFinishLaunchingWithOptions:) and
application(:didFinishLaunchingWithOptions:) methods contains the
localNotification key. This method is called at some point after your
delegate’s application(_:didFinishLaunchingWithOptions:) method.
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 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
I might by fighting the windmills but I need to put some clearance into my knowledge of remote notifications. I want to handle notification while my app is turned off (killed from the app switcher) but user decides to turn it on not by tapping on notification but by tapping on app icon.
As far is I know, when app is killed and a remote notification arrives user has to tap on notification to pass it in launchOptions from didFinishLaunchingWithOptions: but... I want to handle this notification when user taps on app icon and nothing is passed to lauchOptions. In that scenario, at the moment I have no notification at all...
Is it possible to handle notification in background and perform action on it no matter how the app has been launched? Maybe didReceiveRemoteNotification: fetchCompletionHandler:?
Yeah, you are fighting the windmills :)
I recommend you to read Local and Push Notifications in depth. It's a bit long but the doc is clarifying.
In a fragment of this doc you can read:
If the application icon is tapped on a device running iOS, the
application calls the same method
(application:didFinishLaunchingWithOptions:), but furnishes no
information about the notification.
And later on:
When handling remote notifications in
application:didFinishLaunchingWithOptions: or
applicationDidFinishLaunching:, the application delegate might perform
a major additional task. Just after the application launches, the
delegate should connect with its provider and fetch the waiting data.
Listing 2-5 gives a schematic illustration of this procedure.
So having said this you could have a list of sent notifications for each device in your server and each time your app launches check if the device has any pending notification.
From the Local and Push Notification Programming Guide
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
So, if your application is launched from the icon then you won't receive the notification data. You need your app to query the service/data store that is responsible for sending the notification to see if there is outstanding data/transactions/whatever.
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.