Badge Count is not shown in iOS App - ios

The Badge count is not shown in my app for background and termination cases.
I added this code in appdelegate didfinishlaunch
UIApplication.shared.applicationIconBadgeNumber = 0
if #available(iOS 10, *)
{
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
guard error == nil else
{
return
}
if granted
{
UIApplication.shared.registerForRemoteNotifications()
}
}
}
else
{
let settings : UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .sound , .badge], categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
UIApplication.shared.registerForRemoteNotifications()
}
UIApplication.shared.applicationIconBadgeNumber += 1
print("Badge Count ===> \( UIApplication.shared.applicationIconBadgeNumber)")
The print shows correct count. But not shown in the app.
Actually I dont need to update badge count for each notification. For some share or like we need to update badge count. So I created a method and update the count.
func setBadgeCount()
{
if(self.currentAppState() == 1 || self.currentAppState() == 3)
{
sleep(2)
UIApplication.shared.applicationIconBadgeNumber += 1
print("Badge Count ===> \( UIApplication.shared.applicationIconBadgeNumber)")
}
}
callthis method from
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
{
setBadgeCount()
}

The app is not going to update the badge number with this method unless the app is actually open. If you want to update the badge number upon receiving a notification then you have to set the badge number in the payload of notification. Below is the sample of payload looks like. Put your desired number there and send it will work.
{
"aps": {
"alert": "Test Push Notification",
"sound": "yourSound.aiff",
"Badge": "desiredNumber"
}
}

You have written this code in didFinishLaunchingWithOptions which is called only once. So how would it update badge number.
Only add UIApplication.shared.applicationIconBadgeNumber = 0 in didFinishLaunchingWithOptions
Instead use,
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
application.applicationIconBadgeNumber = application.applicationIconBadgeNumber + 1;
}
For push notification use,
func application(application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
application.applicationIconBadgeNumber = application.applicationIconBadgeNumber + 1;
}
As per your updated question, you are not getting proper badge count when app is entering background or terminating , while you are getting proper log. This is because to handle these cases we need to store badge counts somewhere. You can store it in UserDefaults and then fetch it accordingly.

Just go to onesignal message settings and turn on badge count

Related

UNUserNotificationCenter didReceive / willPresent not triggered ios 11

I have a working application with notifications that appear well. Now I would like to handle some event on notification like when the user tap on the banner.
My iOS Deployment Target is 11.0 and the same for my deployment target.
I implemented everything in my AppDelegate.swift file:
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, RCTBridgeDelegate {
var window: UIWindow?
var didFinishLaunching: Bool = false
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
let bridge = RCTBridge(delegate: self, launchOptions: launchOptions)
let rootView = RCTRootView(bridge: bridge, moduleName: "root", initialProperties: nil)
rootView?.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1)
self.window = UIWindow(frame: UIScreen.main.bounds)
let rootViewController = UIViewController()
rootViewController.view = rootView
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
didFinishLaunching = true
Fabric.with([Crashlytics.self])
FirebaseApp.configure()
// This block is necessary to ask user authorization to receive notification
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.badge, .sound, .alert], completionHandler: {(grant, error) in
if error == nil {
if grant {
print("### permission granted")
application.registerForRemoteNotifications()
} else {
//User didn't grant permission
}
} else {
print("error: ",error)
}
})
} else {
// Fallback on earlier versions
let notificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(notificationSettings)
}
self.firstLaunchAction()
self.initTracker()
RNSplashScreen.showSplash("LaunchScreen", inRootView: rootViewController.view)
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
let token = tokenParts.joined()
print("### Device Token: \(token)")
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("### Failed to register for remote notifications with error: \(error)")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
if response.actionIdentifier == "like" {
print("### Handle like action identifier")
} else if response.actionIdentifier == "save" {
print("### Handle save action identifier")
} else {
print("### No custom action identifiers chosen")
}
// Make sure completionHandler method is at the bottom of this func
completionHandler()
}
As you can see, I use Firebase to send remote notification so I have a payload in json like this :
return {
notification: {
title,
body
},
data: {
title,
body,
...data
},
android: {
ttl: 3600 * 1000,
notification: {
icon: 'stock_ticker_update',
color: '#002559'
}
},
apns: {
payload: {
aps: {
alert: {
title: 'NITL ACUMEN BI RFS CODA Dev Offshore',
body: 'Send a Message - PN testing group'
},
sound: 'default'
}
}
},
condition
};
Most part of my code is copied from website. But my actual behaviour is that, when I click on the notification banner nothing happen ...
I see the nofication banner so I think there is no problem with my APNs registration. I don't know why didReceive is not trigger on click event.
Do I miss something in my implementation ? My notification payload is wrong ?
Does someone can help me to figure out where is my mistake ? I've read an infinite number of tutorials without results. Some help would be really appreciated thank you :)
To support a background update notification, make sure that the payload’s aps dictionary includes the content-available key with a value of 1.
{
"aps" : {
"content-available" : 1,
"sound" : “default"
....
},
....
}
When a background update notification is delivered to the user’s device, iOS wakes up your app in the background and gives it up to 30 seconds to run. In iOS, the system delivers background update notifications by calling the application: didReceiveRemoteNotification: fetchCompletionHandler: method of your app delegate.
Reference: Creating the Remote Notification Payload

how to setting up AppDelegate for push notification in swift

I am trying to setup a push notification system for my application. I have a server and a developer license to setup the push notification service.
I am currently running my app in Swift4 Xcode 9
here are my questions :
1_ is that possible that I set the title and body of notification massage ??
2_ what is the func of receiving massage ? I'm using didReceiveRemoteNotification but this is called when I touch the notification I need a func which is called before showing notification that I can set my massage on it
3_ I'm generating device token in appDelegate and also in my login page for my server which are different from each other. this is not correct right ?
this is my app delegate :
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
print("lunch",launchOptions?.description,launchOptions?.first)
application.registerForRemoteNotifications()
FirebaseApp.configure()
GMSPlacesClient.provideAPIKey("AIzaSyAXGsvzqyN3ArpWuycvQ5GS5weLtptWt14")
UserDefaults.standard.set(["fa_IR"], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
registerForPushNotifications()
return true
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("test : ",messaging.apnsToken)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print("Recived: \(userInfo)")
print()
// completionHandler(.newData)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print("userInfo : ",userInfo)
if application.applicationState == .active {
print("active")
//write your code here when app is in foreground
} else {
print("inactive")
//write your code here for other state
}
}
func getNotificationSettings() {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
} else {
}
}
func registerForPushNotifications() {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
(granted, error) in
print("Permission granted: \(granted)")
guard granted else { return }
self.getNotificationSettings()
}
} else {
let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
UIApplication.shared.registerForRemoteNotifications()
// self.getNotificationSettings()
}
}
Yes, you can manage the content of notification by sending an appropriate payload in the notification. Sending the payload in the following pattern would show title and body in the notification
{
"aps" : {
"alert" : {
"title" : "Game Request",
"body" : "Bob wants to play poker",
},
"badge" : 5
}
}
Display the notification is handled by the system depending upon the app state. If the app is the foreground state you will get the call in the didReceiveRemoteNotification, otherwise, the system handles the displaying part and get control in the app when the user taps on the notification.
You cannot edit the content of notification from the app side.
According to the document
APNs can issue a new device token for a variety of reasons:
User installs your app on a new device
User restores device from a backup
User reinstalls the operating system
Other system-defined events
So its recommended requesting device token at launch time.
You can send the token in login page rather than requesting a new token in the login.

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 remove iOS app icon badge when the app terminates?

I want to set the iOS app icon badge to zero (which removes the badge on the icon) when the app terminates. (...with Swift 4, iOS 10.x, 11.x)
In my ViewController I successfully requested local notification like this:
#objc func requestLocalNotification() -> Bool {
let center = UNUserNotificationCenter.current()
var result = true
center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
result = true
} else {
result = false
}
}
return result
}
And I successfully set the app icon badge with this:
#objc func notifyBadge(_ badge: Int) {
let content = UNMutableNotificationContent()
content.badge = badge as NSNumber
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
}
I can remove the badge when the app starts with this in AppDelegate.swift:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
application.applicationIconBadgeNumber = 0
return true
}
It seemed to make sense to try to do it here when the user double taps the home button:
func applicationWillTerminate(_ application: UIApplication) {
application.applicationIconBadgeNumber = 0
}
But it does not work.
I tried to use the shared application object instead of the passed application parameter:
UIApplication.shared.applicationIconBadgeNumber = 0
There are similar questions (and answers) on SO to reset the app icon badge but I only found 1 that pertains to doing it when the app is terminated by the user:
iphone how to catch if the app is terminated to update the badge icon
But that question is over 5 years old and was not actually answered with a solution. Perhaps someone has figured out a way to do it since then?

Apple Push Notifications in tvOS

Hi i am a newbie to tvOS. I have an TV application which is registered for APNS.
But while i push a notification i am not able to get the notifications.
i am getting the device token but not the notification.
While i try with the Mobile Devices i am getting the notifications,But not in the tvOS why is it so...?
How can i solve this..?
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
if granted == true
{
print("Allow")
UIApplication.shared.registerForRemoteNotifications()
}
else
{
print("Don't Allow")
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print("DEVICE TOKEN = \(deviceTokenString)")
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print(error)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print(userInfo)
}
tvOS supports only 2 types of notifications: badges and content-available. So you need to send one of these two types to APNS. Any of these types notification only changes badge number on App Icon. And only the lastest notification will be delivered to your application when you open the app. There is no visual presentation of notification as it was on iOS
How it looks see on presentation from WWDC 2016/Session 206/tvOS, start watching from 21:20
UPDATE:
On tvOS 11 appeared Silent notifications which wakes the application up and allow to refresh content in background
WWDC 2017 watch from 7:50
This is my solution for Notifications in tvOS.
in AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// set self (AppDelegate) to handle notification
UNUserNotificationCenter.current().delegate = self
// Request permission from user to send notification
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound], completionHandler: { authorized, error in
if authorized {
DispatchQueue.main.async(execute: {
application.registerForRemoteNotifications()
})
}
})
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
//print(userInfo)
print("Notification Received")
let nc = NotificationCenter.default
nc.post(name: Notification.Name("foo"), object: nil)
}
The first function provide the permission necessary for notification.
And the second function received the notification and send a notification to the current viewcontroller and make the magic happpend.
This is the viewcontroller
//viewload NotificationCenter.default.addObserver(self, selector: #selector(updateTable(_ :)), name: Notification.Name("foo"), object: nil)

Resources