Local notification: da iOS 9 ad iOS 10

Una subdola differenza nel comportamento delle notifiche locali fra iOS 9 e iOS 10 è come viene gestita una notifica la cui proprietà fireDate è impostata ad una data nel passato.

In iOS 9 semplicemente questa notifica veniva ignorata, mentre in iOS 10 viene lanciata immediatamente (probabilmente perché il sistema pensa che adesso sia il momento più vicino possibile alla data ormai passata).

Per cui, prima di impostare una fireDate ad un oggetto UILocalNotification è bene controllare che

1
[fireDate timeIntervalSinceNow] > 0
[fireDate timeIntervalSinceNow] > 0

ovvero che la data sia nel futuro.

Evitare notification duplicate

Talvolta, per semplificare il codice da utilizzare per un’app, è comodo ricorrere alle notifiche dell’NSNotificationCenter. Una volta aggiunto un observer, però, è buona norma evitare che venga aggiunto una seconda volta, duplicando il codice eseguito una volta innescata la notifica.

Per evitare questo problema è sufficiente ricordarsi di rimuovere l’observer prima di aggiungerlo, poiché rimuovere un observer che non esiste non crea nessun tipo di inconveniente:

1
[[NSNotificationCenter defaultCenter] removeObserver:self name:foo object:bar]
[[NSNotificationCenter defaultCenter] removeObserver:self name:foo object:bar]

Mostrare una notifica push ad applicazione aperta

Le notifiche push appaiono sullo schermo quando l’applicazione che le riceve non è attiva, ma non accade nulla in automatico quando l’applicazione è attiva. Questo perché si possa decidere autonomamente se mostrare o meno il testo della notifica, come mostrarlo e come tener conto del valore del badge.

Se volessimo ad esempio visualizzare il testo della notifica in un alert in base alla notifica ricevuta ad app aperta, allora basterà usare il metodo application:didReceiveRemoteNotification: nell’AppDelegate.m e usando il dizionario UserInfo per accedere alle informazioni della notifica. Ad esempio testo dell’allerta è disponibile con queste chiavi:

1
NSString *message = [userInfo objectForKey:@"aps"] valueForKey:@"alert"];
NSString *message = [userInfo objectForKey:@"aps"] valueForKey:@"alert"];

Il nuovo valore per il badge è disponibile alla chiave @”badge”.

Dal momento che una notifica può anche non avere testo, è bene controllare che il testo ci sia prima di utilizzarlo se questa eventualità può verificarsi in base al progetto dell’app. Ecco un modo per fare questa verifica:

1
2
3
4
5
id notification = [[userInfo objectForKey:@"aps"] valueForKey:@"alert"];
if ([notification isKindOfClass:[NSString class]]){
   //la notifica ha testo
 
}
id notification = [[userInfo objectForKey:@"aps"] valueForKey:@"alert"];
if ([notification isKindOfClass:[NSString class]]){
   //la notifica ha testo

}

Permettere all’utente di attivare e disattivare le Push Notification

L’utente può attivare e disattivare a piacere le Push Notification nelle impostazioni del suo dispositivo, ma una specifica opzione, magari tramite un UISwitch (il classico interruttore on/off), dentro l’app sarebbe molto più comodo.

si potrà quindi impostare lo status dell’UISwitch leggendo la configurazione delle notifiche:

1
notificationSwitch.on = ([[UIApplication sharedApplication] enabledRemoteNotificationTypes] != UIRemoteNotificationTypeNone);
notificationSwitch.on = ([[UIApplication sharedApplication] enabledRemoteNotificationTypes] != UIRemoteNotificationTypeNone);

e aggiungendo un target allo switch quando il valore cambia (di modo da disattivare le notifiche quando lo switch viene spento e riattivarle quando viene riacceso) tramite il classico comando registerForRemoteNotification: e l’unregisterForRemoreNotifications (senza argomenti).

Per evitare di riattivare le notifiche all’avvio, contestualmente andrà impostata una chiave nelle preferenze dell’utente, tramite l’oggetto [NSUserDefaults standardUserDefaults], di modo che nell’AppDelegate si chieda la riattivazione delle notifiche solo se richiesto dall’utente.

Notifiche Push: idee ed avvertenze

Quando si implementano le Notifiche Push può essere utile, talvolta, di notificare solo il cambiamento di badge, senza suono né testo.

E viceversa si può fare in modo che le notifiche con testo vengano mostrate come UIAlertView quando vengono ricevute ad app aperta, grazie al metodo application:didReceiveRemoteNotification: e grazie ad un dizionario che alla chiave “aps” contiene, fra l’altro, il testo della notifica.

Apple usa JSON come formato di comunicazione fra il server delle notifiche e l’app e questo formato restituisce un NSCFBoolean se il valor è zero, oppure un NSCFString se è una stringa. Quindi cosa accade se riceviamo una notifica muta ad app aperta?

Prima di creare l’alert dobbiamo sincerarci di aver ricevuto una stringa e quindi usiamo il metodo isKindOfClass e la seguente condizione:

1
2
3
4
5
6
id notification = [userInfo objectForKey:@"aps"] valueForKey:@"alert"];
 
if ([notification isKindOfClass:[NSString class]]) {
     // mostra alert
 
}
id notification = [userInfo objectForKey:@"aps"] valueForKey:@"alert"];

if ([notification isKindOfClass:[NSString class]]) {
     // mostra alert

}

In questo modo non si rischierà di usare un booleano dove invece andrebbe usata una stringa, con conseguente crash assicurato dell’app a causa di un errore del tipo:

-[__NSCFBoolean isEqualToString:[: unrecognized selector sent to instance…

Mostrare una notifica push ad app aperta

Il centro notifiche reagisce all’invio di una notifica push solo quando l’app è inattiva. Ma come possiamo avvisare ugualmente l’utente che una notifica è stata ricevuta quando l’app è in esecuzione.

È sufficiente, nell’App Delegate, usare il metodo che viene scaturito quando l’app riceve una notifica remota e usare il dizionario userInfo allegato per mostrare il testo, ad esempio, su un UIAlertView, in questo modo:

1
2
3
4
5
6
7
8
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
    NSLog(@"userInfo: %@", userInfo);
 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Notifica" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
 
    [alert show];
 
}
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
    NSLog(@"userInfo: %@", userInfo);

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Notifica" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];

    [alert show];

}

Installare il certificato per le Push Notification [AGGIORNATO]

Solo una annotazione riguardante l’utile articolo di devAPP sulle Notifiche Push. Quando si parla di installare il certificato ci si riferisce, una volta terminata la procedura via Terminale, al semplice caricamento sul un server del file apns-dev.pem (o come avete deciso di chiamarlo). Potete scegliere la cartella che volete, è sufficiente che, usando lo script php descritto nell’articolo stesso, il certificato sia nella stessa posizione dello script. Unico dettaglio da tenere in considerazione è che il server deve supportare il protocollo di crittografia SSL (quindi, ad esempio, Aruba non è compatibile ma Blooweb sì).

Lo script php funziona benissimo, ovviamente va creato un ciclo che vada a pescare i vari token da un archivio (un db, ad esempio) ed esegua lo script una volta per ogni token.

[AGGIORNAMENTO]

Due tutorial (in inglese) illustrano molto in profondità ciò che viene accennato nell’articolo di devAPP. In particolare:

  1. Boxed Ice Blog spiega il significato di tutti i comandi da Terminale e per PHP
  2. mobiForge illustra tutto il procedimento tramite screenshot e spiega come cambiare il suono di avviso quando arriva una notifica push.