Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse - ios

Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: but the completion handler was never called.
On tapping notifications im getting this warning in IOS.
My delegate file
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// This method will be called when app received push notifications in foreground
override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
if #available(iOS 14.0, *) {
completionHandler([.banner, .badge, .sound])
}else{
completionHandler([.alert, .badge, .sound])
}
}
Kindly help..

Related

Disable banner in push notifications in Swift

For Notification Service im using OneSignal SDK. Is it possible to change notification settings from code?
I would like to allow only notification center, badges, sound.
But when i try to set it by
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UNUserNotificationCenter.current().requestAuthorization(options: [.sound, .badge]) { (success, error) in
print(self,#function,success)
}
UNUserNotificationCenter.current().delegate = self
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.sound,.badge])
}
}
The notification came up and showing with Banners and on Lock screen.
I set it manually and it works really cool.
https://i.stack.imgur.com/wQwmM.png
Will be great to set it up from code.

willPresent and didReceive Notification delegate not get called when user in foreground and app is installed fresh

I have implemented FirebaseCloudMessaging, getting notifications when the app is in Background but when I install the fresh app willPresent and didReceive Notification delegate not get called after 30 to 35 minute it will start calling.
It happens only when I install the app by removing the old one.
Here is my code, you can check where I did mistake
import UIKit
import Firebase
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Register for push notification
self.registerForNotification()
FirebaseApp.configure()
Messaging.messaging().delegate = self
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
//MARK: - Register For RemoteNotification
func registerForNotification() {
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { granted, error in }
UIApplication.shared.registerForRemoteNotifications()
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
#if DEVELOPMENT
Messaging.messaging().setAPNSToken(deviceToken, type: .sandbox)
#else
Messaging.messaging().setAPNSToken(deviceToken, type: .prod)
#endif
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
debugPrint("Unable to register for remote notifications: \(error.localizedDescription)")
}
//MARK: - UNUserNotificationCenterDelegate
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
debugPrint(userInfo)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
debugPrint(userInfo)
completionHandler([.badge, .alert, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
print(userInfo)
completionHandler()
}
}
extension AppDelegate: MessagingDelegate {
//MARK: - MessagingDelegate
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print(fcmToken)
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print(remoteMessage.appData)
}
}
Thanks for help
Replace registerForNotification function code with this one. May be it will help
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { (isAllow, error) in
if isAllow {
Messaging.messaging().delegate = self
}
}
UIApplication.shared.registerForRemoteNotifications()
When user allow the notification then this delegate method will be called
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print(fcmToken)
}
when notification is tapped
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
//when notification is tapped
}
This method will be called when app is in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
//this method is called when notification is about to appear in foreground
completionHandler([.alert, .badge, .sound]) // Display notification as
}

Why userNotificationCenter didReceive is not fired?

This is a part of my code. I want to use UNUserNotificationCenter and UNUserNotificationCenterDelegate to handle notification events.
This code catches the notification event when the app is in a foreground state. But "didReceive" is not fired for a background state.
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UNUserNotificationCenter.current().delegate = self
application.registerForRemoteNotifications()
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
print("willPresent") /// This works
completionHandler([.alert, .badge, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
print("didReceive") /// This doesn't work
completionHandler()
}
But if I don't use UNUserNotificationCenter.current().delegate = self the delegate method is correctly fired in the background.
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping FetchCompletionHandler) {
print("didReceiveRemoteNotification... \(userInfo)")
}
How can I use "didReceive"? I want to handle the notification in the background.
application(_:didReceiveRemoteNotification:fetchCompletionHandler:) is called when the application receives a silent push notification. Silent push notifications can be delivered in when the application is in the background state, iOS wakes the application to perform background processing invisible to the user.
A silent push notification has the content-available flag set to 1.
Silent push notifications should not include an alert, badge, or sound. Silent push is not meant to be visible to the user, it is only a hint to the application that new remote content is available.
Removing the content-available flag from your push notification payload will cause iOS to handle it as a regular notification. The user notification center delegate methods will be called instead of application(_:didReceiveRemoteNotification:fetchCompletionHandler:) but your application will be unable to do background processing triggered by the notification.
You can validate the content of your push notification payload for problems like this using this tool
This is how I handle push notification in my app. I think you need to implement all of these methods to handle all iOS versions in the foreground and background mode.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound,.alert,.badge], completionHandler: { (granted, error) in
if error == nil {
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
})
}
else {
let notificationTypes: UIUserNotificationType = [UIUserNotificationType.alert, UIUserNotificationType.badge, UIUserNotificationType.sound]
let pushNotificationSettings = UIUserNotificationSettings(types: notificationTypes, categories: nil)
application.registerUserNotificationSettings(pushNotificationSettings)
application.registerForRemoteNotifications()
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print(deviceTokenString)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to get token; error: \(error)")
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert,.sound])
//do sth
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
//do sth
}
// for iOS < 10
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
}
There are methods of UNUserNotificationCenterDelegate:
willPresent: This method gets called when you receive a notification when your app is in the foreground. If the app is in the background then this method will not calls.
didRecieve: This method gets called when a user clicked on the notification.
In case of background state, only 'didRecieve' will be called when user will click on a notification.

unable to receive the push notification in foreground using FCM

I have been trying to get firebase push-notification in my app. I have tried everything on the internet but couldn't find solution. I have been receiving notification in background, but when App is in foreground I am unable to get the notification. But when I print the userInfo in "didReceiveRemoteNotification" I get the message in console
Any help would be appreciated.
import Firebase
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate{
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//FirebaseApp.configure()
self.initializeFCM(application)
let token = InstanceID.instanceID().token()
debugPrint("GCM TOKEN = \(String(describing: token))")
return true
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error)
{
debugPrint("didFailToRegisterForRemoteNotificationsWithError: \(error)")
}
func application(received remoteMessage: MessagingRemoteMessage)
{
debugPrint("remoteMessage:\(remoteMessage.appData)")
}
func initializeFCM(_ application: UIApplication)
{
print("initializeFCM")
if #available(iOS 10.0, *) // enable new way for notifications on iOS 10
{
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.badge, .alert , .sound]) { (accepted, error) in
if !accepted
{
print("Notification access denied.")
}
else
{
print("Notification access accepted.")
UIApplication.shared.registerForRemoteNotifications();
}
}
}
else
{
let type: UIUserNotificationType = [UIUserNotificationType.badge, UIUserNotificationType.alert, UIUserNotificationType.sound];
let setting = UIUserNotificationSettings(types: type, categories: nil);
UIApplication.shared.registerUserNotificationSettings(setting);
UIApplication.shared.registerForRemoteNotifications();
}
FirebaseApp.configure()
Messaging.messaging().delegate = self
Messaging.messaging().shouldEstablishDirectChannel = true
}
// enable new way for notifications on iOS 10
func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings)
{
debugPrint("didRegister notificationSettings")
if (notificationSettings.types == .alert || notificationSettings.types == .badge || notificationSettings.types == .sound)
{
application.registerForRemoteNotifications()
}
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)
{
debugPrint("didRegisterForRemoteNotificationsWithDeviceToken: NSDATA")
let token = String(format: "%#", deviceToken as CVarArg)
debugPrint("*** deviceToken: \(token)")
Messaging.messaging().apnsToken = deviceToken as Data
debugPrint("Firebase Token:",InstanceID.instanceID().token() as Any)
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
{
debugPrint("didRegisterForRemoteNotificationsWithDeviceToken: DATA")
let token = String(format: "%#", deviceToken as CVarArg)
debugPrint("*** deviceToken: \(token)")
Messaging.messaging().apnsToken = deviceToken
debugPrint("Firebase Token:",InstanceID.instanceID().token() as Any)
}
//-------------------------------------------------------------------------//
// [START receive_message]
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
Messaging.messaging().appDidReceiveMessage(userInfo)
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
Messaging.messaging().appDidReceiveMessage(userInfo)
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
// [END receive_message]
}
// [START ios_10_message_handling]
#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
// With swizzling disabled you must let Messaging know about the message, for Analytics
Messaging.messaging().appDidReceiveMessage(userInfo)
print(userInfo)
// Change this to your preferred presentation option
completionHandler([])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
Messaging.messaging().appDidReceiveMessage(userInfo)
print(userInfo)
completionHandler()
}
}
// [END ios_10_message_handling]
extension AppDelegate : MessagingDelegate {
// [START refresh_token]
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Received data message: \(remoteMessage.appData)")
}
// [END ios_10_data_message]
}
Since iOS 14, .alert is deprecated, you might use .banner instead:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let content = notification.request.content
// Process notification content
print("\(content.userInfo)")
completionHandler([.banner, .list, .sound]) // Display notification Banner
}
From iOS 10, You can display Apple's default notification banner using below function.
Notification behaviour will depend on properties which you return within completionHandler.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let content = notification.request.content
// Process notification content
print("\(content.userInfo)")
completionHandler([.alert, .sound]) // Display notification Banner
}
As per details in your question, you have already implemented above function, but with blank completionHandler(). Because of that notification banner doesn't display while app is in foreground state.
Earlier iOS 10:
You need to handle this by yourself. Like if you want to display banner when you received a notification, while app is in foreground state. You need to do this by yourself. You have to design your custom notification banner to display within app.
Hope it helps you.
Add this func in your AppDelegate:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
}
Add UNUserNotificationCenterDelegate protocol to your AppDelegate class like this:
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
Add below line in didFinishLaunchingWithOptions func:
UNUserNotificationCenter.current().delegate = self

Why I did not receive any notification on my iPhone?

Running this on Xcode8.3 with swift 3.1
Below is my code in AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
if granted {
print("OK!")
}
else {
print("No!")
}
})
application.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("==== didReceiveRemoteNotification ====")
print(userInfo)
}
I use node-apns to push notification to my app and I can have message from my Debug area in Xcode.
==== didReceiveRemoteNotification ====
[AnyHashable("id"): 123, AnyHashable("aps"): {
alert = "Hello World \U270c";
badge = 3;
}]
But, I did not receive any notification on my iPhone.
Did I missing something?
With iOS 10, you can do the following to see push notifications when the App is in Foreground. You have to implement the below function in AppDelegate. It's a delegate method of UNUserNotificationCenterDelegate.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
Follow the below steps:
Import UserNotifications and extend UNUserNotificationCenterDelegate in AppDelegate.
Set up the UNUserNotificationCenter delegate in didFinishLaunchingWithOptions.
let center = UNUserNotificationCenter.current()center.delegate = self
Implement the will present method in AppDelegate and call the completion handler with the options.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert,.badge,.sound])
}
Now if you get a push, you can see the notification alert even if your app is in foreground. More Info in Apple Doc.
if you want to handle notifications, when your app is active, you should do something like this, because the push view won't appear
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
if application.applicationState == .active {
//create custom view or something
} else {
//it was background/off
}
}
you might be also interested in creating new build schema, so your app will wait until it would be launched, so you can debug your app behaviour when receiving push.

Resources