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
Related
My requirement is prevent remote notification from being display.
I can handler this if app is in foreground or background in following methods:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
//logic hide notification here
}
public func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
//logic hide notification here
}
When app is being killed, I'm trying to handler logic in UNNotificationServiceExtension but it did not work:
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: #escaping (UNNotificationContent) -> Void) {
// logic hide notification here
}
I've read this article: Is it possible to prevent a remote notification from being displayed?
It said that Apple not allow to do this, is this correct?
Yes, it's correct.
You cannot catch a remote notification and hide it. The best way to not receive remote notifications is to say no to the permission. If your server send remote notifications you can configure it not to send notifications when you does not want.
Another way to send notifications and not show them is to send "silent notification". It allows you to receive the notification, get its content and do what you want (you have only 30s). I thinks, you can send silent notifications, check content and send a local notification if it needs to, but I'm not sure.
Are you attempting to remove notifications completely? (foreground AND background?)
If that is the case then you should ask your back-end service to send you a silent notification instead of a normal one. you shouldn't be handling that yourself.
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
I have APNS connected to my app.
The problem is in different behavior of system delegate didReceiveRemoteNotification. It is working properly only when the debugger is attached to the app, otherwise, it is not called when the app is in the background state. For example, the delegate is called if test phone is connected to the mac via USB cable and app is being debugged. Right after cable disconnection delegate is not called anymore.
The question is how app state (debugged or not) influence on didReceiveRemoteNotification behavior. (both IOS 10 and 11)
To detect delegate call I make backend requests and I'm sure there is no problem with call detection.
I had the same problem, spent a lot of time looking for a solution. I found a workaround mentioned in the Apple forums.
Make the class where you handle the push notifications a delegate of UNUserNotificationCenter
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
}
and then implement the willPresent notification: UNNotification method
#available(iOS 10.0, *)
extension APNSService: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
Log.debug?.message("Received push in foreground through UserNotificationCenter, calling Inbox.incrementalSync")
...
completionHandler([])
}
}
I am writing a reminder app in iOS 10; my local notifications are send using the UserNotifications framework. Sending the notification works fine already; my problem is rather the background handling of the notification.
Earlier days, you could use didReceiveRemoteNotification in the app delegate for handling stuff like userInfo; now, UserNotification has apparently it's own methods.
I want to detect, generally, if in my absence a notification has arrived. Case: I received it, I tap open the app icon, bam: alert controller that says: you've received a notification.
I am using these both functions for it:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (_ options: UNNotificationPresentationOptions) -> Void) {
print("Handle push from foreground")
UserDefaults.standard.set(true, forKey: "didReceiveRemoteNotification")
UserDefaults.standard.synchronize()
print("\(notification.request.content.userInfo)")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Handle push from background or closed")
UserDefaults.standard.set(true, forKey: "didReceiveRemoteNotification")
print("\(response.notification.request.content.userInfo)")
}
But they ONLY work, if I access the app by tapping on the notification in Notification Center. So, how do I detect if I've received a notification in the scenario that I don't enter the app through the notification, but through the app itself?
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.