当您的应用处于打开状态且在前台时,显示股票iOS通知横幅吗?


123

当Apple的官方iOS Messages应用程序打开并在前台运行时,来自其他联系人的新消息将触发原始的iOS通知股票提示横幅。参见下图。

在App Store的第三方应用程序中有可能吗?当您的应用处于打开状态且处于前台时,您的应用的本地通知和/或推送通知?

测试我的应用程序时,会收到通知,但不会显示iOS警报UI

但是,这种行为出现在苹果的官方消息应用程序:

消息处于打开状态并且位于前台。 仍显示通知警报。

本地和远程通知编程指南说:

当操作系统传递本地通知或远程通知并且目标应用未在前台运行时,它可以通过警报,图标徽章编号或声音向用户显示通知。

如果在传递通知时应用程序在前台运行,则应用程序委托会接收本地或远程通知。

是的,我们可以在前台接收通知数据。但是我看不到呈现本机iOS通知警报UI的方法

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo 
{
    // I know we still receive the notification `userInfo` payload in the foreground.
    // This question is about displaying the stock iOS notification alert UI.

    // Yes, one *could* use a 3rd party toast alert framework. 
    [self use3rdPartyToastAlertFrameworkFromGithub]
}

然后,Messages是否在前台使用私有API来显示警报?

出于此问题的目的,请不要在github等上建议任何第三方的“ toast”弹出警报。我只对可以在您的本地,本地iOS本地或推送通知警报UI 上完成此操作感兴趣应用程序是打开的,并且处于前台

Answers:


152

iOS 10添加了UNUserNotificationCenterDelegate用于在应用程序处于前台时处理通知的协议。

UNUserNotificationCenterDelegate协议定义了用于接收通知和处理动作的方法。当您的应用程序位于前台时,到达的通知将传递到您的委托对象,而不是使用系统界面自动显示。

迅速:

optional func userNotificationCenter(_ center: UNUserNotificationCenter, 
                     willPresent notification: UNNotification, 
      withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void)

目标C:

- (void)userNotificationCenter:(UNUserNotificationCenter *)center 
       willPresentNotification:(UNNotification *)notification 
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler;

UNNotificationPresentationOptions标志允许您指定UNNotificationPresentationOptionAlert显示使用通知中的文本警报。

这是关键,因为它允许您在应用打开时和在前台运行时显示警报,这是iOS 10的新增功能。


样例代码:

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Set UNUserNotificationCenterDelegate
        UNUserNotificationCenter.current().delegate = self
        
        return true
    }
    
}

// Conform to UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
    
    func userNotificationCenter(_ center: UNUserNotificationCenter,
           willPresent notification: UNNotification,
           withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
    {
        completionHandler(.alert)
    }
    
}

4
您能提供一个工作代码示例吗,系统会在该示例中显示传入的前台通知,就像应用程序在后台显示一样?
azmeuk

1
@azmeuk检查我的答案 ...
chengsam

8
不要忘记添加UNUserNotificationCenter.current().delegate = selfapplication(_:willFinishLaunchingWithOptions:)application(_:didFinishLaunchingWithOptions:)方法
Deniss Fedotovs

3
另外,请确保您没有将设备置于“ 请勿打扰”模式,否则通知将在通知中心中显示,但不会在应用程序的前台显示
Jadent

2
我的2美分:不要错过:导入UserNotifications。!
ingconti

94

要在应用程序处于前台状态时显示横幅消息,请使用以下方法。

iOS 10以上版本,Swift 3以上版本

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

1
哇,在我读过的所有地方,人们都说不可能。我很高兴找到这个答案,它的工作原理与我预期的完全一样!当应用程序运行时,现在推送通知的显示与在后台运行时的通知完全相同。谢谢!
Torre Lasley

1
该代码段在哪里?在appDelegate还是其他地方?
Yoav R.

@YoavR。AppDelegate
chengsam 2016年

我使用了相同的代码。但是我不知道为什么当应用程序处于前台时通知没有显示。
Boominadha Prakash M

2
Chengsam您可能要纠正此问题:不必将其放在中AppDelegate。必须将它放在符合的任何对象上UNUserNotificationCenterDelegate。话虽如此,大多数开发人员还是AppDelegate遵从了UNUserNotificationCenterDelegate。@YoavR。
亲爱的

16

编辑:

现在可以在iOS 10中使用前景警报了!请看这个答案

对于iOS 9及以下版本:

当您的应用处于打开状态且处于前台时,似乎无法显示股票iOS通知警报。Messages.app必须使用私有API。

当应用程序已经位于最前面时,系统不会显示任何警报,标记应用程序的图标或播放任何声音。- UILocalNotification文档

UIApplicationDelegate方法仍然被调用,让您的应用程序以应对本地或远程通知:

application:didReceiveLocalNotification:
application:didReceiveRemoteNotification:

但是,原始的本机iOS通知警报横幅UI将不会像在Apple的Messages.app 那样显示,该消息必须使用私有API。

最好的办法是滚动自己的警报横幅或使用现有框架:

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo 
{    
    // Use a 3rd party toast alert framework to display a banner 
    [self toastAlertFromGithub]
}

我在这里为这种行为打开了雷达: rdar://22313177


3
那么,WhatsApp和其他著名的应用程序如何做到这一点?
马查多

@tardoandre有截图吗?我认为这是通过模仿他们自己的观点中的iOS股票警报来实现的。
pkamb

2
toastAlertFromGithub如果您建议使用此第三方库,则应包括链接!
Ketan Parmar

14

要在打开应用程序时显示通知,我们需要手动处理它。因此,我在下面要做的就是处理收到的通知。

在AppDelegate.m中添加以下所有内容

  1. 处理来电通知
  2. 创建一个视图,添加AppIcon,Notification消息并将其显示为动画
  3. 添加触摸识别器可将其删除(如果被触摸)或在5秒钟之内删除动画。

让我知道这是否可以解决。对我来说效果很好,但是不确定这是否正确。

- (void)application:(UIApplication *)applicationdidReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {


NSString *notifMessage = [[userInfo objectForKey:@"aps"] objectForKey:@"alert"];

//Define notifView as UIView in the header file
[_notifView removeFromSuperview]; //If already existing

_notifView = [[UIView alloc] initWithFrame:CGRectMake(0, -70, self.window.frame.size.width, 80)];
[_notifView setBackgroundColor:[UIColor blackColor]];

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10,15,30,30)];
imageView.image = [UIImage imageNamed:@"AppLogo.png"];

UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 15, self.window.frame.size.width - 100 , 30)];
myLabel.font = [UIFont fontWithName:@"Helvetica" size:10.0];
myLabel.text = notifMessage;

[myLabel setTextColor:[UIColor whiteColor]];
[myLabel setNumberOfLines:0];

[_notifView setAlpha:0.95];

//The Icon
[_notifView addSubview:imageView];

//The Text
[_notifView addSubview:myLabel];

//The View
[self.window addSubview:_notifView];

UITapGestureRecognizer *tapToDismissNotif = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                    action:@selector(dismissNotifFromScreen)];
tapToDismissNotif.numberOfTapsRequired = 1;
tapToDismissNotif.numberOfTouchesRequired = 1;

[_notifView addGestureRecognizer:tapToDismissNotif];


[UIView animateWithDuration:1.0 delay:.1 usingSpringWithDamping:0.5 initialSpringVelocity:0.1 options:UIViewAnimationOptionCurveEaseIn animations:^{

    [_notifView setFrame:CGRectMake(0, 0, self.window.frame.size.width, 60)];

} completion:^(BOOL finished) {


}];


//Remove from top view after 5 seconds
[self performSelector:@selector(dismissNotifFromScreen) withObject:nil afterDelay:5.0];


return;


}

//If the user touches the view or to remove from view after 5 seconds
- (void)dismissNotifFromScreen{

[UIView animateWithDuration:1.0 delay:.1 usingSpringWithDamping:0.5 initialSpringVelocity:0.1 options:UIViewAnimationOptionCurveEaseIn animations:^{

    [_notifView setFrame:CGRectMake(0, -70, self.window.frame.size.width, 60)];

} completion:^(BOOL finished) {


}];


}

3
这对于创建您自己的警报可能是一个很好的答案,但未显示如截图所示的Stock iOS警报。
pkamb

嗨,谢谢你的客气话。是的,它看起来不是这样(如果您正在谈论外观),因为图像中上面显示的是iOS通知,而通过代码的是自定义。我们也许可以在视图中复制外观。我认为,WhatsApp的,有着简洁的寻找一个与背景虚化等
哈菲兹

1
有人投了反对票:(。很高兴听到为什么!?。谢谢
。– Hafeez

2
我这样做了,因为此答案中的代码(虽然可能是不错的)并没有真正回答所提出的问题:在应用程序中显示库存的 iOS吐司横幅。在SO上还有其他问题,那么这个答案将是很棒的。
pkamb

1
感谢pkamb的澄清,这是有道理的。我想念“股票”一词。
哈菲兹

10

这是在前台或开放阶段(iOS 10和Swift 2.3)中应用程序接收推送通知的代码

@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

userNotificationCenter(_:willPresent:withCompletionHandler:)仅在将属性添加到有效负载时才调用该方法content-available:1。最终的有效负载应类似于:

{
     "aps":{
          "alert":"Testing.. (7)",
          "badge":1,"sound":"default"
     },
     "content-available":1
}

1
userNotificationCenter(_:willPresent:withCompletionHandler:)当您的应用在前台运行时将被调用。因此,与“ 后台获取 ” 有关的“ 内容可用 ” 无关紧要。
DawnSong

9
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.body = body;
content.userInfo = userInfo;
content.sound = [UNNotificationSound defaultSound];
[content setValue:@(YES) forKeyPath:@"shouldAlwaysAlertWhileAppIsForeground"];

UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"Notif" content:content trigger:nil];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
    DLog(@"Error:%@", error);
}];

当应用程序针对iOS 10处于活动状态时,我可以显示推送通知

  1. 来自服务器的推送通知应该是静默的

  2. 从服务器接收远程通知时,您将发送本地通知并设置keyPath的值:shouldAlwaysAlertWhileAppIsForeground = True


快速2-是content.setValue("YES", forKeyPath: "shouldAlwaysAlertWhileAppIsForeground"),对吗?(“是”(不正确))
Yoav R.

注意:这将在这里碰撞下的iOS 12.见讨论您的应用程序: stackoverflow.com/questions/41373321/...
马特Bearson

5

您可以自己处理通知并显示自定义警报。Viber,Whatsapp和BisPhone等应用程序都使用这种方法。

第三方自定义警报的一个示例是CRToast

当您的应用程序位于前台时,尝试安排本地通知,您将看到没有显示股票iOS警报:

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

谢谢,不过只是使用普通的iOS通知警报来寻找答案。
pkamb

1
确定,但我认为你不能做到这一点,也看看这个链接:stackoverflow.com/questions/14872088/...
莫Farhand

6
@matt我试图将这个问题放在主题上:在前台显示股票iOS警报。大量其他“最佳吐司警报框架”问题。“不,你不能显示在前台的iOS警报”的答案是完全可以接受的,我会接受的答案,直到这可能的的iOS的未来版本。
pkamb

4

Swift 3版本

当应用程序处于前台时,这将显示警报。

if #available(iOS 10.0, *)
{
    // need to setup the global notification delegate somewhere when your app starts
    //
    UNUserNotificationCenter.current().delegate = applicationDelegate

    // to show a message
    //
    let content = UNMutableNotificationContent()
    content.body = "MESSAGE"

    let request = UNNotificationRequest(identifier: "fred", content: content, trigger: nil)
    UNUserNotificationCenter.current().add(request)
    {
       error in // called when message has been sent

       debugPrint("Error: \(error)")
    }
}

ApplicationDelegate的实现 UNUserNotificationCenterDelegate

@available(iOS 10.0, *)
public func userNotificationCenter(_ center : UNUserNotificationCenter, willPresent notification : UNNotification, withCompletionHandler completionHandler : @escaping (UNNotificationPresentationOptions) -> Void)
{
    completionHandler([.alert]) // only-always show the alert
}

只是要确保...您是说,从iOS 10开始,您现在还可以像在后台一样在前台显示警报/横幅/声音吗?
亲爱的

我在哪里可以放置上面的编码部分?在收到remoteNotification吗?
user1960169

@Leslie Godwin将在iOS 8.0中使用它在前台显示通知
Dilip Tiwari

2

要显示本地通知,这是最佳选择。需要更少的代码来编写“ BRYXBanner” https://cocoapods.org/pods/BRYXBanner

let banner = Banner(title: "title", subtitle: "subtitle", image: UIImage(named: "addContact"), backgroundColor: UIColor(red:137.0/255.0, green:172.0/255.0, blue:2.0/255.0, alpha:1.000))
    banner.dismissesOnTap = true
    banner.show(duration: 1.0)

BRYXBanner框架似乎并没有使用股票 iOS的通知旗帜。
pkamb

1

如果您的部署目标> = iOS10,请使用UNUserNotification,如下所示-

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
    {
        // Change this to your preferred presentation option
        completionHandler([.alert, .sound])
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.