当你的应用程序打开并在前台显示一个股票 iOS 通知横幅?

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

这可能在应用程序商店的第三方应用程序?当你的应用程序是 打开并且在前景中时,你的应用程序的本地和/或推送通知?

当测试 我的应用时,只接收到 没有显示 iOS 警报 UI的通知。

但是在苹果的官方消息应用程序 中看到的这种行为:

Messages is open and in the foreground. Still shows a notification alert.

本地和远程通知编程指南表示:

当操作系统传递本地通知或远程通知时,目标应用程序是 而不是在前台奔跑,它可以通过 警报、图标徽章号或声音向用户显示通知。

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

所以是的,我们可以在前台接收到 通知资料,但是我看不到接收到 显示本地 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]
}

消息是否使用私有 API 在前台显示警报?

对于这个问题,请不要建议任何第三方“吐司”弹出提醒 on github 或等等。我只对使用 本地 iOS 系统本地通知或推送通知警报 UI 当您的应用程序打开并在前台时是否可以完成这项工作感兴趣。

108234 次浏览

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

第三方自定义警报的一个例子是 干杯

当你的应用程序在前台时,尝试调度一个本地通知,你会看到没有显示股票的 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];
}

编辑:

前景提醒现在可以在 iOS10! 请看这个答案

IOS9及以下版本:

当你的应用程序打开并显示在前台时,似乎不可能显示股票 iOS 通知警报。App 必须使用私有 API。

当应用程序已经在最前面时,系统不会显示任何警报,不会给应用程序的图标加徽章,也不会播放任何声音。UILocalNotification 文档

UIApplicationDelegate方法 威尔仍然被调用,允许您的应用程序响应本地或远程通知:

application:didReceiveLocalNotification:
application:didReceiveRemoteNotification:

然而,原生 iOS 通知提醒横幅 UI 将 不被展示,因为它是在苹果的 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

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

将以下所有内容添加到 AppGenerate.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) {




}];




}

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来使用通知提供的文本显示警报。

这是关键,因为它允许您显示警报 而你的应用程序是打开的,并在前台,这是 iOS10的新特性。


示例代码:

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

}

要显示本地通知,这是最好的选择。需要更少的代码来写“ 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)
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);
}];

我可以显示推送通知时,应用程序是活跃的 IOS10.

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

  2. 当从服务器接收远程通知时,发送本地通知并设置 KeyPath: should dAlertWhileAppIsForeground = True的值

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

IOS 10 + ,Swift 3 + :

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)
{
completionHandler([UNNotificationPresentationOptions.Alert,UNNotificationPresentationOptions.Sound,UNNotificationPresentationOptions.Badge])
}

如果需要访问 userInfo 的通知使用代码: notification.request.content.userInfo

只有在将属性 content-available:1添加到有效负载时才调用方法 userNotificationCenter(_:willPresent:withCompletionHandler:)。最终的有效载荷应该是这样的:

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

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

应用程序代表 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
}

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

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

下面是一个使用 SwiftUI 的版本,可以像这样修改你的主应用程序文件:

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