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?
Related
What is the right way to play a tone associated with notification in iOS 15 without displaying banner or list?
When handling notifications in foreground, both local and push, notification sounds are not playing if UNNotificationPresentationOptions is only sound. If additional options like banner or list is added along with sound then notification tone plays.
When app is in background, all options of notification presentation are working properly.
I know alert option is depreciated from iOS 15. Is using sound as the only presentation option, no longer valid?
Below is the snippet
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification, withCompletionHandler
completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.sound) //not working
//completionHandler([.banner, .sound]) //works
//completionHandler([.list, .sound]) //works
}
Update: Apple confirmed that this was a bug and it is now fixed in iOS 16 beta 2. No solution for iOS 15 though.
I found the solution.
You would need to set the completion handler like this:
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
switch UIApplication.shared.applicationState {
case .active:
if #available(iOS 14.0, *) {
completionHandler([.sound, .list])
} else {
// Fallback on earlier versions
completionHandler([.sound])
}
default:
if #available(iOS 14.0, *) {
completionHandler([.banner, .sound])
} else {
// Fallback on earlier versions
completionHandler([.alert, .sound])
}
}
}
Now the in-app notifications come with sound and with my custom banner.
.list will add the notification on the Notification Center as well, which I find very useful, in case the user is using the app and missed some notifications.
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
When push notification arrives, and app is in foreground, I need to show custom popup. It must come from the upper edge of the screen, stay visible to a few seconds and then disappear back behind the top edge.
My question is how do I show it? As I know, in order to make view visible, I must add it as a subview to some existing view. But push notification may come at random time, so I do not know beforehand which view controller will be active at that moment.
So: where do I attach my custom view to (to make it visible on top of everything)?
You need to implement the following delegate in your appDelegate and your push notification will appear in foreground as well.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
completionHandler()
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound])
}
And on tapping on the notification you can get the same behavior as you do when app is in background.
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?