Exibindo um banner de notificação do iOS quando seu aplicativo está aberto e em primeiro plano?

123

Quando o aplicativo oficial iOS Messages da Apple é aberto e, em primeiro plano, novas mensagens de outros contatos acionam um banner nativo de alerta de notificação do iOS. Veja a imagem abaixo.

Isso é possível em aplicativos de terceiros na App Store? Notificações locais e / ou push para seu aplicativo enquanto ele estiver aberto e em primeiro plano ?

Ao testar meu aplicativo , as notificações são recebidas, mas nenhuma interface de usuário de alerta do iOS é mostrada .

Mas esse comportamento é visto no aplicativo oficial Mensagens da Apple:

As mensagens estão abertas e em primeiro plano.  Ainda mostra um alerta de notificação.

O Guia de programação de notificação local e remota diz:

Quando o sistema operacional entrega uma notificação local ou remota e o aplicativo de destino não está sendo executado em primeiro plano , ele pode apresentar a notificação ao usuário por meio de um alerta , número do emblema do ícone ou som.

Se o aplicativo estiver sendo executado em primeiro plano quando a notificação for entregue, o representante do aplicativo receberá uma notificação local ou remota.

Então, sim, podemos receber os dados da notificação em primeiro plano. Mas não vejo como apresentar a interface do usuário de alerta de notificação nativa do 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]
}

As Mensagens estão usando uma API privada para exibir o alerta em primeiro plano?

Para os fins desta pergunta, não sugira nenhum alerta pop-up de "brinde" de terceiros no github ou etc. Estou interessado apenas se isso puder ser feito usando a interface do usuário nativa local , iOS Local ou Push Notification do iOS, enquanto o seu aplicativo está aberto e em primeiro plano .

pkamb
fonte

Respostas:

152

O iOS 10 adiciona o UNUserNotificationCenterDelegateprotocolo para lidar com notificações enquanto o aplicativo está em primeiro plano.

O UNUserNotificationCenterDelegateprotocolo define métodos para receber notificações e manipular ações. Quando o aplicativo está em primeiro plano, as notificações de chegada são entregues ao objeto delegado em vez de exibidas automaticamente usando as interfaces do sistema.

Rápido:

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

Objetivo-C:

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

o sinalizadores UNNotificationPresentationOptions permitem especificarUNNotificationPresentationOptionAlert a exibição de um alerta usando o texto fornecido pela notificação.

Esta é a chave, pois permite exibir o alerta enquanto o aplicativo está aberto e em primeiro plano , o que é novo no iOS 10.


Código de amostra:

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
fonte
4
Você poderia fornecer uma amostra de código funcional em que uma notificação de primeiro plano recebida seja exibida pelo sistema como se o aplicativo estivesse em segundo plano?
azmeuk
1
@azmeuk Verifique minha resposta ...
chengsam 23/11
8
Não se esqueça de adicionar UNUserNotificationCenter.current().delegate = selfo método application(_:willFinishLaunchingWithOptions:)ouapplication(_:didFinishLaunchingWithOptions:)
Deniss Fedotovs
3
Também certifique-se que você não tem o dispositivo em modo de Do Not Disturb caso contrário, as notificações serão visíveis no Centro de Notificações, mas não será apresentado em primeiro plano sobre a sua aplicação
Jadent
2
meus 2 centavos: não perca: importe UserNotifications. !
ingconti
94

Para exibir a mensagem de faixa enquanto o aplicativo estiver em primeiro plano, use o seguinte método.

iOS 10+, Swift 3+ :

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.alert, .badge, .sound])
}
chengsam
fonte
1
Uau, em todos os lugares que leio as pessoas dizem que isso não é possível. Estou tão feliz que encontrei esta resposta, ela funciona exatamente como eu esperava! Quando o aplicativo está em execução, as notificações por push agora são exibidas exatamente como seriam se o aplicativo estivesse em segundo plano. Obrigado!
Torre Lasley
1
Para onde esse trecho vai? No appDelegate, ou em outro lugar?
Yoav R.
@YoavR. AppDelegate
chengsam
Eu usei o mesmo código. Mas não sei por que a notificação não é exibida quando o aplicativo estava em primeiro plano.
Boominadha Prakash M
2
Chengsam você pode querer corrigir isso: Ele não precisa ser colocado no AppDelegate. Tem que ser colocado para qualquer objeto que esteja em conformidade UNUserNotificationCenterDelegate. Dito isto, a maioria dos desenvolvedores faz a sua AppDelegateconformidade UNUserNotificationCenterDelegate. @YoavR.
Honey
16

EDITAR:

Agora, alertas de primeiro plano são possíveis no iOS 10! Por favor, veja esta resposta .

Para iOS 9 e abaixo:

Não parece possível mostrar o alerta de notificação padrão do iOS quando o aplicativo está aberto e em primeiro plano. O Messages.app deve estar usando uma API privada.

O sistema não exibe nenhum alerta, marca o ícone do aplicativo ou reproduz qualquer som quando o aplicativo já está na frente. - Documentos UILocalNotification

Os UIApplicationDelegatemétodos irá ainda ser chamado, permitindo sua aplicação para responder à notificação local ou remoto:

application:didReceiveLocalNotification:
application:didReceiveRemoteNotification:

No entanto, a interface do usuário do banner de alerta de notificação nativo do iOS não será mostrada como está no Messages.app da Apple, que deve estar usando uma API privada.

O melhor que você pode fazer é lançar seu próprio banner de alerta ou usar uma estrutura existente:

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

Eu abri um radar para esse comportamento aqui: rdar://22313177

pkamb
fonte
3
Como o whatsapp e outros aplicativos famosos fazem isso, então?
Machado
@tardoandre tem uma captura de tela? Suponho que simule o alerta padrão do iOS em suas próprias visualizações.
Pkamb #
2
Você deve incluir o link para, toastAlertFromGithubse você está sugerindo a utilização desta biblioteca de terceiros!
Ketan Parmar
14

Para mostrar notificações enquanto o aplicativo está aberto, precisamos manipulá-lo manualmente. Então, o que estou fazendo abaixo é lidar com a notificação uma vez recebida.

Adicione tudo abaixo em AppDelegate.m

  1. Lidar com chamada para notificar
  2. Crie uma visualização, adicione AppIcon, mensagem de notificação e mostre-a como uma animação
  3. Adicione o reconhecedor de toque para remover se tocado ou remova em 5 segundos com animação.

Deixe-me saber se esta é uma solução aceitável. Funcionou bem para mim, mas não tenho certeza se este é o caminho certo.

- (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
fonte
3
Essa pode ser uma boa resposta para criar seu próprio alerta, mas não está mostrando o Alerta do iOS para ações, como mostra a captura de tela.
Pkamb 07/06
Olá, obrigado por suas amáveis ​​palavras. Sim, não ficará assim (se você estiver falando sobre a aparência), pois o mostrado acima na imagem é uma notificação do iOS e o via código é personalizado. Talvez possamos replicar a aparência da exibição. Eu acho que WhatsApp tem um puro um olhando com fundo do borrão etc.
Hafeez
1
Alguém para baixo votado :( Seria bom ouvir isso, obrigado.!?..
Hafeez
2
Eu fiz, como o código nesta resposta (agradável embora possa ser) realmente não responder à pergunta: Mostrando um banco de iOS brinde bandeira dentro do aplicativo. Existem outras perguntas sobre SO em que essa resposta seria ótima.
pkamb
1
Obrigado pkamb por esclarecer, faz sentido. Eu perdi a palavra "estoque", eu acho.
Hafeez
10

Aqui está o código para receber a notificação por push quando o aplicativo estiver em primeiro plano ou em estágio aberto, iOS 10 e 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])
}

Se você precisar acessar as informações do usuário da notificação, use o código: notification.request.content.userInfo

O método userNotificationCenter(_:willPresent:withCompletionHandler:)só é chamado se você adicionar a carga útil atributo content-available:1. A carga final deve ser algo como:

{
     "aps":{
          "alert":"Testing.. (7)",
          "badge":1,"sound":"default"
     },
     "content-available":1
}
Kavin Kumar Arumugam
fonte
1
userNotificationCenter(_:willPresent:withCompletionHandler:)será chamado quando seu aplicativo estiver sendo executado em primeiro plano. Portanto, NÃO importa com " conteúdo disponível ", relacionado à " busca em segundo plano ".
precisa saber é o seguinte
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);
}];

Posso mostrar notificação por push quando o aplicativo está ativo para iOS 10.

  1. A notificação por push do servidor deve ser silenciosa .

  2. Ao receber uma notificação remota do servidor, você envia uma notificação local e define o valor para keyPath: shouldAlwaysAlertWhileAppIsForeground = True

Nguyen Loc
fonte
no rápido 2 - é content.setValue("YES", forKeyPath: "shouldAlwaysAlertWhileAppIsForeground"), certo? (com "Sim" e não é verdade)
Yoav R.
Cuidado: Isso
travará
5

Você pode lidar com a notificação e mostrar um alerta personalizado. Aplicativos como Viber, Whatsapp e BisPhone usam essa abordagem.

Um exemplo de alerta personalizado de terceiros é CRToast .

Tente agendar uma notificação local enquanto o aplicativo estiver em primeiro plano e você verá que nenhum alerta do iOS para ações é mostrado:

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
fonte
Obrigado, mas apenas procurando respostas usando o alerta de notificação padrão do iOS.
Pkamb
1
ok, mas acho que você não pode fazê-lo, veja também este link: stackoverflow.com/questions/14872088/…
Mo Farhand
6
@matt Estou tentando manter esta pergunta no tópico: mostrando o alerta de ações do iOS em primeiro plano. Muitas outras perguntas sobre o "melhor quadro de alerta de brinde". Uma resposta "Não, você não pode mostrar o alerta do iOS em primeiro plano" seria perfeitamente aceitável, e eu aceitarei essa resposta até que isso seja possível em uma versão futura do iOS.
pkamb
4

Versão Swift 3

Isso mostra um alerta quando o aplicativo está em primeiro 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)")
    }
}

A implementação do 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
fonte
só para ter certeza ... você quer dizer que desde o iOS 10 agora você também pode mostrar alertas / banners / sons em primeiro plano, assim como em segundo plano?
Querida
Onde posso colocar a parte de codificação acima? em receiveRemoteNotification?
User1960169
@Leslie Godwin ele vai trabalhar para iOS 8.0 para mostrar notificações no Primeiro Plano
Dilip Tiwari
2

Para mostrar a notificação local, esta é a melhor opção. precisa de menos código para escrever "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
fonte
Essa BRYXBannerestrutura não parece usar o banner de notificação do iOS para ações .
Pkamb # 6/16
1

Se o seu destino de implantação> = iOS10, use UNUserNotification como abaixo:

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