I'm trying to setup silent push notifications and I'm stuck with this problem. JSON that I send to APNs is:
{
"aps": {
"alert": "test",
"badge": 0,
"content-available": 1
}
}
Delegate method is:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
var pushData = userInfo["aps"] as? [AnyHashable : Any];
if pushData?["content-available"] as? Int == 1 {
NSLog("received silent notification")
completionHandler(.noData)
} else {
NSLog("received notification")
completionHandler(.newData)
}
}
When backend sends push notification, my app is in background. XCode shows me 'received silent notification', but this notification still pops up as normal. Could you please tell me, what I'm doing is wrong? It probably shouldn't be happening, right?
Project is set up with 'remote notifications' checked in 'background modes'.
Correct json payload for silent push notification should look like this
{
"aps" = {
"content-available" : 1,
"sound" : ""
};
// add custom key-value pairs
}
Related
We are using APNS to send push notifications to out devices. The payload looks like the following:
{
"data":{
"aps":{
"alert":{
"loc-args":["bharathp"],
"loc-key":"LiKudoAlertBody",
"title-loc-key":"LiKudoAlertTitle"
}
},
"fromName":"bharathp",
"source":"community",
"type":"kudos",
"message":"{....some dictionary....}",
"fromId":"1696757163"
},
"to":"some string"
}
But on iOS when I receive the notification I only get the "aps" part of the payload.
[AnyHashable("aps"): {
alert = {
"loc-args" = (
bharathp
);
"loc-key" = LiKudoAlertBody;
"title-loc-key" = LiKudoAlertTitle;
};
}]
I'm printing the above using
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
// Print notification payload data
print("Push notification received: \(data)")
}
Is the format I'm sending incorrect? What could possibly be the issue here?
Maybe it's because you are using a deprecated delegate method. You could try to use the new delegate methods.
#available(iOS, introduced: 3.0, deprecated: 10.0, message: "Use UserNotifications Framework's -[UNUserNotificationCenterDelegate willPresentNotification:withCompletionHandler:] or -[UNUserNotificationCenterDelegate didReceiveNotificationResponse:withCompletionHandler:] for user visible notifications and -[UIApplicationDelegate application:didReceiveRemoteNotification:fetchCompletionHandler:] for silent remote notifications")
optional public func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any])
I have implemented FCM notification to send notification.
When I send a notification from the firebase console then I get the notification. But when I send the notification from the server, I get success but the notification doesn't appear..
Secondly, how do I get the notification response data?
My didReceiveRemoteNotification function is also not working. Here is my code:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
print("Recived: \(userInfo)")
print("success")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("Recived: \(userInfo)")
print("success")
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print("Recived: \(userInfo)")
print("success")
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
self.application(application, didReceiveRemoteNotification: userInfo) { (UIBackgroundFetchResult) in
print("Recived: \(userInfo)")
print("success")
}
print("Recived: \(userInfo)")
print("success")
let state: UIApplicationState = application.applicationState
// user tapped notification while app was in background
if state == .inactive || state == .background {
print("Inactive")
}
else {
print("Active")
}
}
I found that the message below works best for me both with Android and iOS (I use a firebase function to send it but that shouldn't matter). Note that for this to work you need to use the send method and not one of the deprecated ones, so something like: admin.messaging().send(message)
Message to feed to the send:
const message = {
token: addresseePushToken,
/*
Apple Push Notification Service
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns
*/
apns: {
headers: {
'apns-priority': 10, // defaults to 10 (send immediately), can be set to 5 (consider device power)
'apns-collapse-id': chatId // group multiple notifications into a single notification (must not exceed 64 bytes)
},
payload: {
aps: {
alert: {
title: title,
body: doc.message,
},
badge: unseenCount+1,
}
}
},
/*
Android specifics
https://firebase.google.com/docs/cloud-messaging/admin/send-messages#android_specific_fields
*/
android: {
priority: 'high', // either 'normal' or 'high' - high send immediately & waking sleeping device
notification: { // notification object creates status bar notification if app in background
tag: chatId, // key for grouping notifications (Android only)
title: title,
body: doc.message,
color: '#ffffff', // notification's icon color
icon: thumbUrl, // if not specified FCM displays the launcher icon as defined in app manifest
}
},
// data object is available to the app both when received in foreground and background
data: {
type: 'chat',
senderId: senderId,
title: title,
body: doc.message,
},
}
I solved an issue very similar to this adding this to the Firebase notification:
"apns" : {
"payload" : {
"aps" : {
"content-available" : 1
}
}
}
I need some help in getting the inner push data.
in my app delegate file i have the following:
// Push notification received
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
// Print notification payload data
print("Push notification received: \(data)")
}
which results in the following:
Push notification received: [AnyHashable("aps"): {
Link = "http://www.website.com.dll?i.user8=App&id=374941&mobileOnly=true";
alert = "New survey";
}]
How would i go about in getting the value go LINK from data
thanks
You can get push data as like below.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
let dictPayload = userInfo as NSDictionary
if let data = dictPayload.value(forKey: "aps") as? NSDictionary {
let link = data.value(forKey: "Link") as? String
print(link)
}
print("Push notification received: \(data)")
}
We are using kinvey business logic to push notification on postSave:
Here is what it look like if sent from engagements:
{
"aps": {
"alert": "Hello World",
"sound": "default"
},
}
The aps structure is passed as a nested object on the userInfo object that is available in the didReceiveRemoteNotification appDelegate method. You can use it with something like this in Swift:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
if let notification = userInfo["aps"] as? NSDictionary,
let alert = notification["alert"] as? String {
// do something with 'alert'
(code snippet from http://www.intertech.com/Blog/push-notifications-tutorial-for-ios-9/)
For some reason my didReceiveRemoteNotification is never called. I have done the following:
checklist of APNS:
Create AppId allowed with Push Notification
Create SSL certificate with valid certificate and app id
Create Provisioning profile with same certificate and make sure to add device
With Code:
Register app for push notification
Handle didRegisterForRemoteNotificationsWithDeviceToken method
Set targets> Capability> background modes> Remote Notification
Handle didReceiveRemoteNotification
Yet my function does not seem to get called. My code looks like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if (application.respondsToSelector("isRegisteredForRemoteNotifications"))
{
// iOS 8 Notifications
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: (.Badge | .Sound | .Alert), categories: nil));
application.registerForRemoteNotifications()
}
else
{
// iOS < 8 Notifications
application.registerForRemoteNotificationTypes(.Badge | .Sound | .Alert)
}
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var tokenString = ""
for var i = 0; i < deviceToken.length; i++ {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
apnsID = tokenString
println("******apnsID is \(apnsID)")
dToken = deviceToken
println("******dToken is \(dToken)")
NSUserDefaults.standardUserDefaults().setObject(deviceToken, forKey: "deviceToken")
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println("***********didFailToRegisterForRemoteNotificationsWithError")
println(error)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
println("Getting notification")
var message: NSString = ""
var alert: AnyObject? = userInfo["aps"]
println(userInfo["aps"])
if((alert) != nil){
var alert = UIAlertView()
alert.title = "Title"
alert.message = "Message"
alert.addButtonWithTitle("OK")
alert.show()
}
}
add content_available:true in your request . for iOS payload data.You will get notification in didReceiveRemoteNotification. Now handle it.
As I found out having the same problem myself, in order for didReceiveRemoteNotificationto be called, the incoming notification music carry an "available_content" : true parameter with the notification payload. So in case of you sending the notification in a dictionary form , as was my case in device to device pushes, you just have to add it in the dictionary as you would specify other parameters as you would for sound or badge, also needed if you're using some sort of push service as Postman
Three steps:
Add logic here to handle incoming notification:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// Add your logic here
completionHandler(.newData)
}
Add Background mode to capabilities in target, and ensure to check 'Remote notifications'
While sending a push notification, add "content_available" : true
This worked for me in iOS 14/Xcode 12.3.