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?
Related
I used local notification to deliver a message to the user at the same time I want to update App badge when the notification triggers, but the local notification delegate have functions that deal with notifications when the app is in the foreground and when the user interacts with notification (like a tap on it). Is there any way to update the app badge when the notification triggers and the app is in background?
Handle notification when the app is in the foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// run code when app in foreground
}
Handle notification when the tap action on it
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
// run code when user interact with notification only
}
To update App badge when local notification trigger set the badge value in the code bellow when set the notification:
func schedulNotification() {
let content = UNMutableNotificationContent()
content.badge = 1 // That will appear on app icon when notification trigger
// Continue notification settings...
}
I have now integrated push notifications in my app using FirebaseNotifications. For this I use a NotificationServiceExtension for processing (CoreData, ...) and the usual methods, such as didReceiveRemoteNotification, willPresent or didReceive in AppDelegate.
The processing of the content and the display of the push notification works perfectly in all status of the app - in the background and also in the foreground.
If the app is in the foreground or in the background, but not killed, tapping on the push notification also works and the didReceive method is called and I can navigate to the desired content.
If the app is completely killed, a tap on the push notification a few seconds later starts the app, but the usual launch screen (splash screen) is not called and nothing else happens - the app remains on a white screen.
At first I suspected I had forgotten to call a completionHandler, but they are all stored and I don't find an error anywhere.
Can someone please help me, where there could still be a problem that the splash screen, then the AppDelegate and my normal ViewController, is called up.
Thank you - here is my code in the AppDelegate. Unfortunately I don't have a log because the app has to be completely killed and I therefore have no output in the Xcode console.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
completionHandler(UIBackgroundFetchResult.newData)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([[.alert, .badge, .sound]])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
defer {
completionHandler()
}
if response.actionIdentifier == "friends" {
print("Open button was pressed.")
// TODO: - Deep link to friends
}
completionHandler()
}
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
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'm creating an iOS-Native app. I'm using XCode 8, testing on iOS10, using swift 3.
I'm dealing with APNS and sending Remote notifications (through OneSignal).
The notifications work flawlessly outside my app (when it is in background). However, when I have the app in foreground, no matter what I pass into the completionHandler() (ex. [.alert, .sound], or [.sound] or []) the system creates a UIAlertController with the contents of the notification (title and body) and presents it to the user. This is incredibly obnoxious as a user-interface and I would imagine there is some way to work around it.
I'm implementing the UNUserNotificationCenterDelegate as follows:
extension ViewController: UNUserNotificationCenterDelegate{
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
//This is my BRYXBanner notification presentation/
let banner = Banner(title: notification.request.content.title, subtitle: notification.request.content.body, image: nil, backgroundColor: .blue, didTapBlock: nil)
banner.alpha = 0.9
banner.animationDuration = 0.2
banner.position = .top
banner.show(genView, duration: 3.0)
completionHandler([])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch(response.actionIdentifier){
//switch cases for actions/
default: break
}
completionHandler([])
}
}
I'm also implementing the UIApplicationDelegate but that one simply has print statements.
What I'm seeing when I receive a notification is this:
Screenshot of a custom notification I sent for this
I've seen others have had this issue (How to disable default notification alert view on iOS remote notifications?) but have no idea how they got around it. Most posts simply lead to "oh, I fixed it" with no further explanation.
How can I bypass the showing of this notification, whether it be silencing the notification (if that works) or dealing with the completion handler or intercepting the notification before it is displayed?