Reputation: 5418
I am using push notification service in my app. When app is in background I am able to see notification on notification screen(screen shown when we swipe down from top of iOS device). But if application is in foreground the delegate method
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
is getting called but notification is not displayed in notification screen.
I want to show notification on notification screen independent of whether app is in background or foreground. I am tired by searching for a solution. Any help is greatly appreciated.
Upvotes: 239
Views: 275224
Reputation: 58049
It's simply:
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
) -> Bool {
UNUserNotificationCenter.current().delegate = self
UIApplication.shared.registerForRemoteNotifications() .. etc
return true
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
completionHandler([.banner, .badge, .sound, .list])
}
}
Don't forget .list
.
If your app is in the background, this will appear correctly on the phone. If your app is in the foreground, this will appear correctly on the phone (ie in front of your app).
Sounds, audio, notifications center, everything works perfectly. There are no issues. There is nothing to branch on, just call the completion handler with all options.
Tip: when you are typing "userNotificationCe.." for autocompletion, be aware there's an alternate aysnc-style selection. You want the one above, not the async one.
// Not the one you want from autocompletion
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification)
async -> UNNotificationPresentationOptions {
}
Upvotes: 4
Reputation: 49
Works in iOS 14+ as well, no need to handle any alerts or views manually simply let iOS do its thing
Inside where we reive the notification replace with below code
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
@escaping (UNNotificationPresentationOptions) -> Void
) {
if (UIApplication.shared.applicationState == .inactive || UIApplication.shared.applicationState == .background) {
if #available(iOS 14.0, *) {
completionHandler([[.banner, .sound]])
} else {
completionHandler([.alert, .sound])
}
} else {
if #available(iOS 14.0, *) {
completionHandler([[.banner]])
} else {
completionHandler([.alert])
}
}
}
Main thing to lookout for is not to use sound while in forground it wont show banner
Upvotes: 1
Reputation: 13274
100% working tested
First import
import UserNotifications
then add delegate in class
UNUserNotificationCenterDelegate
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate
Following method is responsible while app is open and notifcation comes.
willPresent
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let content = notification.request.content
let alertVC = UIAlertController.init(title: title, message: body, preferredStyle: .alert)
alertVC.addAction(UIAlertAction.init(title: appLan_share.Ok_txt, style: .default, handler: {
_ in
//handle tap here or navigate somewhere…..
}))
vc?.present(alertVC, animated: true, completion: nil)
print("notification Data: \(content.userInfo.values)")
completionHandler([.alert, .sound])
}
you can also handle application state by checking current application state.
Additionally if your app is not running then following method is responsible for handling push notification
didReceive
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
let aps = userInfo["aps"] as? [String: Any]
let alert = aps?["alert"] as? [String: String]
}
Upvotes: 1
Reputation: 9965
For anyone might be interested, I ended up creating a custom view that looks like the system push banner on the top but adds a close button (small blue X) and an option to tap the message for custom action. It also supports the case of more than one notification arrived before the user had time to read/dismiss the old ones (With no limit to how many can pile up...)
The usage is basically on-liner:
[AGPushNoteView showWithNotificationMessage:@"John Doe sent you a message!"];
And it looks like this on iOS7 (iOS6 have an iOS6 look and feel...)
Upvotes: 37
Reputation: 1093
Objective C
For iOS 10
we need integrate willPresentNotification
method for show notification banner in foreground
.
If app in foreground mode(active)
- (void)userNotificationCenter:(UNUserNotificationCenter* )center willPresentNotification:(UNNotification* )notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
NSLog( @"Here handle push notification in foreground" );
//For notification Banner - when app in foreground
completionHandler(UNNotificationPresentationOptionAlert);
// Print Notification info
NSLog(@"Userinfo %@",notification.request.content.userInfo);
}
Upvotes: 42
Reputation: 261
For Swift 5
1) Confirm the delegate to the AppDelegate with
UNUserNotificationCenterDelegate
2)
UNUserNotificationCenter.current().delegate = self
indidFinishLaunch
3) Implement the below the method in
AppDelegate
.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
print("Push notification received in foreground.")
completionHandler([.alert, .sound, .badge])
}
That's it!
Upvotes: 24
Reputation: 863
Best Approach for this is to add UNUserNotificationCenterDelegate
in AppDelegate
by using extension AppDelegate: UNUserNotificationCenterDelegate
That extension tells the app to be able to get notification when in use
And implement this method
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.alert)
}
This method will be called on the delegate only if the application is in the Foreground.
So The final Implementation:
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.alert)
}
}
And To call this you must set the delegate in AppDelegate in didFinishLaunchingWithOptions
add this line
UNUserNotificationCenter.current().delegate = self
You can modify
completionHandler(.alert)
with
completionHandler([.alert, .badge, .sound]))
Upvotes: 1
Reputation: 15951
For swift 5 to parse PushNotification dictionary
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
if application.applicationState == .active {
if let aps1 = data["aps"] as? NSDictionary {
if let dict = aps1["alert"] as? NSDictionary {
if let strTitle = dict["title"] as? String , let strBody = dict["body"] as? String {
if let topVC = UIApplication.getTopViewController() {
//Apply your own logic as per requirement
print("strTitle ::\(strTitle) , strBody :: \(strBody)")
}
}
}
}
}
}
To fetch top viewController on which we show topBanner
extension UIApplication {
class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return getTopViewController(base: nav.visibleViewController)
} else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
return getTopViewController(base: selected)
} else if let presented = base?.presentedViewController {
return getTopViewController(base: presented)
}
return base
}
}
Upvotes: 3
Reputation: 3802
Xcode 10 Swift 4.2
To show Push Notification when your app is in the foreground -
Step 1 : add delegate UNUserNotificationCenterDelegate in AppDelegate class.
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
Step 2 : Set the UNUserNotificationCenter delegate
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.delegate = self
Step 3 : This step will allow your app to show Push Notification even when your app is in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound])
}
Step 4 : This step is optional. Check if your app is in the foreground and if it is in foreground then show Local PushNotification.
func application(_ application: UIApplication,didReceiveRemoteNotification userInfo: [AnyHashable: Any],fetchCompletionHandler completionHandler:@escaping (UIBackgroundFetchResult) -> Void) {
let state : UIApplicationState = application.applicationState
if (state == .inactive || state == .background) {
// go to screen relevant to Notification content
print("background")
} else {
// App is in UIApplicationStateActive (running in foreground)
print("foreground")
showLocalNotification()
}
}
Local Notification function -
fileprivate func showLocalNotification() {
//creating the notification content
let content = UNMutableNotificationContent()
//adding title, subtitle, body and badge
content.title = "App Update"
//content.subtitle = "local notification"
content.body = "New version of app update is available."
//content.badge = 1
content.sound = UNNotificationSound.default()
//getting the notification trigger
//it will be called after 5 seconds
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
//getting the notification request
let request = UNNotificationRequest(identifier: "SimplifiedIOSNotification", content: content, trigger: trigger)
//adding the notification to notification center
notificationCenter.add(request, withCompletionHandler: nil)
}
Upvotes: 22
Reputation: 7405
For displaying banner message while app is in foreground, use the following method.
iOS 10, Swift 3/4 :
// 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])
}
iOS 10, Swift 2.3 :
@available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void)
{
//Handle the notification
completionHandler(
[UNNotificationPresentationOptions.Alert,
UNNotificationPresentationOptions.Sound,
UNNotificationPresentationOptions.Badge])
}
You must also register your app delegate as the delegate for the notifications center:
import UserNotifications
// snip!
class AppDelegate : UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate
// snip!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// set the delegate in didFinishLaunchingWithOptions
UNUserNotificationCenter.current().delegate = self
...
}
Upvotes: 253
Reputation: 4569
As mentioned above, you should use UserNotification.framework
to achieve this. But for my purposes I have to show it in app anyway and wanted to have iOS 11
style, so I've created a small helper view, maybe would be useful for someone.
GitHub iOS 11 Push Notification View.
Upvotes: 0
Reputation: 5418
If the application is running in the foreground, iOS won't show a notification banner/alert. That's by design. But we can achieve it by using UILocalNotification
as follows
Check whether application is in active state on receiving a remote
notification. If in active state fire a UILocalNotification.
if (application.applicationState == UIApplicationStateActive ) {
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.userInfo = userInfo;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertBody = message;
localNotification.fireDate = [NSDate date];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
SWIFT:
if application.applicationState == .active {
var localNotification = UILocalNotification()
localNotification.userInfo = userInfo
localNotification.soundName = UILocalNotificationDefaultSoundName
localNotification.alertBody = message
localNotification.fireDate = Date()
UIApplication.shared.scheduleLocalNotification(localNotification)
}
Upvotes: 27
Reputation: 5420
In your app delegate use bellow code
import UIKit
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var currentToken: String?
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
application.registerForRemoteNotifications()
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
// Enable or disable features based on authorization.
if granted == true
{
print("Allow")
UIApplication.shared.registerForRemoteNotifications()
}
else
{
print("Don't Allow")
}
}
UNUserNotificationCenter.current().delegate = self
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data){
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
let token = tokenParts.joined()
currentToken = token //get device token to delegate variable
}
public class var shared: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
}
Upvotes: 2
Reputation:
Below code will be work for you :
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
application.applicationIconBadgeNumber = 0;
//self.textView.text = [userInfo description];
// We can determine whether an application is launched as a result of the user tapping the action
// button or whether the notification was delivered to the already-running application by examining
// the application state.
if (application.applicationState == UIApplicationStateActive) {
// Nothing to do if applicationState is Inactive, the iOS already displayed an alert view.
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Did receive a Remote Notification" message:[NSString stringWithFormat:@"Your App name received this notification while it was running:\n%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]]delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
}
}
Upvotes: 61
Reputation: 61
Adding that completionHandler line to delegate method solved same problem for me:
//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) {
completionHandler([.alert, .badge, .sound])
}
Upvotes: 4
Reputation: 1832
Here is the code to receive Push Notification when app in active state (foreground or open). UNUserNotificationCenter documentation
@available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void)
{
completionHandler([UNNotificationPresentationOptions.Alert,UNNotificationPresentationOptions.Sound,UNNotificationPresentationOptions.Badge])
}
If you need to access userInfo of notification use code: notification.request.content.userInfo
Upvotes: 8
Reputation: 66
If your application is in foreground state, it means you are currently using the same app. So there is no need to show notification on the top generally.
But still if you want to show notification in that case you have to create your custom Alert View or Custom View like Toast or something else to show to the user that you have got a notification.
You can also show a badge on the top if you have such kind of feature in your app.
Upvotes: -2
Reputation: 594
You can create your own notification that mimics the banner alert.
One way is to create a custom uiview that looks like the banner and can animate and respond to touches. With this in mind you can create even better banners with even more functionality.
Or you can look for an api that does it for you and add them as podfiles to your project.
Here are a couple that I have used:
https://github.com/terryworona/TWMessageBarManager
https://github.com/toursprung/TSMessages
Upvotes: 9
Reputation: 7333
As @Danial Martine said iOS won't show a notification banner/alert. That's by design. But if really have to do it then there is one way . I have also achieve this by same.
1.Download the parse frame work from Parse FrameWork
2.Import #import <Parse/Parse.h>
3.Add following code to your didReceiveRemoteNotification Method
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[PFPush handlePush:userInfo];
}
PFPush will take care how to handle the remote notification . If App is in foreground this shows the alert otherwise it shows the notification at the top.
Upvotes: -3
Reputation: 7845
If the application is running in the foreground, iOS won't show a notification banner/alert. That's by design. You have to write some code to deal with the situation of your app receiving a notification while it is in the foreground. You should show the notification in the most appropriate way (for example, adding a badge number to a UITabBar
icon, simulating a Notification Center banner, etc.).
Upvotes: 17