【问题标题】:Displaying a stock iOS notification banner when your app is open and in the foreground?当您的应用程序打开并在前台显示股票 iOS 通知横幅?
【发布时间】:2015-08-31 09:40:45
【问题描述】:

当 Apple 的官方 iOS 消息应用程序打开并位于前台时,来自其他联系人的新消息会触发原生 iOS 通知提醒横幅。见下图。

这在 App Store 上的 3rd 方应用程序中是否可行?当您的应用打开并在前台时为您的应用提供本地和/或推送通知?

在测试我的应用时,会收到通知,但没有显示 iOS 警报 UI

但这种行为在 Apple 的官方消息应用中可见:

Local and Remote Notification Programming Guide 说:

当操作系统发送本地通知或远程通知,而目标应用未在前台运行时,它可以通过警报向用户呈现通知、图标徽章编号或声音。

如果应用在发送通知时在前台运行,则应用委托会收到本地或远程通知。

所以是的,我们可以在前台接收通知数据。但我认为没有办法呈现原生 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 等上建议任何第 3 方“吐司”弹出警报。我只对使用 stock,原生 iOS 本地或推送通知提醒 UI 当您的应用程序打开并在前台时

【问题讨论】:

    标签: ios uikit apple-push-notifications uilocalnotification toast


    【解决方案1】:

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

    第 3 方自定义警报的一个示例是 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 通知警报寻找答案。
    • 好的,但我认为你做不到,也看看这个链接:stackoverflow.com/questions/14872088/…
    • @matt 我试图将这个问题保持在主题上:在前台显示股票 iOS 警报。许多其他“最佳吐司警报框架”问题。 “不,你不能在前台显示 iOS 警报”的答案是完全可以接受的,我会接受这个答案,直到在未来的 iOS 版本中成为可能。
    【解决方案2】:

    编辑:

    现在可以在 iOS 10 中使用前台警报! Please see this answer.

    适用于 iOS 9 及更低版本:

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

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

    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

    【讨论】:

    • whatsapp 和其他著名应用程序是如何做到这一点的呢?
    • @tardoandre 有截图吗?我认为这是通过在他们自己的视图中模仿股票 iOS 警报。
    • 如果您建议使用此第三方库,则应包含toastAlertFromGithub 的链接!
    【解决方案3】:

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

    在 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) {
    
    
    }];
    
    
    }
    

    【讨论】:

    • 这可能是创建您自己的警报的好答案,但它没有显示 Stock iOS 警报,如屏幕截图所示。
    • 您好,谢谢您的客气话。是的,它看起来不像那样(如果您在谈论外观),因为上图中显示的是 iOS 通知,而通过代码的通知是自定义的。我们也许可以复制视图中的外观。我认为 WhatsApp 看起来很整洁,带有背景模糊等。
    • 有人投了反对票 :(。很高兴听到为什么!?。谢谢。
    • 我做到了,因为这个答案中的代码(尽管它可能很好)并没有真正回答所提出的问题:在应用程序中显示 stock iOS toast 横幅。还有其他关于 SO 的问题,这个答案会很好。
    • 感谢 pkamb 的澄清,这是有道理的。我猜错了“股票”这个词。
    【解决方案4】:

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

    【讨论】:

    • 您能否提供一个工作代码示例,其中系统显示传入的前台通知,就像应用程序在后台一样?
    • @azmeuk 检查我的answer...
    • 不要忘记在application(_:willFinishLaunchingWithOptions:)application(_:didFinishLaunchingWithOptions:) 方法中添加UNUserNotificationCenter.current().delegate = self
    • 还要确保您的设备不在Do Not Disturb mode 中,否则通知将在通知中心可见,但不会显示在应用程序的前台
    • 我的 2 美分:不要错过:导入 UserNotifications。 !
    【解决方案5】:

    要显示本地通知,这是最好的选择。需要更少的代码来编写“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 框架似乎没有使用stock iOS 通知横幅。
    【解决方案6】:
    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

    3. 的值

    【讨论】:

    • 在 swift 2 中 - 它是 content.setValue("YES", forKeyPath: "shouldAlwaysAlertWhileAppIsForeground") ,对吗? (用“是”而不是真的)
    • 警告:这将使您的应用在 iOS 12 下崩溃。请参阅此处的讨论:stackoverflow.com/questions/41373321/…
    【解决方案7】:

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

    iOS 10+、Swift 3+

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

    【讨论】:

    • 哇,我读到的所有地方都有人说这是不可能的。我很高兴我找到了这个答案,它完全符合我的预期!当应用程序运行时,推送通知现在显示的方式与应用程序在后台时完全一样。谢谢!
    • 这个 sn-p 去哪儿了?在 appDelegate 中,还是在其他地方?
    • @YoavR。 AppDelegate
    • Chengsam 您可能需要更正此问题:它不必放在AppDelegate 中。它必须用于符合UNUserNotificationCenterDelegate 的任何对象。话虽如此,大多数开发人员使他们的AppDelegate 符合UNUserNotificationCenterDelegate。 @YoavR。
    • 这可以是有条件的吗?我的意思是假设我正在显示聊天通知。如果聊天屏幕打开,我可以不显示通知,否则显示吗?
    【解决方案8】:

    这是在应用程序处于前台或打开阶段,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
    }
    

    【讨论】:

    • userNotificationCenter(_:willPresent:withCompletionHandler:) 将在您的应用程序在前台运行时被调用。所以与“content-available”无关,它与“background fetch”相关。
    【解决方案9】:

    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 开始,您现在也可以像在后台一样在前台显示警报/横幅/声音了吗?
    • 我可以把上面的编码部分放在哪里?在没有收到远程通知?
    • @Leslie Godwin 是否适用于 ios 8.0 在前台显示通知
    【解决方案10】:

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

    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                    willPresent notification: UNNotification,
                                    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
        {
            // Change this to your preferred presentation option
            completionHandler([.alert, .sound])
        }
    

    【讨论】:

    • 您能解释一下这是如何工作的吗?比如这个函数什么时候被调用?
    【解决方案11】:

    这是一个适用于 SwiftUI 的版本。修改你的主 App 文件:

    import SwiftUI
    import UserNotifications
    
    let appDelegate = AppDelegate()
    
    @main
    struct MyApp: App {
        let persistenceController = PersistenceController.shared
        
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .onAppear() {
                        UNUserNotificationCenter.current().delegate = appDelegate
                    }
                    .environment(\.managedObjectContext, persistenceController.container.viewContext)
            }
        }
    }
    
    class AppDelegate: UIResponder, UIApplicationDelegate {
        
    }
    
    // Conform to UNUserNotificationCenterDelegate
    extension AppDelegate: UNUserNotificationCenterDelegate {
        func userNotificationCenter(_ center: UNUserNotificationCenter,
                                    willPresent notification: UNNotification,
                                    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
        {
            completionHandler([.alert, .badge, .sound])
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-10
      • 1970-01-01
      • 1970-01-01
      • 2018-05-04
      相关资源
      最近更新 更多