Custom payload in APNS not delivered - ios

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

Related

Show fcm notification if meet a condition with swift

I am using firebase push notification, where my app is subscribed to a topic, all is good. But I want to know if it is possible to show the notification if pass a notification. this is my scene:
local_user_id = 10
var payload = {
notification: {
title: "hi",
body: "this is a notification",
sound: "default"
},
data: {
user_id: "1",
message: "you should pay $3020.25"
}
};
1) control if user is_login (true/false)
2)get the message data of notification and check:
if (payload.data.user_id = local_user_id && is_login){
show_notification()
}
3) show notification
Actually I only have the notification and no more, I am new with firebase, this is my code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
(granted, error) in
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
let dict = userInfo["aps"] as! NSDictionary
let message = dict["alert"]
print("response")
print(message)
}
I don't know how to do that what I want, is it posible?
thanks in advance
You can not control show hide notification in your application. You can put some logic on the backend side, whether this notification should be displayed or not. Nevertheless, I have workaround below possible way.
Use a silent push. Then trigger local notifications. Note: Silent
push isn't always reliable.
So just include content-available: 1 in your payload as shown
below to get a silent notification.it will act as silent notification.
Also in Info.plist should have UIBackgroundModes set to
remote-notification
but it'll be limited to Running and background mode only. you won't be able to receive or handle it if content-available is set to 0 while your app is offline
If you are trying to just present the notification to the user while the app is running in the foreground, you would need to have your AppDelegate conform to the UNUserNotificationCenterDelegate. This is because when the application is running, the notifications will be presented to the UNUserNotificationCenter shared object.
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void {
let content = notification.request.content
if content.data["user_id"] == local_user_id && is_login {
completionHandler(.alert)
} else {
completionHandler([])
}
}
}
You would want to make sure that the completionHandler is executed at some point in this block, because this is the handler that does the presentation of the notification. If you want a silent notification, you can use completionHandler([]) to silence the alert. Other possible options for the completionHandler are available here.

How to get notification response data using Firebase?

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
}
}
}

Silent push notifications still pop up as normal

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
}

Receiving Push Notifications on Swift with AWS Mobile Hub

I am currently developing and iOS app using Swift, which I am new to, and the code generated from AWS Mobile Hub, with AWS SNS to register devices and send notifications.
On my class AWSMobileClient I have the following code:
func didFinishLaunching(_ application: UIApplication, withOptions launchOptions: [AnyHashable: Any]?) -> Bool {
print("didFinishLaunching:")
// Register the sign in provider instances with their unique identifier
AWSSignInProviderFactory.sharedInstance().register(signInProvider: AWSFacebookSignInProvider.sharedInstance(), forKey: AWSFacebookSignInProviderKey)
var didFinishLaunching: Bool = AWSIdentityManager.default().interceptApplication(application, didFinishLaunchingWithOptions: launchOptions)
didFinishLaunching = didFinishLaunching && AWSPushManager(forKey: ServiceKey).interceptApplication(application, didFinishLaunchingWithOptions: launchOptions)
if (!isInitialized) {
AWSIdentityManager.default().resumeSession(completionHandler: { (result: Any?, error: Error?) in
print("Result: \(result) \n Error:\(error)")
}) // If you get an EXC_BAD_ACCESS here in iOS Simulator, then do Simulator -> "Reset Content and Settings..."
// This will clear bad auth tokens stored by other apps with the same bundle ID.
isInitialized = true
}
return didFinishLaunching
}
Which is called normally.
On my AppDelegate, I have the following:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
AWSMobileClient.sharedInstance.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
NotificationCenter.default.post(name: Notification.Name(rawValue: AWSMobileClient.remoteNotificationKey), object: deviceToken)
print("###--- DID REGISTER FOR REMOTE NOTIFICATION ---###")
}
Which is also called.
However, when I try sending a notification using AWS SNS, my function:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("###--- DID RECEIVE REMOTE NOTIFICATION ---###")
AWSMobileClient.sharedInstance.application(application, didReceiveRemoteNotification: userInfo , fetchCompletionHandler: completionHandler)
// This is where you intercept push notifications.
if (application.applicationState == .active) {
UIAlertView.init(title: "Notification Received", message: userInfo.description, delegate: nil, cancelButtonTitle: "OK").show()
}
}
Is never called.
Looking for a solution I read that since iOS 10 there are some chances that need to be made to deal with push notification, but I'm not sure about the correct ways.
How should I implement the code to receive the notifications?

didReceiveRemoteNotification not called Swift

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.

Resources