¿Está mostrando un banner de notificación de iOS cuando su aplicación está abierta y en primer plano?

123

Cuando la aplicación de mensajes iOS oficial de Apple está abierta y en primer plano, los mensajes nuevos de otros contactos activan un banner de alerta de notificación original de iOS. Vea la imagen a continuación.

¿Es esto posible en aplicaciones de terceros en la App Store? Notificaciones locales y / o push para su aplicación mientras su aplicación está abierta y en primer plano ?

Al probar mi aplicación , se reciben notificaciones pero no se muestra la interfaz de usuario de alerta de iOS .

Pero este comportamiento se ve en la aplicación de mensajes oficial de Apple:

Los mensajes están abiertos y en primer plano.  Todavía muestra una alerta de notificación.

La Guía de programación de notificaciones locales y remotas dice:

Cuando el sistema operativo entrega una notificación local o una notificación remota y la aplicación de destino no se está ejecutando en primer plano , puede presentar la notificación al usuario a través de un alerta , un número de placa de icono o un sonido.

Si la aplicación se está ejecutando en primer plano cuando se envía la notificación, el delegado de la aplicación recibe una notificación local o remota.

Entonces, sí, podemos recibir los datos de notificación mientras estamos en primer plano. Pero no veo forma de presentar la interfaz de usuario de alerta de notificación nativa de iOS .

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

¿Entonces Messages usa una API privada para mostrar la alerta mientras está en primer plano?

A los efectos de esta pregunta, por favor, no sugieren ninguna tercera parte "tostadas" alertas emergentes en GitHub o etc. Sólo me interesa si esto se puede hacer usando el archivo, iOS nativa local o de notificación Push alertas de interfaz de usuario , mientras que su la aplicación está abierta y en primer plano .

pkamb
fuente

Respuestas:

152

iOS 10 agrega el UNUserNotificationCenterDelegateprotocolo para manejar notificaciones mientras su aplicación está en primer plano.

El UNUserNotificationCenterDelegateprotocolo define métodos para recibir notificaciones y manejar acciones. Cuando su aplicación está en primer plano, las notificaciones que llegan se envían a su objeto delegado en lugar de mostrarse automáticamente mediante las interfaces del sistema.

Rápido:

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

C objetivo:

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

Los indicadores UNNotificationPresentationOptions le permiten especificar UNNotificationPresentationOptionAlertque se muestre una alerta utilizando el texto proporcionado por la notificación.

Esto es clave, ya que le permite mostrar la alerta mientras su aplicación está abierta y en primer plano , lo cual es nuevo para iOS 10.


Código de muestra:

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)
    }
    
}
pkamb
fuente
4
¿Podría proporcionar una muestra de código de trabajo donde el sistema muestre una notificación de primer plano entrante como si la aplicación estuviera en segundo plano?
azmeuk
1
@azmeuk Comprueba mi respuesta ...
chengsam
8
No olvides agregar UNUserNotificationCenter.current().delegate = selfel método application(_:willFinishLaunchingWithOptions:)oapplication(_:didFinishLaunchingWithOptions:)
Deniss Fedotovs
3
También asegúrese de que no tiene su dispositivo en el modo No molestar, de lo contrario, las notificaciones serán visibles en el Centro de notificaciones, pero no se presentarán en primer plano sobre su aplicación
Jadent
2
mis 2 centavos: no se pierda: importar UserNotifications. !
ingconti
95

Para mostrar un mensaje de banner mientras la aplicación está en primer plano, use el siguiente método.

iOS 10+, Swift 3+ :

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.alert, .badge, .sound])
}
Chengsam
fuente
1
Vaya, dondequiera que leí, la gente decía que esto no era posible. Estoy tan contento de haber encontrado esta respuesta, ¡funciona exactamente como esperaba! Cuando la aplicación se está ejecutando, las notificaciones push ahora se muestran exactamente como lo harían si la aplicación estuviera en segundo plano. ¡Gracias!
Torre Lasley
1
¿A dónde va este fragmento? ¿En appDelegate o en otro lugar?
Yoav R.
@YoavR. AppDelegate
chengsam
He usado el mismo código. Pero no sé por qué la notificación no se muestra cuando la aplicación estaba en primer plano.
Boominadha Prakash M
3
Chengsam, es posible que desee corregir esto: no tiene que estar en el formato AppDelegate. Tiene que ponerse para cualquier objeto que se ajuste UNUserNotificationCenterDelegate. Dicho esto, la mayoría de los desarrolladores se AppDelegateajustan a UNUserNotificationCenterDelegate. @YoavR.
Miel
16

EDITAR:

¡Las alertas en primer plano ahora son posibles en iOS 10! Por favor mira esta respuesta .

Para iOS 9 y versiones anteriores:

No parece posible mostrar la alerta de notificación de iOS estándar cuando su aplicación está abierta y en primer plano. Messages.app debe utilizar una API privada.

El sistema no muestra ninguna alerta, no identifica el ícono de la aplicación ni reproduce ningún sonido cuando la aplicación ya está al frente. - Documentos de UILocalNotification

Se seguirán llamando a los UIApplicationDelegatemétodos , lo que permitirá que su aplicación responda a la notificación local o remota:

application:didReceiveLocalNotification:
application:didReceiveRemoteNotification:

Sin embargo, la interfaz de usuario de banner de alerta de notificación de iOS nativa de stock no se mostrará como en la aplicación Messages.app de Apple, que debe estar usando una API privada.

Lo mejor que puede hacer es lanzar su propio banner de alerta o utilizar un marco existente:

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

He abierto un radar para este comportamiento aquí: rdar://22313177

pkamb
fuente
3
Entonces, ¿cómo hacen eso WhatsApp y otras aplicaciones famosas?
Machado
@tardoandre tiene una captura de pantalla? Supongo que es imitando la alerta de iOS estándar en sus propias vistas.
pkamb
2
¡Debe incluir un enlace toastAlertFromGithubsi está sugiriendo el uso de esta biblioteca de terceros!
Ketan Parmar
14

Para mostrar notificaciones mientras la aplicación está abierta, debemos manejarla manualmente. Entonces, lo que estoy haciendo a continuación es manejar la notificación una vez recibida.

Agregue todo a continuación en AppDelegate.m

  1. Manejar llamada para notificar
  2. Cree una vista, agregue AppIcon, mensaje de notificación y muéstrelo como una animación
  3. Agregue el reconocedor táctil para eliminar si se toca o eliminar en 5 segundos con animación.

Avísame si esta es una buena solución. Me funcionó bien, pero no estoy seguro de si es la forma correcta.

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


}];


}
Hafeez
fuente
3
Esta puede ser una buena respuesta para crear su propia alerta, pero no muestra la alerta de iOS de stock como se muestra en la captura de pantalla.
pkamb
Hola, gracias por tus amables palabras. Sí, no se verá así (si está hablando de la apariencia) ya que la que se muestra arriba en la imagen es una notificación de iOS y la que se realiza a través del código es personalizada. Quizás podamos replicar el aspecto en la vista. Creo que WhatsApp tiene un aspecto elegante con fondo borroso, etc.
Hafeez
1
Alguien votó en contra :(. ¡Sería bueno saber por qué!?. Gracias.
Hafeez
2
Lo hice, ya que el código en esta respuesta (agradable aunque puede ser) realmente no responder a la pregunta planteada: mostrando un archivo IOS tostadas bandera dentro de la aplicación. Hay otras preguntas sobre SO donde esta respuesta sería excelente.
pkamb
1
Gracias pkamb por aclararlo, tiene sentido. Me perdí la palabra "stock", supongo.
Hafeez
10

Aquí está el código para recibir notificaciones push cuando la aplicación está en primer plano o en etapa abierta, iOS 10 y 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])
}

Si necesita acceder a la información de usuario del código de uso de notificación: notification.request.content.userInfo

El método userNotificationCenter(_:willPresent:withCompletionHandler:) solo se llama si agrega a la carga útil el atributo content-available:1. La carga útil final debería ser algo como:

{
     "aps":{
          "alert":"Testing.. (7)",
          "badge":1,"sound":"default"
     },
     "content-available":1
}
Kavin Kumar Arumugam
fuente
1
userNotificationCenter(_:willPresent:withCompletionHandler:)se llamará cuando su aplicación se esté ejecutando en primer plano. Por lo tanto, NO importa con " contenido disponible ", que está relacionado con " búsqueda en segundo plano ".
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);
}];

Puedo mostrar notificaciones automáticas cuando la aplicación está activa para iOS 10.

  1. La notificación push del servidor debe ser silenciosa .

  2. Cuando recibe una notificación remota del servidor, envía una notificación local y establece el valor de keyPath: shouldAlwaysAlertWhileAppIsForeground = True

Nguyen Loc
fuente
en Swift 2 - lo es content.setValue("YES", forKeyPath: "shouldAlwaysAlertWhileAppIsForeground"), ¿ verdad ? (con "Sí" y no es cierto)
Yoav R.
Precaución: Esto bloqueará su aplicación en iOS 12. Vea la discusión aquí: stackoverflow.com/questions/41373321/…
Matt Bearson
5

Puede manejar la notificación usted mismo y mostrar una alerta personalizada. Aplicaciones como Viber, Whatsapp y BisPhone utilizan este enfoque.

Un ejemplo de alerta personalizada de terceros es CRToast .

Intente programar una notificación local mientras su aplicación está en primer plano, y verá que no se muestra ninguna alerta de stock de 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];
}
Mo Farhand
fuente
Gracias, pero solo busco respuestas usando la alerta de notificación de iOS.
pkamb
1
ok, pero creo que no puedes hacerlo, mira también este enlace: stackoverflow.com/questions/14872088/…
Mo Farhand
6
@matt Estoy intentando mantener esta pregunta sobre el tema: mostrar la alerta de iOS en primer plano. Un montón de otras preguntas sobre el "mejor marco de alerta de tostadas". Una respuesta de "No, no se puede mostrar la alerta de iOS en primer plano" sería perfectamente aceptable, y aceptaré esa respuesta hasta que esto sea posible en una versión futura de iOS.
pkamb
4

Versión Swift 3

Esto muestra una alerta cuando la aplicación está en primer plano.

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

Aplicación de ApplicationDelegate de 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
}
Leslie Godwin
fuente
solo para estar seguro ... ¿quiere decir que desde iOS 10 ahora también puede mostrar alertas / pancartas / sonidos en primer plano como lo hace en segundo plano?
Cariño
¿Dónde puedo poner la parte de codificación anterior? ¿Recibió una notificación remota?
user1960169
@Leslie Godwin, ¿funcionará para ios 8.0 para mostrar notificaciones en primer plano
Dilip Tiwari
2

Para mostrar una notificación local, esta es la mejor opción. necesita menos código para escribir "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)
Mantosh Kumar
fuente
Esto BRYXBannerno parece marco para utilizar el de la bandera de aviso IOS.
pkamb
1

Si su objetivo de implementación> = iOS10, use UNUserNotification como se muestra a continuación-

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