[iOs] Come configurare, inviare e ricevere le notifiche push in una app iOs

Eccovi un tutorial su come configurare, inviare e ricevere le push notification di Apple in una app iOs. Tali notifiche sono molto utili nel caso in cui vogliate segnalare aggiornamento ed eventi agli utenti che hanno installato la vostra app e che hanno, ovviamente, dato il consenso per la loro ricezione. La configurazione non è molto immediata, specie la parte di creazione dei certificati, per cui vi descriverò i singoli passi nel dettaglio.

Prima di essere operativi, vediamo il modello di programmazione per capire quali sono le componenti in gioco e il flusso funzionale di registrazione, di accreditamento e di invio/ricezione delle notifiche push:

  1. Push-NotificationL’app, registrata sul Provisioning Portal con un AppID, deve essere configurata in modo da avere la funzionalità di push notification abilitata. Una volta abilitata, occorre generare un Provisioning Profile (sia per l’ambiente di sandbox – o development –   che per quello di production – o distribution) da associare all’app stessa. Lato app, quando l’utente dà il consenso alla ricezione delle notifiche push, si fa richiesta ad iOs per la registrazione e l’autorizzazione alle notifiche.
  2. iOs contatterà il server APNS (Apple Push Notification Service), il quale ricevuta la richiesta, genererà un device token da inoltrare direttamente all’app che ha chiesto la registrazione. Il device token è un “indirizzo” univoco che serve all’APNS per rintracciare il device e per inoltrare le notifiche push tramite l’app.
  3. Una volta ricevuto il device token, dall’app occorrerà richiamare un nostro servizio remoto (registerDevice) in cui registrare tale token, oltre ad una serie di altre info utili del device. L’idea è quella di registrare su un nostro database online, la lista di tutti i device, e relativi device token generati, in modo da inoltrare tutte le nostre notifiche a chi ne ha fatto espressamente richiesta.
  4. Un altro servizio remoto presente sul nostro server (sendPush) sarà responsabile dell’invio delle notifiche push (un semplice messaggio di testo). Tale servizio dovrà essere configurato in modo da avere l’autorizzazione dall’APNS server: occorrerà, dunque, generare e configurare un certificato SSL (e una relativa chiave privata) per poter inoltrare una richiesta di notifica push a ciascun device accreditato.
  5. Quando l’APNS server riceve una richiesta di invio di una notifica push per un determinato device token (dopo aver attestato la veridicità del certificato SSL del servizio remoto sendPush), inoltra la notifica. Dall’altra parte, sul device a cui è associato il device token, verrà visualizzato un alert dell’app (o una notifica nel Centro Notifiche) con il messaggio inviato. Oltre l’alert, si può decidere se riprodorre anche un suono e/o visualizzare un badge (il numeretto con il totale delle notifiche sull’icona dell’app). Cliccando sulla notifica o facendo lo “swipe” sull’alert, verrà aperta la vostra app.

 

NOTA. Non è possibile testare le push notification sul simulatore, ma soltanto direttamente su un iPhone/iPad.

 

Push Notification Payload.  Una richiesta di invio di una push notification (dal nostro server all’APNS server) è fatta da un breve messaggio costituito da un device token a cui indirizzare la notifica, un payload ed altre parti. Il payload contiene il messaggio vero e proprio (in formato JSON), compresi alcuni parametri. In totale non deve superare i 256 bytes. Per maggiori informazioni sui parametri, vedi Local and Push Notification Programming Guide.

Un esempio di messaggio è il seguente:

{"aps":{"alert":"Hello, world!","sound":"default"}}

Vi riporto i tutorial da cui sono partito per poter scrivere questa mini-guida:

 

Partiamo ora con la parte operativa:

 

 

1. Abilitazione delle Push Notifications sul Provisioning Portal. Accedete al vostro Provisioning Portal. Prima di abilitare la funzionalità di push notification occorre possedere un certificato non scaduto per lo sviluppo (Development Certificate) e per la distribuzione (Distribution Certificate), nonché aver registrato un App ID associato alla propria app (sezione Identifiers). Per tale AppID occorre abilitare l’opzione “Push Notifications” e generare due certificati (Development Push SSL Certificate e Production Push SSL Certificate). Per la generazione di questi certificati, leggete le istruzioni che vengono riportate dopo il click su “Create Certificate“: si utilizza il tool Accesso Portachiavi per creare il Certificate Signing Request (CSR) che occorrerà uploadare.

 

iOS App IDs - Apple DeveloperSettings - iOS App IDs - Apple Developer - Push Notification

 

Dopo aver completato la generazione, occorre effettuare il download dei due certificati, e facendo doppio click, si importano sempre in Accesso Portachiavi nella sezione “I miei certificati“. I certificati di Development iOs Push Services e Distribution iOs Push Servicesci serviranno per creare i certificati SSL da configurare sul servizio remoto del nostro server, come vedremo nel passo 3.

 

AccessoPortachiavi-I miei certificati
2. Creazione dei certificati di Provisioning Profiles.
Dopo aver abilitato le push notification di una app, occorre generare, o rigenerare i certificati di Provisioning Profile per lo sviluppo (Development Provisioning Profile) e la distribuzione (Distribution Provisioning Profile). Questi due certicati, dopo aver effettuato il download e il doppio click su ognuno di essi, verranno importati in xCode (pannello Organizer). Ecco qui come si genera un provisioning profile: http://www.wikihow.com/Create-a-Provisioning-Profile-for-iPhone

 

Qui, invece, viene spiegato come associare i provisioning profile ad una build configuration: vedi paragrafo Assigning Provisioning Profiles to Build Configurations in http://developer.apple.com/library/ios/#technotes/tn2250/_index.html

 

3. Generazione del certificato SSL per il servizio remoto.
Per poter inviare una notifica push dal servizio remoto (sendPush) all’APNS server, occorre configurare un certificato SSL (uno  per l’ambiente di sandbox, quando sviluppiamo e testiamo l’app, e un altro per quello di produzione, quando l’app viene rilasciata sullo store).

 

ATTENZIONE. La procedura che vi spiego viene fatta soltanto per l’ambiente di sandbox, ma è identica per la configurazione dell’ambiente di produzione.

 

  • Esportazione del certificato di Push Services dal Portachiavi. Se vi spostate nella sezione “I miei certificati” del tool “Accesso Portachiavi“, noterete i certificati Apple Development iOs Push Services e/o Apple Distribution iOs Push Services (se avete eseguito correttamente il punto 1). Nel caso in cui vogliate configurare l’ambiente di sandbox, occorre esportare il certificato Apple Development iOs Push Servicesfacendo click destro su di esso ed esportandolo con estensione .p12. Salvatelo con il nome apns-dev-cert.p12 in una directory del vostro pc. Vi verrà chiesta una password che occorrerà ricordarsi in seguito.
  • Esportazione della chiave privata associata al certificato di Push Services. Se espandete il certificato, noterete una chiave privata ad esso associato. Occorre esportare anche tale chiave con estensione .p12. Salvatela nella stessa directory del certificato esportato al punto precedente, nominandola apns-dev-key.p12. Anche qui vi verrà chiesta una password (passphrase) che dovete ricordare in seguito.

A questo punto, da Terminale, occorre generare un file .PEM che conterrà il certificato SSL utile al servizio remoto per connettersi ed autenticarsi sull’APNS server. Ecco i comandi da lanciare, dopo essersi spostati nella directory locale in cui avete salvato i file apns-dev-key.p12 e apns-dev-cert.p12:

openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12

openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12

openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem

cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem

Quando vi viene chiesta la password (o passphrase) inserite quella che avete digitato all’atto dell’esportazione dei certificato SSL e chiave privata.

Tra tutti i file generati, a voi interessa il file apns-dev.pem, che dovrete caricare sul vostro server remoto. Mettetelo in una directory push_notification del server, in cui caricare anche gli script PHP riportati nei punti seguenti.

NOTA. La precedente procedura andrà ripetuta per la generazione del certificato SSL per l’ambiente di produzione. Rinominate i file sostituendo la dicitura “dev” con “prod”, per esempio (apns-prod.pem, apns-prod-key.p12 e apns-prod-cert.p12).

 

4. Consenso e Registrazione dell’app alle notifiche push. Per poter abilitare le notifiche push lato app, occorre inserire il seguente codice nell’AppDelegate, prima della return del metodo didFinishLaunchingWithOptions:

 //si chiede all'utente se vuol ricevere le notifiche push
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
Dopo aver compilato la propria app, eseguitela direttamente sul device (ricordate, non sul simulatore!). Ecco che all’avvio vi verrà chiesto se volete consentire la ricezione di avvisi, badge o suoni:

 

notifiche_push_app
Per abilitare o disabilitare le notifiche relative alla vostra app, basta spostarsi nelle Impostazioni >>Notifiche del proprio device.

 

5. Ricezione del device token. Dopo aver dato consenso all’app di ricezione delle push notification, iOs in automatico richiamerà il server APNS per farsi inviare il device token. Si intercetta il device token inserendo nell’AppDelegate i seguenti metodi:

 

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
	NSLog(@"My token is: %@", deviceToken);
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
	NSLog(@"Failed to get token, error: %@", error);
}

 

Quando un’app si registra per la ricezione delle notifiche push, riceve un device token che viene stampato nel metodo precedente didRegisterForRemoteNotificationsWithDeviceToken. Questo token dovrà essere registrato e passato al servizio remoto PHP (registerDevice), che vedremo in seguito.

6. Servizio remoto per la registrazione del device token

Per poter inviare le notifiche push a tutti i device che hanno dato il consenso alla loro ricezione (Punto 5) e che hanno ricevuto il device token (Punto 6), occorre registrare sul proprio server (in un database) quest’ultima informazione. Innanzitutto, il metodo lato app didRegisterForRemoteNotificationsWithDeviceToken che è stato introdotto al Punto 5, deve essere ulteriormente esteso come segue:

/**
 * iOS: Fetch and Format Device Token and Register Important Information to Remote Server
 */
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {

#if !TARGET_IPHONE_SIMULATOR

	NSLog(@"Did register for remote notifications: %@", devToken);

	// Get Bundle Info for Remote Registration (handy if you have more than one app)
	NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
	NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];

	// Check what Notifications the user has turned on.  We registered for all three, but they may have manually disabled some or all of them.
	NSUInteger rntypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

	// Set the defaults to disabled unless we find otherwise...
	NSString *pushBadge = @"disabled";
	NSString *pushAlert = @"disabled";
	NSString *pushSound = @"disabled";

	// Check what Registered Types are turned on. This is a bit tricky since if two are enabled, and one is off, it will return a number 2... not telling you which
	// one is actually disabled. So we are literally checking to see if rnTypes matches what is turned on, instead of by number. The "tricky" part is that the
	// single notification types will only match if they are the ONLY one enabled.  Likewise, when we are checking for a pair of notifications, it will only be
	// true if those two notifications are on.  This is why the code is written this way
	if(rntypes == UIRemoteNotificationTypeBadge){
		pushBadge = @"enabled";
	}
	else if(rntypes == UIRemoteNotificationTypeAlert){
		pushAlert = @"enabled";
	}
	else if(rntypes == UIRemoteNotificationTypeSound){
		pushSound = @"enabled";
	}
	else if(rntypes == ( UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert)){
		pushBadge = @"enabled";
		pushAlert = @"enabled";
	}
	else if(rntypes == ( UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)){
		pushBadge = @"enabled";
		pushSound = @"enabled";
	}
	else if(rntypes == ( UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)){
		pushAlert = @"enabled";
		pushSound = @"enabled";
	}
	else if(rntypes == ( UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)){
		pushBadge = @"enabled";
		pushAlert = @"enabled";
		pushSound = @"enabled";
	}

	// Get the users Device Model, Display Name, Unique ID, Token & Version Number
	UIDevice *dev = [UIDevice currentDevice];
	NSString *deviceUuid = dev.uniqueIdentifier;
    NSString *deviceName = dev.name;
	NSString *deviceModel = dev.model;
	NSString *deviceSystemVersion = [dev.systemVersion stringByReplacingOccurrencesOfString:@"." withString:@"_"];

	// Prepare the Device Token for Registration (remove spaces and < >)
	NSString *deviceToken = [[[[devToken description]
                               stringByReplacingOccurrencesOfString:@"<"withString:@""]
                              stringByReplacingOccurrencesOfString:@">" withString:@""]
                             stringByReplacingOccurrencesOfString: @" " withString: @""];

	// Build URL String for Registration
	// !!! CHANGE "www.mywebsite.com" TO YOUR WEBSITE. Leave out the http://
	// !!! SAMPLE: "secure.awesomeapp.com"
	NSString *host = @"www.lubannaiuolu.net/lubannapp";

	// !!! CHANGE "/apns.php?" TO THE PATH TO WHERE apns.php IS INSTALLED
	// !!! ( MUST START WITH / AND END WITH ? ).
	// !!! SAMPLE: "/path/to/apns.php?"
	NSString *urlString = [@"/push_notification" stringByAppendingString:@"/registerDevice.php?"];

	urlString = [urlString stringByAppendingString:@"&appname="];
	urlString = [urlString stringByAppendingString:appName];
	urlString = [urlString stringByAppendingString:@"&appversion="];
	urlString = [urlString stringByAppendingString:appVersion];
	urlString = [urlString stringByAppendingString:@"&deviceuid="];
	urlString = [urlString stringByAppendingString:deviceUuid];
	urlString = [urlString stringByAppendingString:@"&devicetoken="];
	urlString = [urlString stringByAppendingString:deviceToken];
	urlString = [urlString stringByAppendingString:@"&devicename="];
	urlString = [urlString stringByAppendingString:deviceName];
	urlString = [urlString stringByAppendingString:@"&devicemodel="];
	urlString = [urlString stringByAppendingString:deviceModel];
	urlString = [urlString stringByAppendingString:@"&deviceversion="];
	urlString = [urlString stringByAppendingString:deviceSystemVersion];
	urlString = [urlString stringByAppendingString:@"&pushbadge="];
	urlString = [urlString stringByAppendingString:pushBadge];
	urlString = [urlString stringByAppendingString:@"&pushalert="];
	urlString = [urlString stringByAppendingString:pushAlert];
	urlString = [urlString stringByAppendingString:@"&pushsound="];
	urlString = [urlString stringByAppendingString:pushSound];

	// Register the Device Data
	// !!! CHANGE "http" TO "https" IF YOU ARE USING HTTPS PROTOCOL
	NSURL *url = [[NSURL alloc] initWithScheme:@"http" host:host path:urlString];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
	NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
	NSLog(@"Register URL: %@", url);
	NSLog(@"Return Data: %@", returnData);

    //application.applicationIconBadgeNumber = 0;

#endif
}

Prima di scrivervi il codice del servizio registerDevice da pubblicare sul vostro server, occorre creare la tabella sul database che raccoglierà i dati dei device accreditati. Eccovi il codice SQL:

--
-- Struttura della tabella `apns_devices`
--

CREATE TABLE IF NOT EXISTS `apns_devices` (
  `pid` int(9) unsigned NOT NULL AUTO_INCREMENT,
  `clientid` varchar(64) NOT NULL,
  `appname` varchar(255) NOT NULL,
  `appversion` varchar(25) DEFAULT NULL,
  `deviceuid` char(40) NOT NULL,
  `devicetoken` char(64) NOT NULL,
  `devicename` varchar(255) NOT NULL,
  `devicemodel` varchar(100) NOT NULL,
  `deviceversion` varchar(25) NOT NULL,
  `pushbadge` enum('disabled','enabled') DEFAULT 'disabled',
  `pushalert` enum('disabled','enabled') DEFAULT 'disabled',
  `pushsound` enum('disabled','enabled') DEFAULT 'disabled',
  `development` enum('production','sandbox') CHARACTER SET latin1 NOT NULL DEFAULT 'production',
  `status` enum('active','uninstalled') NOT NULL DEFAULT 'active',
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`pid`),
  UNIQUE KEY `appname` (`appname`,`deviceuid`),
  KEY `clientid` (`clientid`),
  KEY `devicetoken` (`devicetoken`),
  KEY `devicename` (`devicename`),
  KEY `devicemodel` (`devicemodel`),
  KEY `deviceversion` (`deviceversion`),
  KEY `pushbadge` (`pushbadge`),
  KEY `pushalert` (`pushalert`),
  KEY `pushsound` (`pushsound`),
  KEY `development` (`development`),
  KEY `status` (`status`),
  KEY `created` (`created`),
  KEY `modified` (`modified`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Store unique devices' AUTO_INCREMENT=7 ;

Il servizio registerDevice esposto sul vostro server che scriverà sulla tabella apns_devices è, invece, il seguente:

//registerDevice.php

<?php
global $DB;

include '../config.php';
include '../openDb.php';

$appname = $_GET['appname'];
$appversion = $_GET['appversion'];
$deviceuid = $_GET['deviceuid'];
$devicemodel = $_GET['devicemodel'];
$devicetoken = $_GET['devicetoken'];
$devicename = $_GET['devicename'];
$deviceversion = $_GET['deviceversion'];
$pushbadge = $_GET['pushbadge'];
$pushalert = $_GET['pushalert'];
$pushsound = $_GET['pushsound'];

//Controllo se il device è stato già registrato
$result = mysql_query("SELECT * FROM `apns_devices` where DEVICETOKEN = '$devicetoken'");

if($result){

	$num_rows = mysql_num_rows($result);

	if($num_rows==0){
		echo 'Nessun risultato...inserisco nel DB il nuovo deviceuid: '. $deviceuid;
		//mysql_query("INSERT INTO `banna_lubannapp_device` (DEVICEID, DEVICENAME, NOTE, CREATE_DATE) VALUES ('$deviceid','$devicename',null,NOW());");
		mysql_query("INSERT INTO `apns_devices` (APPNAME, APPVERSION, DEVICEUID, DEVICEMODEL, DEVICETOKEN, DEVICENAME, DEVICEVERSION, PUSHBADGE, PUSHALERT, PUSHSOUND, CREATED) VALUES ('$appname', '$appversion', '$deviceuid', '$devicemodel', '$devicetoken', '$devicename', '$deviceversion', '$pushbadge', '$pushalert', '$pushsound', NOW());");

	}
	else{
		echo 'Trovato un risultato...faccio l\'update per il deviceuid: '. $deviceuid;
		//mysql_query("UPDATE `banna_lubannapp_device` SET DEVICENAME='$devicename', DEVICEID='$deviceid', MODIFY_DATE=NOW() WHERE DEVICEID='$deviceid';");
		mysql_query("UPDATE `apns_devices` SET APPNAME='$appname', APPVERSION='$appversion', DEVICEUID='$deviceuid', DEVICETOKEN='$devicetoken', DEVICENAME='$devicename', DEVICEVERSION='$deviceversion', PUSHBADGE='$pushbadge', PUSHALERT='$pushalert', PUSHSOUND='$pushsound' WHERE DEVICEUID='$deviceuid';");
	}
}

include '../closeDb.php';
?>

NOTA. Per ovvi motivi, le password di accesso al database e l’apertura/chiusura della connessione al database, li ho inseriti in file PHP separati ed inclusi (con clausola include) nello script precedente.

Quindi, ricapitolando le cose scritte in questo punto 6 sono:

  • il device, che dà il consenso e che riceve il device token dall’APNS server, manda grazie al metodo didRegisterForRemoteNotificationsWithDeviceToken le sue informazioni ad un servizio web remoto registerDevice
  • il servizio registerDevice prende tutti i parametri in input (qui in GET) e li registra nella tabella apns_devices del database
  • tutti i device accreditati saranno, dunque, presenti nella tabella apns_devices, dalla quale andremo a prelevare i device token utili per l’invio della notifica push spiegata nel punto seguente.

 

7. Servizio remoto per l’invio della notifica push a tutti i device accreditati

Per poter inviare le notifiche push a tutti i device accreditati e “censiti” nella tabella apns_devices costruita al punto 6, occorre scrivere il servizio web sendPush che andrà richiamato dal vostro sito (nel mio caso dal forum) o tramite una form HTML (per esempio, ve ne ho preparata una di test al punto 9).

Ecco il codice della pagina sendPush.php:

//sendPush.php

<?php

// il file di config contiene le credenziali per la connessione al DB
include '../config.php';
include '../openDb.php';

// Put your private key's passphrase here and certificate's name:
$passphrase = 'XXXXXXXXXXXX';
$certificate = 'apns-dev.pem';

// Put your alert message here:
$message = $_POST['message'];
$type = $_POST['type'];
$id_message = $_POST['id_message'];

//Recupero la lista di tutti i device registrati per l'invio delle notifiche push:

$select = "SELECT DEVICEUID, DEVICETOKEN FROM apns_devices"; 
$rows = mysql_query($select); 

 while ($r = mysql_fetch_array($rows)) {

  	$deviceToken = $r['DEVICETOKEN'];
  	$deviceUid = $r['DEVICEUID'];

	////////////////////////////////////////////////////////////////////////////////
	echo 'Sending push notification for device with uid=' . $deviceUid;

	$ctx = stream_context_create();
	stream_context_set_option($ctx, 'ssl', 'local_cert', 'apns-dev.pem');
	stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);

	// Open a connection to the APNS server
	// replaced for production environment with gateway.push.apple.com
	$fp = stream_socket_client(
		'ssl://gateway.sandbox.push.apple.com:2195', $err,
		$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);

	if (!$fp)
		exit("<br>Failed to connect: $err $errstr" . PHP_EOL);

	echo '<br>Connected to APNS' . PHP_EOL;

	// Create the payload body
	$body['aps'] = array(
		'alert' => $message,
		'sound' => 'default',
		'type' => $type,
		'id_message' => $id_message 
		);

	// Encode the payload as JSON
	$payload = json_encode($body);

	// Build the binary notification
	$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;

	// Send it to the server
	$result = fwrite($fp, $msg, strlen($msg));

	if (!$result)
		echo '<br>Message not delivered' . PHP_EOL;
	else
		echo '<br>Message successfully delivered' . PHP_EOL;

	// Close the connection to the server
	fclose($fp);

	echo '<br><br>';

}

include '../closeDb.php';

?>

Il precedente servizio, apre una socket verso l’APNS server di Apple. Occorre, dunque, passare il certificato SSL generato al punto 3 (variabile $certificate), e la passphrase che avete utilizzato per generare il certificato (variabile $passphrase). Si scorre la lista dei device censiti nel database e si invia, per ogni singolo device token, il messaggio da notificare.

NOTA. Per la configurazione per l’ambiente di produzione, dovrete sostituire l’URL dell’APNS server da gateway.sandbox.push.apple.com a gateway.push.apple.com.

8. Ricezione della push notification sull’app

/**
 * Remote Notification Received while application was open.
 */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

#if !TARGET_IPHONE_SIMULATOR

    application.applicationIconBadgeNumber = 0;

    // We can determine whether an application is launched as a result of the user tapping the action
    // button or whether the notification was delivered to the already-running application by examining
    // the application state.

    if (application.applicationState == UIApplicationStateActive) {
        // Nothing to do if applicationState is Inactive, the iOS already displayed an alert view.
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Notifica Push"
                                                            message:[NSString stringWithFormat:@"%@",
                                                                     [[userInfo objectForKey:@"aps"] objectForKey:@"alert"]]
                                                           delegate:self
                                                  cancelButtonTitle:@"OK"
                                                  otherButtonTitles:nil];
        [alertView show];
        [alertView release];
    }

	NSLog(@"remote notification: %@",[userInfo description]);
	NSDictionary *apsInfo = [userInfo objectForKey:@"aps"];

	NSString *alert = [apsInfo objectForKey:@"alert"];
	NSLog(@"Received Push Alert: %@", alert);

	NSString *sound = [apsInfo objectForKey:@"sound"];
	NSLog(@"Received Push Sound: %@", sound);

	NSString *badge = [apsInfo objectForKey:@"badge"];
	NSLog(@"Received Push Badge: %@", badge);

#endif

}

NOTA: il controllo su UIApplicationStateActive, serve per rilevare se l’app è in foreground (ossia aperta). Le notifiche push vengono visualizzate quando l’app è chiusa o in background. Quando è aperta, si intercetta tale stato per visualizzare un alert con il messaggio inviato. Quando è inattiva, l’alert viene lanciato in automatico da iOs.

 

9. Test della notifica push. Per poter testare l‘invio della notifica push, vi allego una form semplice:

//pushform.php

<form action="sendpush.php" method="POST">
<p>Message</p><textarea name="message" rows="6" cols="25"></textarea><br />

<input type="submit" value="Send"><input type="reset" value="Clear">
</form>

All’invio del messaggio scritto sulla form, sull’app vi verrà visualizzato l’alert con la notifica push.

iOs Push Test

 

Potete scaricare gli script lato server nell’allegato seguente:

 

iOs_Pysh_Notification_PHP
Titolo: iOs_Pysh_Notification_PHP (0 click)
Etichetta:
Filename: push_notification.zip
Dimensione: 4 kB
push_notification_test
Titolo: push_notification_test (0 click)
Etichetta:
Filename: push_notification_test.zip
Dimensione: 21 kB

13 pensieri su “[iOs] Come configurare, inviare e ricevere le notifiche push in una app iOs

  1. Complimenti per il tutorial, ho un problema. Compilando il form per provare un invio di pushnotification esce il seguente errore dopo un po’ di attesa in cui prova qualcosa:

    Sending push notification for device with uid=
    Failed to connect: 110 Connection timed out

    Qualche idea?

  2. Ciao ottimo tutorial, ho provato a seguirlo ma mi restituisce questo errore:” nessuna stringa di autorizzazione ‘aps-environment’ valida trovata per l’applicazione” e ovviamente non mi invoca la richiesta di notifica a display, sai dirmi perchè?

    • Ciao Antonio, l’errore sembrerebbe riconducibile al certificato. Hai configurato bene il path? Occorre inserire un percorso assoluto al file PEM. Ti consiglio di lasciare nella stessa directory del PEM anche il file .p12 con la chiave privata. Oppure prova a ricreare il certificato.

  3. Ciao Francesco,
    ti ringrazio per l’ottimo tutorial che sto cercando di seguire.
    In fondo hai scritto “Potete scaricare gli script lato server nell’allegato seguente.” ma non vedo l’allegato. Puoi indicarmi da dove scaricare gli script lato server per fare le prove? Grazie mille e complimenti per il tuo blog!

    Guido

  4. Ciao Francesco!
    Ho concluso la fase di test e sono riuscito a mandarmi le notifiche push!
    Volevo segnalarti alcune cose da correggere nella guida.

    1) Nell’APP delegate, quando spieghi del token, il primo pezzo di codice, quello dove c’è NSLog utilizza la variabile deviceToken mentre, più avanti nella guida, quando dici che il metodo ha bisogno di ulteriori righe di codice, tale variabile diventa devToken. Io ho uniformato tutto a devToken per non avere errori;

    2) dev.UniqueIdentifier è stato deprecato. Pertanto, al posto di NSString *deviceUuid = dev.uniqueIdentifier ho utilizzato questo:

    // Create universally unique identifier (object)
    CFUUIDRef uuidObject = CFUUIDCreate(kCFAllocatorDefault);

    //Get the string representation of CFUUID object.

    NSString *deviceUuid = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidObject);
    CFRelease (uuidObject);

    3) Dentro didReceiveRemoteNotification commentare [alertView release]; o specificare che per app che usano l’ANR questo parametro va commentato. Io l’ho commentato, e funziona tutto.

    4) Dentro pushForm.php ho creato una struttura standard e nel tag ho inserito questo:
    Su alcuni webserver l’UTF-8 può non essere impostato come charset di default (come nel mio caso)… quindi succedeva che non appena mettevo un carattere speciale nel form, nella push mi arrivava un bel . Con questa modifica invece funziona tutto correttamente.

    Grazie per aver condiviso con tutti noi il tuo lavoro! Seguirò il tuo blog con piacere. Buona domenica!

    • ciao, a me da questo errore….:

      2015-11-26 19:30:57.199 okkio[890:323971] Did register for remote notifications:
      2015-11-26 19:30:57.199 okkio[890:323971] enabledRemoteNotificationTypes is not supported in iOS 8.0 and later.
      2015-11-26 19:30:57.225 okkio[890:323971] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[__NSCFString stringByAppendingString:]: nil argument’
      *** First throw call stack:
      (0x1831b8f48 0x197d6bf80 0x1831b8e90 0x184015338 0x1000eb50c 0x10013dca8 0x10013dc68 0x100143710 0x1831701f8 0x18316e060 0x18309cca0 0x18e2d8088 0x1887b4ffc 0x1000ebe9c 0x1985ba8b8)
      libc++abi.dylib: terminating with uncaught exception of type NSException

  5. Ciao Francesco,
    una domanda: ma per utilizzare le push notification bisogna disporre di un server con protocollo ssl abilitato?

    • Ciao Lucio,
      occorre avere un server che riesca ad aprire una connessione in socket verso l’apns di Apple, su porta 2195. Se ti da errori di connection timeout, allora vuol dire che non riesce ad aprire la socket

  6. Gentilissimo Francesco,
    prima di tutto grazie per il tutorial.
    Oggi mi sto accingendo a seguire le tue istrizioni, però mi sovviene un dubbio ovvero ma le notifiche posso inviarle anche con asp?
    Grazie immensamente per la pazienza

  7. ciao,
    bellissimo tutorial, solo che io ho un piccolo problema a monte…quando tento di esportare il certificato dal portachiavi non mi da la possibilità di esportarlo in .p12 ma solo in .cer ed il certificato in questione non ha la chiave privata annessa.

    consigli?!

    grazie anticipatamente, Angelo

    • Ciao Angelo,
      se non ha la chiave annessa vuol dire che il certificato non è stato configurato correttamente o non è quello di provisioning. Se non compare la chiave non fa esportare il .p12, ma solo il .cer

  8. Ciao, ottimo tutorial, ho solo un errore in questo pezzo di codice:

    NSString *deviceUuid = dev.uniqueIdentifier; (qui mi dice: property ‘uniqueIdentifier’ not found on object of type UIDevice

    potresti aiutarmi? Grazie.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *


7 − = due