I need help finishing this piece of code so the app will show badge number when a push notification is received, I can receive push notification, but just no badge on app, here is the code
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: #escaping
(UIBackgroundFetchResult) -> Void) {
if let aps = userInfo["aps"] as? NSDictionary, let _ = aps["alert"] as? String, let sound = aps["sound"] as? String
{
if let systemSound = SystemSoundID(sound) {
AudioServicesPlayAlertSound(systemSound)
}
NotificationCenter.default.post(name: Notification.Name(rawValue: SystemSetting.refreshCouponListNotification), object: nil)
completionHandler(UIBackgroundFetchResult.newData)
}
}
There is the two Methods are Called for Push notification
Foreground Method
Background Method
1.Foreground Method.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
Get content of Request of Notification
let content = notification.request.content
2.Background Method
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void)
Get content of Request of Notification
let content = response.notification.request.content
Get Badge Count
let badge = content.badge as! Int
Follow these steps to set badge count in iOS :
1.Implement logic to calculate count in backend and send that count through Push notification like :
{
"aps" : {
"alert" : "You got your Push Message.",
"badge" : 9
}
}
2.Get Badge count from Push notification response :
let pushContent = response.notification.request.content
let badgeCount = content.badge as! Int
3.set badge count in didReceiveRemoteNotification method :
UIApplication.sharedApplication().applicationIconBadgeNumber = badgeCount
Related
I'm configuring push notifications in Swift. So far I have 3 scenarios.
1 - App In Foreground
In the foreground, I think I did everything correct cus I did receive the push notification data.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("userNotificationCenter willPresent")
let content = notification.request.content
UIApplication.shared.applicationIconBadgeNumber = 0
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
completionHandler([.alert, .sound])
}
2 - User clicks on the Push Notification banner
This is also working fine.
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
print("userNotificationCenter didReceive")
defer {
completionHandler()
}
guard response.actionIdentifier == UNNotificationDefaultActionIdentifier else {
return
}
let content = response.notification.request.content
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
}
3 - App in background, then the user gets into the app
In this scenario, the push notification arrives at the user's phone. But, instead of clicking on the push notification itself, they get into the app. And I can't fetch any info from the push notification
Could anyone help on how to configure the 3rd scenario? Thank you.
you need to consider applicationState
UIApplication.State
//AppDelegate
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
switch UIApplication.shared.applicationState {
case .active:
print("Received push message from APNs on Foreground")
case .background:
print("Received push message from APNs on Background")
case .inactive:
print("Received push message from APNs back to Foreground")
}
}
When the app is background to foreground, UIApplication.State is inactive
inactive is 'The app is running in the foreground but is not receiving events.'
thus I think the best way to do the behavior you want is to write it yourself.
for example,
//AppDelegate
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
switch UIApplication.shared.applicationState {
case .active:
print("Received push message from APNs on Foreground")
case .background:
print("Received push message from APNs on Background")
case .inactive:
print("Received push message from APNs back to Foreground")
guard let nav = window?.rootViewController as? UINavigationController,
let currentVC = nav.viewControllers.last else {return}
if currentVC is 'youWantViewController' { //if you want ViewController, use notification post
let name = Notification.Name(rawValue: K.Event.pushRequest)
NotificationCenter.default.post(name: name, object: nil)
} else { //move to you want ViewController
let vc = 'yourViewController'()
root.navigationController?.pushViewController(vc, animated: true)
}
}
completionHandler(.newData)
}
I hope it will be of help.
After the rich push is handled in the background (user clicked on an UNNotificationAction without opening the app - no foreground)), then when you enter the app, there is a duplicate push event resulting in "didReceiveRemoteNotification" execution.
My question is:
Why when I handle the rich push in:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
and call competionHandler(), same push is being received in:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
?
Push setup:
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
if granted {
print("UNUserNotificationCenter auth granted")
Utils.performTaskOnMain {
application.registerForRemoteNotifications()
}
} else {
print("UNUserNotificationCenter auth error = \(error?.localizedDescription ?? "")")
}
Push handler
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
{
print("AppDelegate didReceiveRemoteNotification, with info:\(userInfo)")
handleNotificationUserInfo(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
UserNotificationsManager.shared.handleActionIdentifierForReceivedNotification(response)
completionHandler()
}
Push notification payload:
info:[AnyHashable("content-available"): 1, AnyHashable("messageInfo"): {"push_type":"XXXX","category":"videoCategory","mediaUrl":"https://XXXX.png","threadId":"24274","alertTitle":null,"initiator":"XXXXX XXXX.mp3","alertBody":null,"mutableContent":true}, AnyHashable("media-url"): https://XXXXX.png, AnyHashable("aps"): {
alert = {
body = "XXXXX";
};
badge = 56;
category = "XXX.videoCategory";
"content-available" = 1;
"mutable-content" = 1;
sound = "XXXX.mp3";
}]
The "duplicate" push that is being delivered to your app is a silent push notification. Your push notification contains the content-available key in addition to the alert dictionary.
The alert dictionary causes a user-visible notification to be delivered.
The content-available key causes it to be delivered again as a silent push notification, which is not visible to the user.
This is an unsupported configuration. Remove the content-available key and only the user visible push notification will be delivered. If you are actively using silent push send it as a separate push with only the content-available, category and your custom keys.
Now i have 1 way to do push notification.
I use firebase console( https://console.firebase.google.com/ ) and then assign bundle ID and send push notification.
now i have a question.
How to detection from firebase console on my an application(with swift).
This is my didReceiveRemoteNotification code
didReceiveRemoteNotification Code
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID1: \(messageID)")
}
var pushId = userInfo["push-id"] as? String
if(pushId == nil){
pushId = "-1"
}
fcmAccessCount(pushId: pushId!)
badgeCount()
switch application.applicationState {
case .active:
break
case .inactive:
break
case .background:
break
default:
break
}
if let aps = userInfo["aps"] as? NSDictionary {
if let alert = aps["alert"] as? String {
let alert = UIAlertController(title: "message is... ", message: alert, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
}
}
Please write this code in App Delegate class, like below and try-
class AppDelegate: UIResponder, UIApplicationDelegate{
}
#available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
//From here we will navigate to other screens:-
print("User Info : \(userInfo)")
// Change this to your preferred presentation option
//completionHandler([])
completionHandler([.alert,.sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// From here we can navigat to required screens:-
// Print full message.
print(userInfo)
completionHandler()
}
}
extension AppDelegate : FIRMessagingDelegate {
/// The callback to handle data message received via FCM for devices running iOS 10 or above.
public func applicationReceivedRemoteMessage(_ remoteMessage: FIRMessagingRemoteMessage) {
}
I am trying to show the Banner notification when the app is active.
I used given method but there is no result , Banner notification are appearing only when the app is closed :
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print("Push notification received: \(userInfo)")
if application.applicationState == .active {
print("active")
let localNotification = UILocalNotification()
localNotification.userInfo = userInfo
localNotification.alertAction = "Test"
localNotification.soundName = UILocalNotificationDefaultSoundName
localNotification.alertBody = "Notification test!!"
localNotification.fireDate = Date()
UIApplication.shared.scheduleLocalNotification(localNotification)
}
}
It prints "active" but the notification is not showing. Am i missing any step ?
Thank you.
If the application is running in the foreground, iOS won't show a notification banner/alert. You have to write some code to deal with the situation of your app receiving a notification while it is in the foreground.
Or you can use popular Third party library : github.com/bryx-inc/BRYXBanner
Use it like below
import BRYXBanner // import in your class
// Put this code where you are getting notification
let banner = Banner(title: "title", subtitle: "subtitle", image: UIImage(named: "addContact"), backgroundColor: UIColor(red:137.0/255.0, green:172.0/255.0, blue:2.0/255.0, alpha:1.000))
banner.dismissesOnTap = true
banner.show(duration: 1.0)
But if You are using iOS 10.0+ then you can approach goal for displaying banner message while app is in foreground, use the following method.
// This method will be called when app received push notifications in foreground for iOS 10+
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
To show notification in foreground. you need to write delegate methods\
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (_ options: UNNotificationPresentationOptions) -> Void) {
//Called when a notification is delivered to a foreground app.
let userInfo = notification.request.content.userInfo as? NSDictionary
print("\(userInfo)")
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
// Called to let your app know which action was selected by the user for a given notification.
let userInfo = response.notification.request.content.userInfo as? NSDictionary
print("\(userInfo)")
}
Add this code. You need to parse userInfo.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
let notification = JSON(userInfo)
print(notification)
}
I want to set badge count on app icon when notification recieved.Below method is called when notification is recieved.But the badge count does not set.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
var userData = userInfo as NSDictionary? as? [AnyHashable: Any] ?? [:]
var aps = userData["aps"] as! NSDictionary
var badge = aps["badge"]
print("data is \(badge!)")
UIApplication.shared.applicationIconBadgeNumber = badge! as! Int
if #available(iOS 10.0, *) {
let content = UNMutableNotificationContent()
content.badge = 10
} else {
// Fallback on earlier versions
}
// your badge count
}
Actually in iOS 10 these two methods are called:
If the app is in the foreground:
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
If the app is in the background:
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void)
You need to get the content of the request of the notification
foreground method
let content = notification.request.content
background method
let content = response.notification.request.content
The badge number is in the property badge of content
let badgeNumber = content.badge as! Int
I was missing the authorization for badge.I added badge in code
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound,.badge]) { (granted, error) in
// actions based on whether notifications were authorized or not
}
application.registerForRemoteNotifications()
}
I added this in didFinishLaunchWithOptions