Afficher une bannière de notification iOS lorsque votre application est ouverte et au premier plan?

123

Lorsque l'application iOS Messages officielle d'Apple est ouverte et au premier plan, les nouveaux messages d'autres contacts déclenchent une bannière d'alerte de notification iOS native. Voir l'image ci-dessous.

Est-ce possible dans les applications tierces de l'App Store? Notifications locales et / ou push pour votre application lorsque votre application est ouverte et au premier plan ?

Lors du test de mon application , des notifications sont reçues mais aucune interface utilisateur d'alerte iOS n'est affichée .

Mais ce comportement est visible dans l'application Messages officiels d'Apple:

Les messages sont ouverts et au premier plan.  Affiche toujours une alerte de notification.

Le guide de programmation des notifications locales et distantes dit:

Lorsque le système d'exploitation délivre une notification locale ou à distance et que l'application cible est ne s'exécute pas au premier plan , il peut présenter la notification à l'utilisateur via une alerte , un numéro de badge d'icône ou un son.

Si l'application s'exécute dans le premier plan lorsque la notification est envoyée, le délégué d'application reçoit une notification locale ou distante.

Alors oui, nous pouvons recevoir les données de notification au premier plan. Mais je ne vois aucun moyen de présenter l'interface utilisateur d'alerte de notification iOS native .

-(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 utilise-t-il alors une API privée pour afficher l'alerte au premier plan?

Pour les besoins de cette question, veuillez ne pas suggérer d'alertes pop-up tierces "toast" sur github ou etc. Je ne suis intéressé que si cela peut être fait en utilisant l' interface utilisateur des alertes stock, iOS Local ou Push Notification pendant votre l'application est ouverte et au premier plan .

pkamb
la source

Réponses:

152

iOS 10 ajoute le UNUserNotificationCenterDelegateprotocole de gestion des notifications lorsque votre application est au premier plan.

Le UNUserNotificationCenterDelegateprotocole définit les méthodes de réception des notifications et de gestion des actions. Lorsque votre application est au premier plan, les notifications entrantes sont envoyées à votre objet délégué au lieu d'être affichées automatiquement à l'aide des interfaces système.

Rapide:

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

Objectif c:

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

Les indicateurs UNNotificationPresentationOptions vous permettent de spécifier UNNotificationPresentationOptionAlertd'afficher une alerte à l'aide du texte fourni par la notification.

Ceci est essentiel car il vous permet d'afficher l'alerte lorsque votre application est ouverte et au premier plan , ce qui est nouveau pour iOS 10.


Exemple de code:

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
la source
4
Pourriez-vous fournir un exemple de code de travail dans lequel une notification de premier plan entrante est affichée par le système comme si l'application était en arrière-plan?
azmeuk
1
@azmeuk Vérifiez ma réponse ...
chengsam
8
N'oubliez pas d'ajouter UNUserNotificationCenter.current().delegate = selfla méthode application(_:willFinishLaunchingWithOptions:)ouapplication(_:didFinishLaunchingWithOptions:)
Deniss Fedotovs
3
Assurez-vous également que vous n'avez pas votre appareil en mode Ne pas déranger sinon les notifications seront visibles dans le centre de notifications, mais ne seront pas présentées au premier plan sur votre application
Jadent
2
mes 2 cents: ne manquez pas: importez UserNotifications. !
ingconti
95

Pour afficher le message de la bannière lorsque l'application est au premier plan, utilisez la méthode suivante.

iOS 10+, Swift 3+ :

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.alert, .badge, .sound])
}
chengsam
la source
1
Wow, partout où j'ai lu, les gens disaient que ce n'était pas possible. Je suis tellement content d'avoir trouvé cette réponse, cela fonctionne exactement comme je m'y attendais! Lorsque l'application est en cours d'exécution, les notifications push s'affichent désormais exactement comme elles le feraient si l'application était en arrière-plan. Je vous remercie!
Torre Lasley
1
Où va cet extrait? Dans l'appDelegate ou ailleurs?
Yoav R.
@YoavR. AppDelegate
chengsam
J'ai utilisé le même code. Mais je ne sais pas pourquoi la notification ne s'affiche pas lorsque l'application était au premier plan.
Boominadha Prakash M
3
Chengsam, vous voudrez peut-être corriger ceci: il n'est pas nécessaire de le mettre dans le fichier AppDelegate. Il doit être mis pour n'importe quel objet conforme UNUserNotificationCenterDelegate. Cela dit, la plupart des développeurs les mettent en AppDelegateconformité UNUserNotificationCenterDelegate. @YoavR.
Honey
16

ÉDITER:

Les alertes au premier plan sont désormais possibles dans iOS 10! Veuillez voir cette réponse .

Pour iOS 9 et inférieur:

Il ne semble pas possible d'afficher l'alerte de notification de stock iOS lorsque votre application est ouverte et au premier plan. Messages.app doit utiliser une API privée.

Le système n'affiche aucune alerte, n'insigne pas l'icône de l'application ou ne joue aucun son lorsque l'application est déjà au premier plan. - Documents UILocalNotification

Les UIApplicationDelegateméthodes seront toujours appelées, permettant à votre application de répondre à la notification locale ou distante:

application:didReceiveLocalNotification:
application:didReceiveRemoteNotification:

Cependant, l'interface utilisateur de la bannière d'alerte de notification iOS native stock ne sera pas affichée telle qu'elle est dans Messages.app d'Apple, qui doit utiliser une API privée.

Le mieux que vous puissiez faire est de lancer votre propre bannière d'alerte ou d'utiliser un framework existant:

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

J'ai ouvert un radar pour ce comportement ici: rdar://22313177

pkamb
la source
3
Comment WhatsApp et d'autres applications célèbres font-elles cela, alors?
Machado
@tardoandre a une capture d'écran? Je suppose que c'est en imitant l'alerte stock iOS dans leurs propres vues.
pkamb
2
Vous devez inclure un lien pour toastAlertFromGithubsi vous suggérez d'utiliser cette bibliothèque tierce!
Ketan Parmar
14

Pour afficher les notifications lorsque l'application est ouverte, nous devons la gérer manuellement. Donc, ce que je fais ci-dessous est de gérer la notification une fois reçue.

Ajoutez tout ci-dessous dans AppDelegate.m

  1. Traiter l'appel pour notification
  2. Créez une vue, ajoutez AppIcon, un message de notification et affichez-le sous forme d'animation
  3. Ajouter un reconnaisseur tactile pour supprimer si touché ou supprimer en 5 secondes avec animation.

Faites-moi savoir si c'est une bonne solution. Cela a bien fonctionné pour moi mais je ne sais pas si c'est la bonne façon.

- (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
la source
3
Cela peut être une bonne réponse pour créer votre propre alerte, mais cela ne montre pas l' alerte Stock iOS comme indiqué dans la capture d'écran.
pkamb
Salut, merci pour vos aimables paroles. Oui, cela ne ressemblera pas à ça (si vous parlez de l'apparence), car celui montré ci-dessus dans l'image est une notification iOS et celui via le code est personnalisé. Nous pouvons peut-être reproduire les regards dans la vue. Je pense que WhatsApp en a un joli avec un arrière-plan flou, etc.
Hafeez
1
Quelqu'un a voté contre :(. Ce serait bien d'entendre pourquoi!?. Merci.
Hafeez
2
Je l'ai fait, car le code de cette réponse (aussi agréable que cela puisse être) ne répond pas vraiment à la question posée: afficher une bannière de toast iOS stock dans l'application. Il y a d'autres questions sur SO où cette réponse serait excellente.
pkamb
1
Merci pkamb pour la clarification, cela a du sens. J'ai raté le mot «stock», je suppose.
Hafeez
10

Voici le code pour recevoir une notification push lorsque l'application est au premier plan ou en phase ouverte, iOS 10 et 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 vous devez accéder à userInfo de notification, utilisez le code: notification.request.content.userInfo

La méthode userNotificationCenter(_:willPresent:withCompletionHandler:)n'est appelée que si vous ajoutez à la charge utile l'attribut content-available:1. La charge utile finale devrait être quelque chose comme:

{
     "aps":{
          "alert":"Testing.. (7)",
          "badge":1,"sound":"default"
     },
     "content-available":1
}
Kavin Kumar Arumugam
la source
1
userNotificationCenter(_:willPresent:withCompletionHandler:)sera appelée lorsque votre application s'exécute au premier plan. Cela n'a donc PAS d'importance avec " content-available ", qui est lié à " background fetch ".
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);
}];

Je peux afficher une notification push lorsque l'application est active pour iOS 10.

  1. La notification push du serveur doit être silencieuse .

  2. Lorsque vous recevez une notification à distance du serveur, vous envoyez une notification locale et définissez la valeur de keyPath: shouldAlwaysAlertWhileAppIsForeground = True

Nguyen Loc
la source
dans Swift 2 - il est content.setValue("YES", forKeyPath: "shouldAlwaysAlertWhileAppIsForeground"), non? (avec "Oui" et pas vrai)
Yoav R.
Attention: cela plantera votre application sous iOS 12. Voir la discussion ici: stackoverflow.com/questions/41373321/...
Matt Bearson
5

Vous pouvez gérer vous-même la notification et afficher une alerte personnalisée. Des applications telles que Viber, Whatsapp et BisPhone utilisent cette approche.

Un exemple d'alerte personnalisée tierce est CRToast .

Essayez de planifier une notification locale pendant que votre application est au premier plan, et vous verrez qu'aucune alerte de stock iOS n'est affichée:

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
la source
Merci, mais je cherche simplement des réponses à l'aide de l'alerte de notification iOS.
pkamb
1
ok mais je pense que vous ne pouvez pas le faire, regardez également ce lien: stackoverflow.com/questions/14872088/...
Mo Farhand
6
@matt J'essaie de garder cette question sur le sujet: afficher l'alerte stock iOS au premier plan. Beaucoup d'autres questions sur le "meilleur cadre d'alerte toast". Une réponse "Non, vous ne pouvez pas afficher l'alerte iOS au premier plan" serait parfaitement acceptable, et j'accepterai cette réponse jusqu'à ce que cela soit possible dans une future version d'iOS.
pkamb
4

Version Swift 3

Cela affiche une alerte lorsque l'application est au premier plan.

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

Mise en œuvre par 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
la source
juste pour être sûr ... voulez-vous dire que depuis iOS 10, vous pouvez maintenant également afficher des alertes / bannières / sons au premier plan comme vous le faites en arrière-plan?
Honey
Où puis-je mettre la partie de codage ci-dessus? dans a reçuRemoteNotification?
user1960169
@Leslie Godwin fonctionnera-t-il pour iOS 8.0 pour afficher les notifications au premier plan
Dilip Tiwari
2

Pour afficher la notification locale, c'est la meilleure option. besoin de moins de code pour écrire "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
la source
Ce BRYXBannercadre ne semble pas utiliser le stock bannière de notification iOS.
pkamb
1

Si votre cible de déploiement> = iOS10, utilisez UNUserNotification comme ci-dessous-

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