Handling push notifications payload data - ios

I am searching the way about how to handle push notification payload data as soon as the notification reaches to the client app without opening or tapping it.And I am still not getting the data unless the user tap or open it from notification center or banner or alert.The function didReceiveRemoteNotification only triggered when the user click the notification on the screen.So,how to get the notification payload data when the notification arrive to client app even the user ignore(without open or tap) it.
INFO : I heard that GCM(Google Cloud Messaging) can make notification handler if the client app user tapped the notification or not.It can catch the notification payload json data as soon as it reach the client app without even need user to tap or open it.Is that right?
I really need a hand to pick me up with getting notification payload data on ios without even need a user to open or tap it.
Update : The app is still running on device which mean it was active.I can get the payload data when i click my notification which was "{aps:} json i get it.But,I still cant get the data when i don't open the notification"
Here is my state
When the app was at foreground,I get the data.
1.I run the App,
2.Send Notification,
3.Get the notification with an alert,
4.I get the data(payload).
Work fine when app is active.
But,when the app reach to background
1.Run The app,
2.Close The App by pressing home button,
3.Send Notification,
4.Get the notification.
5.But,cant get the data until i click notification that I was receive at banner
or notification center.
But,when i click the notification at banner or notification it went to app and then i get the data.
Is there anyway that i can get the data if the app in background when the notification received.
Here is the code :
import UIKit
import RealmSwift
let realm = try! Realm()
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var data : [NSObject : AnyObject]!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//one singnal is the push notification service that i use for push notification.
let oneSignal = OneSignal(launchOptions: launchOptions, appId: "__app_id__") { (message, additionalData, isActive) in
NSLog("OneSignal Notification opened:\nMessage: %#", message)
if additionalData != nil {
NSLog("additionalData: %#", additionalData)
}
}
oneSignal.enableInAppAlertNotification(true)
return true
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print("User Info : \(userInfo)")
if let custom = userInfo["custom"] as? NSDictionary{
if let a = custom["a"] as? NSDictionary{
print("A : \(a)")
}
}
}

I came across the same problem. As mentioned in the previous comments, this post is quite helpful.
According to Apple,
When a remote notification arrives, the system displays the
notification to the user and launches the app in the background (if
needed) so that it can call this method. Launching your app in the
background gives you time to process the notification and download any
data associated with it, minimizing the amount of time that elapses
between the arrival of the notification and displaying that data to
the user.
The first thing you have to do is to allow your app to do something when in background. You do this by adding Required background mode in your info.plist, then add it App downloads content in response to push notifications. Your info.plist should look something like this:
Now this is done, your app should awake when it receive a notification. You can execute a small code inside didReceiveRemoteNotification. Such as this.
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
//do some code here
UIBackgroundFetchResult.NewData
}
Note that you have to pay attention to the completionHandler:
As soon as you finish processing the notification, you must call the
block in the handler parameter or your app will be terminated. Your
app has up to 30 seconds of wall-clock time to process the
notification and call the specified completion handler block.
Let me know if everything is clear :)

Related

How to delete specific remote notification if app is closed or in background

My app has a chat service, when new notification is received, I want to clear the notifications between user1 and user2 except the new one.
I can do it when app is in foreground by calling:
UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
print("count: \(notifications.count)")
for notif in notifications {
let nUserInfo = notif.request.content.userInfo
let nType = Int(nUserInfo[AnyHashable("type")] as! String)
if nType == type {
let notifId = notif.request.identifier
if notifId != notification.request.identifier {
center.removeDeliveredNotifications(withIdentifiers: [notif.request.identifier])
}
}
}
where type is a customValue.
How to do this when app is in background or closed by a user.
You need to turn on Background Modes capability and check Remote notifications mode. In order to delete the notification in background, you need to send a new notification with no alert, like {"aps": {"content-available": 1}, "del-id": "1234"}, where content-available means (you can check more about here Apple push service)
Include this key with a value of 1 to configure a background update notification. When this key is present, the system wakes up your app in the background and delivers the notification to its app delegate. For information about configuring and handling background update notifications, see Configuring a Background Update Notification.
and del-id will be the id of the notification you want to delete, you can use an array as well. You can put these information with together with your message notification as well.
In your AppDelegate.swift you will need to add this method to delete the notification in background. In your case, you can send the id of the notification you does not want to delete and use your method to delete all delivered notification except the one with the id you send in your last notification.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
guard let idToDelete = userInfo["del-id"] as? String else {
completionHandler(.noData)
return
}
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [idToDelete])
completionHandler(.noData)
}

iOS Swift Twilio Programmable Chat Push Notifications

Using the TwilioChatClient pod, I have successfully registered my app to Twilio Programmable Chat to receive APN notifications.
However, from what I can tell, these notifications are being created after calling client.register(withToken: deviceToken) on an instantiated TwilioChatClient client, and NOT through the application's AppDelegate didReceiveRemoteNotification method. Stranger yet, didReceiveRemoteNotification is called, but only when the application is in the active state, and not the background state, where I would like to perform some operations.
Does anyone know where and how these notifications are being created, or why didReceiveRemoteNotification is only called during the active state? Amongst other things, I would like to increment the application icon badge number with each notification sent out by the client.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("Registered for notifications");
if UserUtils.client?.userInfo != nil {
print("Has info");
UserUtils.deviceToken = deviceToken;
UserUtils.client?.register(withToken: deviceToken)
} else {
print("No info");
updatedPushToken = deviceToken as NSData?
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("Received a notification");
if UIApplication.shared.applicationState != .active {
print(userInfo);
UserUtils.client?.handleNotification(userInfo);
UIApplication.shared.applicationIconBadgeNumber += 1;
if UserUtils.client?.userInfo != nil {
print(userInfo);
let jsonNotification = JSON(userInfo["aps"])
let alert = jsonNotification["alert"].stringValue + "\"}";
print(JSON.init(parseJSON: alert)["body"]);
} else {
print(userInfo);
let jsonNotification = JSON(userInfo["aps"])
let alert = jsonNotification["alert"].stringValue + "\"}";
print(JSON.init(parseJSON: alert)["body"]);
}
} else {
}
}
where the client.register(withToken: deviceToken) works as intended.
Twilio developer evangelist here.
I've spoken with the Programmable Chat team and this is what I've found out:
application(_:didReceiveRemoteNotification:fetchCompletionHandler:) is for silent notifications in the background that perform background processing only (that is, with "content-available": 1 set in the APNS notification). Programmable Chat sends notifications that show information to the user, so it won't be fired in background mode
Notifications can update the badge count for you though, so this is processing you don't have to do, this requires a different setting in the notification that we currently do not support, however work is being done to add that support now
If you want to both show a notification and do further background processing, this is not supported in regular notifications, however this is supported with iOS 10's service extensions. Programmable Chat doesn't support those either, but again, it is being worked on, so you may see that soon
Keep an eye on the Programmable Chat Changelog for these additions.
Let me know if that helps at all.

Firebase messaging iOS : usersInfo is empty or I never get the notification

I follow the rules from the Google Firebase for configuring my iOS app. When I give to the Firebase Console a Device ID (token) which has never been used, the notification is caught by my app, but the userInfo is empty:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// Print message ID.
print("Message ID: \(userInfo["gcm.message_id"]!)") /* HERE */
// Print full message.
print("%#", userInfo)
}
On the line with the /* HERE */ comment, the app crashes because userInfo is nil.
When I try again another notification from the Firebase console, the notification is not caught and nothing appends (I have a breakpoint in the reception notification function).
What's wrong ?
Make sure you are using the Firebase token that is generated and not the device token that made this mistake. You will need to put this in your code to get the token you need:
print(FIRInstanceID.instanceID().token())
I put this inside of my code:
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {}

How to get notification additionaldata(payloadData) that was at AppDelegate' didFinishLunchingWithOptions if the user didn't open the notification

I am currently using OneSignal for notification service to my app.I really need a help with accessing notification additionaldata(payload data) from AppDelegate inside didFinishLunchingWithOption where OneSignal API can give me like this.
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var data : [NSObject : AnyObject]!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let oneSignal = OneSignal(launchOptions: launchOptions, appId: "48755d3d-abc0-4bac-8f71-095729bb3a65") { (message, additionalData, isActive) in
NSLog("OneSignal Notification opened:\nMessage: %#", message)
if additionalData != nil {
NSLog("additionalData: %#", additionalData)
self.data = additionalData
print(self.data)
}
}
oneSignal.enableInAppAlertNotification(true)
return true
}
}
but,I can only get the data if user click notification when appear or open it from notification center.So,if user neglect that notification without tapping when appear or without swiping or tapping from notification center,how do i get the additional data?
Actually,I want to store all payload data every time it comes into my device at realm database and fetch the data from my server according to that payload data.
You should use application(_:didReceiveRemoteNotification:fetchCompletionHandler:).
If you have enabled remote notifications background mode most of your notifications will be delivered even if the app is not running in the foreground. The only caveat being that the app must have been launched (since notifications are being pushed the user has done this) and it mustn't have been force-quit by the user.
More info in Apple's docs about that specific method.
Or in the "Local and Remote Notification Programming Guide's" notification handling chapter
You can extract all the payload in did finishLaunching by following method..
Let data = launchOptions.objectForKey(UIApplicationLaunchOptionsUIApplicationLaunchOptionsRemoteNotificationUIApplicationLaunchOptionsUIApplicationLaunchOptionsRemoteNotificationKey)

Swift: didReceiveRemoteNotification to be called with no user activity involved (Using Houston ruby gem)

I have a small swift app written. I have successfully configured the remote notification services. Here is the code
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
println("received notification")
var remoteServer = RemoteServer()
remoteServer.sendDataToServer { (success) -> () in
completionHandler(UIBackgroundFetchResult.NewData)
}
}
Now, I am using Houston ruby gem to send the notifications. which looks something like this
require 'houston'
APN = Houston::Client.production
APN.certificate = File.read("production_certificate.pem")
token = "token here"
notification = Houston::Notification.new(device: token)
notification.content_available = true
notification.alert = "test"
notification.badge = 0
APN.push(notification)
I can successfully see the message on the lock screen. But its when I swipe the notification , which opens the app, thats when the didReceiveRemoteNotification method gets called.
I am wondering if there is a way to fire off didReceiveRemoteNotification without the user having to swipe the notification ? (Pretty much no user activity required) ?
I tried setting the alert to nil. But then since no user activity can be detected didReceiveRemoteNotification never gets fired off.
How should I handle this scenario? Should I be using performFetchWithCompletionHandler , but then how to fire it from the remote server?
UPDATE: the didReceiveRemoteNotification does get sent out when the app is currently opened, but as soon as the device is locked. The same isn't getting called.
Thanks

Resources