How to get the proper UINotification when selected on locked screen - ios

Here is my scenario:
The app receives some notifications, in order to be able to have actions on my locked screen they are in silent mode (content-available = 1 on aps payload).
In didReceiveRemoteNotification callback I save it to core data (background or foreground).
My problem is:
Assuming the app was already running and I have locked the screen, when I tap on some notification no callback is called. So far I'm not able to find the proper callback that handles this event.
Am I missing something?
I need to have the notification list saved and be able to go to the proper view when some notification arrives (and is tapped).
By the way receiving the notification, saving, going to the proper view ... everything works except when the screen is locked.

I suspect if your app was running when notification came because if application is in inactive state and notification is tapped then didReceiveRemoteNotification is called by iOS.
However, if for some reason, application is not running then didReceiveRemoteNotification function is not called. In such cases, if user click notification, app is launched by notification and didFinishLaunchingWithOptions gets called:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var userinfo : NSDictionary = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
print(launchOptions);
return true
}
Please check once in your didFinishLaunchingWithOptions function.

Related

iOS - Read the push notification once Received

I have 4 scenario
When the app is not Launched
Given the app was not Launched or Killed
When the push notification receive
And opened the app without tapping the notification
Then the app should capture the notification.
When the app is running in foreground
Given the app running in foreground
When the push notification receive
Then the app should capture the notification.
When the app is running in background
Given the app is running in background
When the push notification receive
And opened the app without tapping the notification
Then the app should capture the notification.
When the app is not Launched and cleared the notification
Given the app is not Launched or Killed
When the push notification receive
And user cleared the notification
And opened the app
Then the app should capture the notification.
The first 3 scenario works fine with the following code
The last scenario is not worked When the app is not Launched and cleared the notification
AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().getDeliveredNotifications(completionHandler: { requests in
for request in requests {
self.setNotification(userInfo: request.request.content.userInfo as NSDictionary)
}
})
}
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
setNotification(userInfo: userInfo as NSDictionary)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
setNotification(userInfo: userInfo as NSDictionary)
}
According to your query
When the app is not Launched and cleared the notification
Given the app is not Launched or Killed When the post notification
receive And user cleared the notification And opened the app Then the
app should capture the notification.
This is not possible for a Normal Push notification unless the user interacts with that notification. You may want to try Silent notifications, these are not shown in the UI but the control reaches the app and you can use the data/payload from there in your code.
When user clears the notification from bar, there is no way to fetch that information.
You could also try to add the same information that is being sent in the push within an API and call it once the user opens the app.
This link deals with all the detail involved. According to your implementation, you can try a combination of both.

How to handle Push on App not running state?

Is it possible to open the iOS App based on push notification content? I believe it's not possible. Is there any other way around? I believe we can go with the widget in iOS10, right? Please suggest some good solution?
Thanks!
Whenever your payload has content-available:1 your app will get called in the backgroundstate as soon as it arrives and will call application(_:didReceiveRemoteNotification:fetchCompletionHandler:). It will only not get called if the user killed the app manually. (This doesn't launch your app. It requires your app to be launched though)
Having that said if your app was terminated (by user) but the user taps on the notitication then your app is launched from didFinishLaunching...delegate method.
Whenever the user taps on push notification the application launches from not running state to running state the in AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
}
in this function you can check application is launch from push or application icon
var notification: [AnyHashable: Any]? = (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] as? [AnyHashable: Any])
if notification != nil {
print("app received notification from remote\(notification)")
application(application, didReceiveRemoteNotification: notification)
}
else {
print("app did not receive notification")
}
Yes we can not open ios applications on push notifications but we can wake up the app on push notifications. Its called VOIP notification. You can have more info regarding this from below link https://github.com/hasyapanchasara/PushKit_SilentPushNotification

iOS Handle Push notifications on application startup only when UI is ready

When the application is not running, and a notification is received, it will arrive inside:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
I have a log there and all is fine, however, let's say I want to show an alert with the body of the notification?
My alert code uses window!.rootViewController?.presentViewController(), however inside didFinishLaunchingWithOptions the UI has not loaded yet, and there is not view controller yet.
What is the best practice to trigger UI events in this scenario?
You have different options on the base of your architecture and view controllers flow. For example you can have a kind of NotificationManager, a singleton which has the responsibility to store information about any push notification received.
In your didFinishLaunchingWithOptions you can set the notification in such manager; afterwards the first view controller you present could interrogate such manager and decide whether there is any notification to consume or continue with the normal flow.
Hope it helps.

Apple Push Notification setting up Remote Notifications method overrides other methods

I have properly set up my app for Remote Notifications with the method
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)
and it processes it correctly now every time the app receives an Apple Push Notification.
But my issue is that this method is being called in all instances now.
didFinishLaunchingWithOptions does not seem to be called anymore? Or the launchOptions is coming up empty?
Basically I used the didReceiveRemoteNotification as a catch all to process any incoming notifications which is my intended purpose, but then when I click the notification itself, it fires the didReceiveRemoteNotification again. Thus processing the notification twice, which I do not want.
So this is how I want my app to handle notifications:
Anytime a notification is received, would like to automatically process the notification in the background
When user clicks notification from outside app, to run a different method than the didReceiveRemoteNotification
When user is inside app, to run a different method than the other
Apple does not allow what you want. Push notifications work in the following way
1) When the application is not running, and the user clicks a notification, the application is launched and the payload of the notification is loaded in the function didFinishLaunchingWithOptions.
2) When the application is running in background, and the user clicks a notification, the application becomes active and the function didReceiveRemoteNotification is called. Now this function contains the payload of the notification.
3) When the application is running and a push notification is called, the function didReceiveRemoteNotification is called and this function contains the payload of the notification.
4) When the app is running in background or inactive and notification is received, nothing can be done with the notifications until the user clicks the notification

How to know a push message info if app is launched from background directly rather than from notification msg?

I have properly registered for the push notification.
Implemented following method to receive notification.
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
Also used UIApplicationLaunchOptionsRemoteNotificationKey from func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool.
I'm able to receive notification when the app is active. I'm also able to see the notification if I open the app from the notification by selecting it from banner or alert.
But if app is not active, it could be alive or killed and if a notification arrives at that point. And I ignore the notification and open the app by directly selecting the app icon from the home screen, I'm not getting the notification information in the UIApplicationLaunchOptionsRemoteNotificationKey from func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool.
So what is the right way to handle this scenario? Should the app call server and get the recent messages it sent? Any help is much appreciated.
If the user will open you app directly from it's home screen, you would not get access to the push notification dictionary.
If you need the data sent in the push notification, so the proper way will be a server request as you suggested.
If user enter the app by click the icon or launch from the background, the push notification message can't deliver to you, the message is cached by system, the only way to get it is from notification center
Answering my question:
It is possible for the app in the background to receive push notification.
To do so send content-available in the aps dictionary of push notification.
Enable background mode of the app from the Background modes section of the Capabilities tab in your Xcode project.
Implement application:didReceiveRemoteNotification:fetchCompletionHandler: in the app delegate.
References:
See section 'Notification Payload' in https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html
See section 'Using Push Notifications to Initiate a Download' in
https://developer.apple.com/library/prerelease/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
However if app is killed then the appdelegate's application:didReceiveRemoteNotification:fetchCompletionHandler: is not getting called.
According to Will iOS launch my app into the background if it was force-quit by the user? post on iOS8.0 it is possible to do it using PushKit. But I have not tested it. And also if VOIP is not used then I dont know if it is possible for app to receive push notification information if it is killed.

Resources