Stai visualizzando un banner di notifica iOS di serie quando la tua app è aperta e in primo piano?


123

Quando l'app iOS Messaggi ufficiale di Apple è aperta e in primo piano, i nuovi messaggi di altri contatti attivano un banner di avviso di notifica iOS nativo. Vedi immagine sotto.

È possibile in app di terze parti sull'App Store? Notifiche locali e / o push per la tua app mentre la tua app è aperta e in primo piano ?

Durante il test della mia app , vengono ricevute notifiche ma non viene visualizzata alcuna interfaccia utente di avviso iOS .

Ma questo comportamento è visibile nell'app Messaggi ufficiale di Apple:

Messaggi è aperto e in primo piano.  Mostra ancora un avviso di notifica.

La Guida alla programmazione delle notifiche locali e remote dice:

Quando il sistema operativo fornisce una notifica locale o remota e l'app di destinazione non è in esecuzione in primo piano , può presentare la notifica all'utente tramite un avviso , un numero di badge icona o un suono.

Se l'app è in esecuzione in primo piano quando viene recapitata la notifica, il delegato dell'app riceve una notifica locale o remota.

Quindi sì, possiamo ricevere i dati di notifica mentre siamo in primo piano. Ma non vedo alcun modo per presentare l'interfaccia utente di avviso di notifica iOS nativa .

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

Messaggi utilizza quindi un'API privata per visualizzare l'avviso mentre è in primo piano?

Ai fini di questa domanda, per favore non suggeriscono alcuna 3a parte "brindisi" avvisi pop-up su GitHub o ecc mi interessa se questo può essere fatto solo con il magazzino, nativo iOS locale o push di notifica avvisi UI in tutta l'applicazione è aperta e in primo piano .

Risposte:


152

iOS 10 aggiunge il UNUserNotificationCenterDelegateprotocollo per la gestione delle notifiche mentre la tua app è in primo piano.

Il UNUserNotificationCenterDelegateprotocollo definisce i metodi per ricevere le notifiche e per gestire le azioni. Quando la tua app è in primo piano, le notifiche in arrivo vengono recapitate all'oggetto delegato invece di essere visualizzate automaticamente usando le interfacce di sistema.

Swift:

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

Objective-C:

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

I flag UNNotificationPresentationOptions consentono di specificare UNNotificationPresentationOptionAlertdi visualizzare un avviso utilizzando il testo fornito dalla notifica.

Questa è la chiave in quanto ti consente di visualizzare l'avviso mentre la tua app è aperta e in primo piano , una novità per iOS 10.


Codice di esempio:

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

4
Potreste fornire un esempio di codice funzionante in cui una notifica in primo piano in arrivo viene visualizzata dal sistema come se l'applicazione fosse in background?
azmeuk

1
@azmeuk Controlla la mia risposta ...
chengsam

8
Non dimenticare di aggiungere UNUserNotificationCenter.current().delegate = selfil metodo application(_:willFinishLaunchingWithOptions:)orapplication(_:didFinishLaunchingWithOptions:)
Deniss Fedotovs

3
Assicurati anche di non avere il tuo dispositivo in modalità Non disturbare altrimenti le notifiche saranno visibili nel Centro notifiche, ma non verrebbero presentate in primo piano sopra la tua applicazione
Jadent

2
i miei 2 centesimi: da non perdere: importa le Notifiche Utente. !
ingconti

95

Per visualizzare il messaggio banner mentre l'app è in primo piano, utilizzare il metodo seguente.

iOS 10+, Swift 3+ :

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

1
Wow, ovunque leggessi la gente diceva che non era possibile. Sono così felice di aver trovato questa risposta, funziona esattamente come mi aspettavo! Quando l'app è in esecuzione, le notifiche push ora vengono visualizzate esattamente come se l'app fosse in background. Grazie!
Torre Lasley

1
Dove va a finire questo frammento? Nell'appDelegate o da qualche altra parte?
Yoav R.

@YoavR. AppDelegate
chengsam

Ho usato lo stesso codice. Ma non so perché la notifica non viene visualizzata quando l'app era in primo piano.
Boominadha Prakash M

3
Chengsam potresti correggere questo: non deve essere inserito nel file AppDelegate. Deve essere utilizzato per qualsiasi oggetto a cui è conforme UNUserNotificationCenterDelegate. Detto questo, la maggior parte degli sviluppatori si AppDelegateconforma a UNUserNotificationCenterDelegate. @YoavR.
Miele

16

MODIFICARE:

Gli avvisi in primo piano sono ora possibili in iOS 10! Si prega di vedere questa risposta .

Per iOS 9 e precedenti:

Non sembra essere possibile mostrare l'avviso di notifica iOS di serie quando la tua app è aperta e in primo piano. Messages.app deve utilizzare un'API privata.

Il sistema non visualizza alcun avviso, contrassegna l'icona dell'app o riproduce alcun suono quando l'app è già in primo piano. - Documenti UILocalNotification

I UIApplicationDelegatemetodi verranno comunque chiamati, consentendo alla tua app di rispondere alla notifica locale o remota:

application:didReceiveLocalNotification:
application:didReceiveRemoteNotification:

Tuttavia, l'interfaccia utente del banner di avviso di notifica iOS nativa di serie non verrà mostrata come in Messages.app di Apple, che deve utilizzare un'API privata.

Il meglio che puoi fare è lanciare il tuo banner di avviso o utilizzare un framework esistente:

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

Ho aperto un radar per questo comportamento qui: rdar://22313177


3
Allora come fanno whatsapp e altre app famose?
Machado

@tardoandre hai uno screenshot? Presumo che sia imitando l'avviso iOS di serie nelle loro visualizzazioni.
pkamb

2
Dovresti includere il link per toastAlertFromGithubse stai suggerendo di usare questa libreria di terze parti!
Ketan Parmar

14

Per mostrare le notifiche mentre l'app è aperta, dobbiamo gestirla manualmente. Quindi quello che sto facendo di seguito è gestire la notifica una volta ricevuta.

Aggiungi tutto sotto in AppDelegate.m

  1. Gestisci la chiamata per la notifica
  2. Crea una visualizzazione, aggiungi AppIcon, Notification message e mostralo come un'animazione
  3. Aggiungi Riconoscitore tattile per rimuovere se toccato o rimuovere in 5 secondi con animazione.

Fammi sapere se questa è una soluzione accettabile. Ha funzionato bene per me, ma non sono sicuro che sia la strada giusta.

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


}];


}

3
Questa potrebbe essere una buona risposta per creare il tuo avviso, ma non mostra l' avviso iOS di riserva come mostrato nello screenshot.
pkamb

Ciao, grazie per le tue gentili parole. Sì, non sarà così (se stai parlando dell'aspetto) poiché quello mostrato sopra nell'immagine è una notifica iOS e quello tramite codice è personalizzato. Possiamo forse replicare gli sguardi nella vista. Penso che WhatsApp ne abbia uno dall'aspetto pulito con sfocatura dello sfondo, ecc.
Hafeez

1
Qualcuno ha votato :(. Sarebbe bello sapere perché!?. Grazie.
Hafeez

2
L'ho fatto, come il codice in questa risposta (bello anche se può essere) non risponde realmente alla domanda posta: mostra un archivio iOS brindisi striscione all'interno della app. Ci sono altre domande su SO dove questa risposta sarebbe ottima.
pkamb

1
Grazie pkamb per aver chiarito, ha senso. Mi è sfuggita la parola "stock" immagino.
Hafeez

10

Ecco il codice per ricevere le notifiche push quando l'app è in primo piano o in fase aperta, 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 è necessario accedere a userInfo della notifica utilizzare il codice: notification.request.content.userInfo

Il metodo userNotificationCenter(_:willPresent:withCompletionHandler:)viene chiamato solo se aggiungi al payload l'attributo content-available:1. Il carico utile finale dovrebbe essere qualcosa del tipo:

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

1
userNotificationCenter(_:willPresent:withCompletionHandler:)verrà chiamato quando la tua app è in esecuzione in primo piano. Quindi NON importa con " contenuto disponibile ", che è correlato al " recupero in background ".
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);
}];

Posso mostrare la notifica push quando l'app è attiva per iOS 10.

  1. La notifica push dal server dovrebbe essere silenziosa .

  2. Quando si riceve una notifica remota dal server, si invia una notifica locale e si imposta il valore per keyPath: shouldAlwaysAlertWhileAppIsForeground = True


in swift 2 - lo è content.setValue("YES", forKeyPath: "shouldAlwaysAlertWhileAppIsForeground"), giusto? (con "Sì" e non vero)
Yoav R.

Attenzione: l'app in iOS 12 verrà arrestata in modo anomalo. Consulta la discussione qui: stackoverflow.com/questions/41373321/…
Matt Bearson

5

Puoi gestire tu stesso la notifica e mostrare un avviso personalizzato. App come Viber, Whatsapp e BisPhone utilizzano questo approccio.

Un esempio di avviso personalizzato di terze parti è CRToast .

Prova a programmare una notifica locale mentre la tua app è in primo piano e vedrai che non viene mostrato alcun avviso iOS stock:

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

Grazie, ma sto solo cercando risposte utilizzando l'avviso di notifica iOS di serie.
pkamb

1
ok, ma penso che non si può fare, anche un'occhiata a questo link: stackoverflow.com/questions/14872088/...
Mo Farhand

6
@ matt Sto tentando di mantenere questa domanda in argomento: mostrare l'avviso iOS di serie in primo piano. Molte altre domande sul "miglior quadro di avviso per i toast". Una risposta di "No, non puoi mostrare l'avviso iOS in primo piano" sarebbe perfettamente accettabile e accetterò quella risposta fino a quando ciò non sarà possibile in una futura versione di iOS.
pkamb

4

Versione Swift 3

Questo mostra un avviso quando l'applicazione è in primo piano.

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

Implementazione di ApplicationDelegate di 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
}

giusto per essere sicuri ... vuoi dire che da iOS 10 ora puoi anche mostrare avvisi / banner / suoni in primo piano proprio come fai in background?
Miele

Dove posso mettere la parte di codifica sopra? in ha ricevutoRemoteNotification?
user1960169

@Leslie Godwin funzionerà per iOS 8.0 per mostrare le notifiche in primo piano
Dilip Tiwari

2

Per mostrare la notifica locale questa è l'opzione migliore. serve meno codice per scrivere "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)

Questo BRYXBannerquadro non sembra utilizzare il magazzino striscione di notifica iOS.
pkamb

1

Se il tuo obiettivo di distribuzione> = iOS10, usa UNUserNotification come di seguito-

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
    {
        // Change this to your preferred presentation option
        completionHandler([.alert, .sound])
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.