iOS前台接收推送通知

236

我在我的应用程序中使用推送通知服务。当应用程序在后台运行时,我可以在通知屏幕上看到通知(通过从iOS设备顶部向下滑动显示的屏幕)。但如果应用程序在前台运行,则委托方法

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo

正在调用,但通知没有显示在通知屏幕上。

我希望在通知屏幕上显示通知,无论应用程序是在后台还是前台运行。我已经搜索了很久,寻找解决办法。非常感谢任何帮助。


42
苹果公司表示:如果您的应用程序在前台运行时接收到本地或远程通知,则您需要以特定于应用程序的方式向用户传递信息。请注意,这是您的责任。 - Lauri Lehmijoki
2
一些最新的(2016年10月)苹果链接: 这里那里那里 - azmeuk
1
iOS 9.3及以下版本不支持推送通知的前台功能,对吗? - Anurag Sharma
2
我在Ionic中遇到了同样的问题... - Sayed Mohd Ali
4
苹果关于用户通知的最新文档链接现在在这里(通用)这里(前台通知) - lukemmtt
显示剩余2条评论
20个回答

252

在应用程序前台显示横幅消息,使用以下方法。

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])
}

你还必须将你的应用代理注册为通知中心的代理:

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
      ...
   }

24
不要忘记将通知中心委托设置为应用程序委托:在application didFinishLaunchingWithOptions中,使用UNUserNotificationsCenter.current().delegate = self - Achintya Ashok
@chengsam 在iOS 8的前台状态下无法工作。 - Dilip Tiwari
@DilipTiwari 这是适用于 iOS 10+ 的。 - chengsam
3
对于那些仍在苦苦挣扎的人,正确的写法是UNUserNotificationCenter,而不是在center前加上's'成为UNUserNotificationsCenter。 - Raj
1
@Achintya Ashok,您的评论中有一个拼写错误,您加入了“s”和“Notification”,应该是UNUserNotificationCenter.current().delegate = self。 - Matthew Usdin
显示剩余12条评论

61

以下代码将适用于您:

- (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];          
    }    
}

这个可以用。关于它的更多信息是,当应用程序在前台时,会出现一个本地UI警报框,其中包含通知文本(title是稍微大一点的粗体文本,而message是在其下方的较小文本。底部有一个“确定”按钮以关闭)。 将选项applicationIconBadgeNumber设置为0是为了隐藏Springboard上应用程序图标顶部显示的数字(例如,在邮件应用中表示未读消息数量)。在这个例子中,我不知道是否需要该选项。 - jwinn
这对UNnotification和UILocalNotification都适用吗? - user6631314

42

Objective C

enter image description here

为了在前台显示通知横幅,对于iOS 10,我们需要集成willPresentNotification方法。

如果应用程序处于前台模式(活动状态)

- (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);
}

1
只需复制代码,不要忘记使用UNUserNotificationCenterDelegate协议。 - Nike Kov
如果我想显示一个弹出窗口而不是这个通知,那该怎么办? - Mihir Oza
@MihirOza 你需要UIAlertController吗? - Ashwini Chougale
我知道,但是当应用程序处于活动状态时,我不想要通知弹出窗口。我只想在我的应用程序中收到警报。 - Mihir Oza
1
我尝试了你的函数,但我仍然无法在前台推送。 - Khaled Boussoffara

37

如果有人感兴趣的话,我最终创建了一个自定义视图,看起来像系统上方的推送横幅,但增加了一个关闭按钮(小蓝色X)和一个选项,可以点击消息执行自定义操作。它还支持用户在有多个通知到达之前没有时间阅读/解除旧通知的情况(没有限制可以积累多少...)

GitHub链接: AGPushNote

基本上是一行代码就能使用:

[AGPushNoteView showWithNotificationMessage:@"John Doe sent you a message!"];

在iOS7上看起来是这样的(iOS6有iOS6的外观和感觉...)

输入图像说明


1
现在也用Swift重新设计了:https://github.com/charliewilliams/CWNotificationBanner/ (由我完成) - buildsucceeded
不错,这将会很有用。 - 无夜之星辰

27

如果应用程序正在前台运行,iOS 不会显示通知横幅/提示。这是设计上的限制。但我们可以通过以下方式使用 UILocalNotification 来实现:

  • 在接收到远程通知时,检查应用程序是否处于活动状态。如果处于活动状态,则触发一个 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)
}

86
我认为这样做并没有什么帮助。本地通知和远程通知被处理方式相同,因此,当本地通知触发时,如果应用程序正在运行,则不会显示/播放徽章/横幅或声音。 - RPM
4
它还将在iOS通知中心中留下一条记录。 - Ab'initio
3
当推送通知到来时,我不会发出本地通知。相反,我会采用类似@Rick77提到的行为,比如显示警报或一些提示框。我想我不必再通过操作系统处理操作系统要求我处理的事情。 - Fábio Oliveira
3
这个解决方案是可行的,因为本地和远程通知的处理方式相同。当应用程序在前台运行时,收到远程通知不会显示任何内容。使用警报或自定义警报是解决方案。 - Hammer
19
这实际上并不起作用。根据UILocalNotification文档所述:如果当系统传递通知时应用程序处于前台可见状态,则会调用应用程序委托的application:didReceiveLocalNotification:方法来处理通知。使用提供的UILocalNotification对象中的信息来决定采取什么操作。当应用程序已经在前台时,系统不会显示任何警报、徽章或播放任何声音。 - Chris Morse
显示剩余7条评论

23

针对 Swift 5:

1)确认AppDelegate的委托使用UNUserNotificationCenterDelegate

2)在didFinishLaunch中使用UNUserNotificationCenter.current().delegate = self

3)实现下面的方法在AppDelegate中。

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
     print("Push notification received in foreground.")
     completionHandler([.alert, .sound, .badge])
}

就是这样了!


1
.alert在iOS14中已被弃用,请改用.banner和.list。https://developer.apple.com/documentation/usernotifications/unnotificationpresentationoptions/3564813-list - blyscuit

22

Xcode 10 Swift 4.2

当您的应用程序在前台时显示推送通知 -

步骤1:在AppDelegate类中添加代理UNUserNotificationCenterDelegate。

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

第二步:设置UNUserNotificationCenter委托

let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.delegate = self

步骤3: 此步骤将允许您的应用程序在前台显示推送通知。

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.alert, .sound])

    }

步骤 4:此步骤为可选。检查您的应用程序是否在前台,如果是,则显示本地推送通知。

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()
        }
    }

本地通知功能 -

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)
    }

2
这是一个很好的例子,说明需要阅读线程中所有回复。早期的线程提到了方法,然后是委托,最后这个线程提到了你需要完成的所有三个步骤。非常感谢Prashant提供完整的答案! - user3069232
很高兴知道它对你有所帮助。愉快编码! - Prashant Gaikwad

17
如果应用程序正在前台运行,iOS 不会显示通知横幅/警报。这是设计如此。您需要编写一些代码来处理应用程序在前台接收到通知的情况。您应该以最合适的方式显示通知(例如,将徽章数字添加到 UITabBar 图标中,模拟通知中心横幅等)。

1
但在iOS邮件应用程序中,他们已经做到了这一点,当邮件应用程序在前台时,您将收到新的通知横幅/警报。 - Ab'initio
3
起初,我并不确定,但在iOS中,并非所有应用程序都是平等的。我猜想原生的邮件应用程序可能使用了一些私有API,在公共软件开发工具包中不可用。或者,通知代码可能对苹果邮件应用程序ID做出了例外。 - Daniel Martín
1
什么??我快要发狂了。 - Josh
@DanielMartín,你能告诉我在iOS 8.0中前台状态下如何接收通知吗? - Dilip Tiwari
18
请注意,本答案仅适用于iOS 9及以下版本。自iOS 10起,苹果引入了一个新的API来处理通知(UNUserNotificationCenter API)。随着这个新API的出现,现在可以在应用程序前台显示通知。因此,如果您因此问题中的不同答案而感到困惑,那是因为其中一些答案太旧了,只描述了iOS 9及之前的行为,而其他答案则没有考虑到UNUserNotificationCenter 仅适用于iOS 10及以上版本。 - tomacco

9
你可以创建自己的通知,模仿横幅警报。
一种方法是创建一个自定义的uiview,它看起来像横幅,并且可以动画和响应触摸。有了这个想法,您甚至可以创建更好的横幅,具有更多的功能。
或者您可以寻找一个api来为您完成这项工作,并将它们作为podfile添加到您的项目中。
以下是我使用过的几个:

https://github.com/terryworona/TWMessageBarManager

https://github.com/toursprung/TSMessages


1
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。 - Robert
1
TWMessageBarManager 可以通过应用程序委托本身轻松调用和使用,因为它使用单例设计模式。感谢提供的链接。 - Jay Mayu

8
这是在应用程序处于活动状态(前台或打开)时接收推送通知的代码。请参考UNUserNotificationCenter文档
@available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void)
{
     completionHandler([UNNotificationPresentationOptions.Alert,UNNotificationPresentationOptions.Sound,UNNotificationPresentationOptions.Badge])
}

如果您需要访问通知的userInfo,请使用以下代码:notification.request.content.userInfo

在哪里编写这个函数?是在viewDidLoad中还是在viewController类中? - iOS Developer
如果我将其作为嵌套函数调用,它会被调用吗? - iOS Developer
1
将此代码放置于AppDelegate类中,您无需调用此函数。 - Milan Jayawardane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接