UNUserNotificationCenterDelegate didReceive is not getting triggered in iOS with Flutter App - ios

I have setup push notifications using APNS for iOS (Using Swift) in the flutter App. didReceiveRemoteNotification is getting triggered when the app receives a push notification from AWS Pinpoint. But none of the other methods are getting triggered when the user taps the notification. Once I handle the user action on the push notification, I can call a scheme using openUrl to specific route on the app.
I have tried by disabling/enabling background modes in the capabilities in the Xcode. Also verified that push notifications are turned on in the capabilities. Pinpoint uses APNS to send the notification to iOS and Firebase to send the notification to Android which is working fine.
Also tried with iOS target version as 10.0, 11.0 and 12.0
UNUserNotificationCenter.current().delegate = self
is declared in didFinishLaunchingWithOptions and imported UserNotifications
When I tap the push notification, this is getting printed in the console:
Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: but the completion handler was never called.
Payload from pinpoint:
[AnyHashable("aps"): {
alert = {
body = "BODY";
title = "TITLE";
};
badge = 0;
"content-available" = 1;
"mutable-content" = 0;
sound = default;
}]
Code,
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
// Print full message.
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
// Print full message.
print(userInfo)
completionHandler()
}
}
didReceive is expected to get triggered when the user taps on the push notification which is not happening in my case.
Can anyone help me on how to trigger when the user taps the push notification?

I was facing a similar problem. iOS swift delegate methods were not triggered. It appears that the methods must have been declared public.
Just replace
func userNotificationCenter
with
public func userNotificationCenter
Maybe it will helps someone...

Have you set center's delegate property?
center.delegate = self
where self is AppDelegate.

Related

Detect push notification selection when the app is at running state in iOS

I am using didReceiveRemoteNotification for detecting the app notification. But it is is getting fired automatically, when the app is at running state. I need the notification selection get detected when the app is at running state, rather than automatic notification detection through didReceiveRemoteNotification. Thanks in Advance
iOS 10+ provide the custom local notification for handling this type of issue when the app is running in the foreground.
In didFinishLaunchingWithOptions, add the delegate
UNUserNotificationCenter.current().delegate = self
then create an appDelegate extension and add this.
#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
// Print full message.
print(userInfo)
// Change this to your preferred presentation option
completionHandler([.alert,.sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print full message.
print("tap on on forground app",userInfo)
completionHandler()
}
}
For details:
Read This Tutorial

Unable to trigger didReceive notification delegate when you bring the app from background to foreground

I have implemented push notification for ios10. Tapping on the notification alert would trigger "didReceive" delegate, were i save the notification in coredata or silent notification if i m in foreground. The problem is if i receive a stack of notification in background and When i bring my app to foreground from background, Is there a possibility to call "didReceive" delegate or any other push notification delegate were i could sync my items to coredata.
Note
I don't want to sync(didReceive or any delegate) the items in background using silent notification nor tapping on the alert. It should sync automatically the stack of push notification when i bring the app to foreground
func handleInboxNotification(didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
if let inboxValue = userInfo["inbox"] as? String, let value = inboxValue.boolValue(), value {
let mappedMessage = MessageCenterSDK.shared.constructReorderedDictionary(userInfo: userInfo)
MessageCenterDataManager.shared.synchronize(messages: mappedMessage)
messageCenterDelegate?.didFindNewMessages(hasNewMessages: true)
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
/// Handle outbound remote
handleInboxNotification(didReceiveRemoteNotification: response.notification.request.content.userInfo)
completionHandler()
}
I was facing the same issue, but my target was for iOS 13 & I'm using BGTaskScheduler to fetch data from the server in the background as well in terminated state.
I too want to trigger the notification when the app is in background. But not tapped but that seems to be not possible so we have changed our implementation by enabling background mode and it worked for me.
Hope it also helps.
For more reference on BGTaskScheduler, https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler
you need to use willpresent delegate in appDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// Change this to your preferred presentation option
completionHandler([])
}
This delegate is called when a notification comes in foreground

Swift: Getting Data from Remote notification

I have a messaging app, which gets data from server through push notification.
In the following image, you can see the process and also check where it gets faulted:
I have researched a lot about this problem but not getting a universal solution.
One solution I get is to use silent notification , discussed Here , to get data before it is shown and save it. But I didn't find how to show notification from app delegate once I received silent notification.
Kindly correct me if I am conceptually wrong somewhere.
Update:
One of problem is that the application:didReceiveRemoteNotification:fetchCompletionHandler: is only called when
app is in foreground
user clicks the notification
But when user doesn't click the notification, application:didReceiveRemoteNotification:fetchCompletionHandler: is not called, and I can't find a way to save the data, that is present in notification.
Your question is "To get data from Remote notification while the App is in foreground" if im correct, You can use these two methods to get data from Remote notifications for background and foreground app modes.
// Notification will present call back
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
// Handle your data here
print("Notification data: \(notification.request.content.userInfo)")
}
#available(iOS 10.0, *)
// Notification interaction response call back
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
// Handle your data here
print("Notification data: \(response.notification.request.content.userInfo)")
}
There are two cases:
Background
Closed State
If the app is in Background State, you have to enable Background Fetch, then this method will be called when the app is in Background application:didReceiveRemoteNotification:fetchCompletionHandler:
When the app is closed or killed by the user the above method not gonna work, for that you can use the VoIP technique.
didReceiveIncomingPushWithPayload method will be called whenever Remote Notification arrives
You can find more details about VoIP here

Local notification is not coming in forgeound in iOS 10.2

I have implemented local notification successfully for iOS 10.2.
But problem is that notification alert only comes if the app is in the background no alert come if the app is foreground.
Is it possible to get local notification in the foreground?
My code is here
func notificationNow(){
print("notification will be triggered in five seconds..Hold on tight")
let content = UNMutableNotificationContent()
content.title = "Intro to Notifications"
content.subtitle = "Lets code,Talk is cheap"
content.body = "Sample code from WWDC"
content.sound = UNNotificationSound.default()
//To Present image in notification
if let path = Bundle.main.path(forResource: "menu2", ofType: "png") {
let url = URL(fileURLWithPath: path)
do {
let attachment = try UNNotificationAttachment(identifier: "sampleImage", url: url, options: nil)
content.attachments = [attachment]
} catch {
print("attachment not found.")
}
}
// Deliver the notification in five seconds.
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5.0, repeats: false)
let request = UNNotificationRequest(identifier:requestIdentifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().add(request){(error) in
if (error != nil){
print(error?.localizedDescription as Any)
}
}
}
In the documentation for UNUserNotificationCenterDelegate:
Important
You must assign your delegate object to the UNUserNotificationCenter object no later before your app finishes launching. For example, in an iOS app, you must assign it in the application(:willFinishLaunchingWithOptions:) or application(:didFinishLaunchingWithOptions:) method.
You appear to be setting the delegate much later — just before the notification is added to the notification center.
I created a simple Swift class singleton with an extension to conform to UNUserNotificationCenterDelegate. In the singleton's init method I assigned the delegate to self. I then initialize the singleton in the AppDelegate's willFinishLaunchingWithOptions method.
Write following code (extension) in the class where you want to observe the local notification
This will notify when you receive notification in foreground or user tapped on notification when the app is in background.
Hope this will solve your problem.
extension ViewController:UNUserNotificationCenterDelegate{
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Tapped in notification")
}
//This is key callback to present notification while the app is in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("Notification being triggered")
//You can either present alert ,sound or increase badge while the app is in foreground too with ios 10
//to distinguish between notifications
// if notification.request.identifier == requestIdentifier
// {
completionHandler( [.alert,.sound,.badge])
// }
}
}
When the app is running in Foreground. You need to capture the Local Notification through delegate methods.
So in your AppDelegate implement the listening for delegate in didFinishLaunchingWithOptions method:
It is important to set the delegate before your app finishes launching.
// Do NOT forget to retain your delegate somewhere
let notificationDelegate = UYLNotificationDelegate()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let center = UNUserNotificationCenter.current()
center.delegate = notificationDelegate
// ...
return true
}
If you want to respond to actionable notifications or receive notifications while your app is in the foreground you need to implement the UNUserNotificationCenterDelegate. This protocol defines two optional methods:
userNotificationCenter(_:willPresent:withCompletionHandler:) is
called when a notification is delivered to a foreground app. You
receive the UNNotification object which contains the original
UNNotificationRequest. You call the completion handler with the
UNNotificationPresentationOptions you want to present (use .none to
ignore the alert).
userNotificationCenter(_:didReceive:withCompletionHandler:) is called
when a user selects an action in a delivered notification. You
receive the UNNotificationResponse object which includes the
actionIdentifier for the user action and the UNNotification object.
The system defined identifiers UNNotificationDefaultActionIdentifier
and UNNotificationDismissActionIdentifier are used when the user taps
the notification to open the app or swipes to dismiss the
notification.
In both cases you must call the completion handler once you finish.
#pragma mark - UNUserNotificationCenterDelegate Methods
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// Play sound and show alert to the user
completionHandler([.alert,.sound])
}
Use below method to configure notification to show in foreground,
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
You can refer Apple documentation for more details!

ios 10 Firebase Push Notification delegate method not called in background mode

I have been struggling with this problem for days and I have looked at every post about this and nothing works.
I am using FCM (Firebase Cloud Messaging). FCM talks directly to the app when in foreground, but it will use APNS when the app is in background.
I am trying to call a method everytime the app got notification by calling the method in the push notification's delegate function
I have these 2 delegate functions:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void)
and
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
which does not get called in background, according to apple documentation.
I also have this function which I believe should get called in the background but it does not.
func application(_ application: UIApplication,didReceiveRemoteNotification userInfo: [AnyHashable: Any],fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
I have all of these functions in ViewController
In background mode, I get banner notifications, but none of the delegate is called. Is there any way to make any of them work in the background, if not what should I do?
In addition I also get this error : <FIRMessaging/WARNING> FIRMessaging receiving notification in invalid state 2 in the log everytime I send a payload while the app is in the background.
Here is the payload that I send using postmate:
{
"priority":"high",
"notification":{
"sound": "default",
"badge": "1",
"title":"mytitle",
"body":"mybody",
"message":"Hello"
},
"content_available":true,
"to" : "/topics/myTopic"
}
I already turned on push notification in capabilities and checked push notification in background modes under capabilities.
I use Xcode 8 and have been testing on iphone 6 iOS 10.0.2
There can only be 1 delegate for a protocol.
In this case, I made APPDelegate and ViewController conform to UIApplicationDelegate. And only delegate functions in APPDelegate got called. That's why the one in ViewController is not called.
The solution would be just put didReceiveRemoteNotification in the AppDelegate.

Resources