Execute code when recieve push notification when app is not running - ios

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.

Related

ios check for displayed local notifications

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

How to call didReceiveRemoteNotification in didfinishlaunchingwithoptions Swift?

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 :)

Push notifications not working properly when the app is not active (killed)

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

Handle local notification in background and suspended

I want to perform some task when local notification fired(assume application is in background/suspended but not in foreground) without taping user on notification. How it possible??.
i am not able to get delegate in application:didReceiveLocalNotification: in case of application is in background/suspended and Local Notification fired.
Please any one can suggest some solution.
Thanks in advance.
The didReceiveLocalNotification method is only called when you application is running in the foreground. If you see a badge and click on the App to start it, then you need to process the local notification using application:willFinishLaunchingWithOptions: (or application:didFinishLaunchingWithOptions:) To get at your local notification in either of these two methods, use UIApplicationLaunchOptionsLocalNotificationKey as a key to the options dictionary.
If your app is in suspended state, you won't be able to know that the notification is fired.

UILocalNotification handle when opened via App icon?

I'm working with UILocalNotifications for the first time. Mostly working with repeating notifications. Most all makes sense, except one thing.
Apple Documentation states several cases for handling local notifications when they fire.
First, a case for when the user "taps the notification" when outside of the App:
If the notification is an alert and the user taps the action button
(or, if the device is locked, drags open the action slider), the
application is launched. In the
application:didFinishLaunchingWithOptions: method the application
delegate can obtain the UILocalNotification object from the passed-in
options dictionary by using the
UIApplicationLaunchOptionsLocalNotificationKey key. The delegate can
inspect the properties of the notification and, if the notification
includes custom data in its userInfo dictionary, it can access that
data and process it accordingly.
It also states a case for what happens when the user is inside the App:
If the application is foremost and visible when the system delivers
the notification, no alert is shown, no icon is badged, and no sound
is played. However, the application:didReceiveLocalNotification: is
called if the application delegate implements it. The
UILocalNotification instance is passed into this method, and the
delegate can check its properties or access any custom data from the
userInfo dictionary.
In both of those cases the developer can access the uilocalnotification and then decide what to do with it. However, in a third case - when the user, outside of the App, sees and ignores the notification and then later launches the App, no method is called that allows the application to know which notifications have previously fired?
At first I thought that this statement was describing that behavior, but now I am not sure:
On the other hand, if the local notification only badges the
application icon, and the user in response launches the application,
the application:didFinishLaunchingWithOptions: method is invoked, but
no UILocalNotification object is included in the options dictionary.
How can I handle the third case? How can I know which local notifications have fired? Do I need to iterate through my list and check all their times myself? Is there a better way to accomplish this?
You need to keep track of what is happening with your notifications. What I mean with this is that, because the notification has fired, and the user didn't launch the app because of a notification nor was your app running at the time of the notification, you need to check your sources to verify if a previously scheduled notification fired date has already passed.

Resources