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.
Related
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
Though till Swift 3 we used didReceiveRemoteNotification userInfo: [AnyHashable : Any] method its working fine, but in Swift 4 its not working. Does anyone have any idea about it ?
For displaying notification while app is in foreground, use the following method.
// This method will be called when app received push notifications in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler([.alert, .badge, .sound])
}
According to apple documentation, you can display notification while app is running
I have implemented remote notifications in my app, however I have problems with didReceiveRemoteNotification:fetchCompletionHandler:.
When the phone's screen is locked, I am getting the notification. If the user swipes the notification, app comes back to foreground and didReceiveRemoteNotification:fetchCompletionHandler: is called.
But if the app is running in the foreground, didReceiveRemoteNotification:fetchCompletionHandler: is never called. What might be the reason?
I'm working on iOS 10.3.2
Which iOS version you are working on ?
There are different methods for iOS 9 and iOS 10.
Below are the ones for iOS 10
//Called when a notification is delivered to a foreground app.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
}
//Called to let your app know which action was selected by the user for a given notification.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
}
For iOS 9, make sure to register your notification in didBecomeActive
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
and in your didReceiveRemoteNotification
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
if application.applicationState == .active {
//foreground state
}
}
Best approach would be to put a debugger in didReceiveRemoteNotification and check further.
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'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?