Push notifications: realizziamo l’applicazione Windows Phone

Print Content | More

Dopo aver messo in piedi il servizio e l’applicazione server necessarie per l’invio delle notifiche push, è giunto il momento di realizzare il client vero e proprio per Windows Phone che riceverà le notifiche. Come già spiegato in precedenza, ogni device che vuole utilizzare le notifiche push deve aprire un canale (identificato da un URL) verso il Push Notification Server di Microsoft. Questo è proprio quello che andremo a fare nell’applicazione: apriremo un canale e, una volta ottenuto l’URL, lo memorizzeremo sul database grazie al servizio WCF che abbiamo creato in precedenza.

Vediamo come fare.

Il client Windows Phone

L’interfaccia grafica che useremo non ha bisogno di commenti: ci limiteremo infatti a inserire un pulsante che, alla pressione, andrà a registrare e aprire il canale. In una applicazione reale, questa operazione potrebbe essere fatta nella pagina delle impostazioni, in cui l’utente può scegliere se attivare o meno la ricezione delle notifiche (ricordatevi che per le notifiche toast questa richiesta è obbligatoria, pena il rifiuto dell’applicazione durante la fase di certificazione).

Partiamo dal vedere cosa succede nel momento in cui premiamo il pulsante per registrare il canale:

private void btnRegisterChannel_Click(object sender, RoutedEventArgs e)
{
    Channel = HttpNotificationChannel.Find(CHANNEL_NAME);
    if (Channel == null)
    {
        Channel = new HttpNotificationChannel(CHANNEL_NAME);
        Channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(Channel_ChannelUriUpdated);
        Channel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(Channel_ShellToastNotificationReceived);
        Channel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(Channel_HttpNotificationReceived);
        Channel.Open();
        Channel.BindToShellToast();
        Channel.BindToShellTile();
    }
    else
    {
        Channel.ChannelUriUpdated+=new EventHandler<NotificationChannelUriEventArgs>(Channel_ChannelUriUpdated);
        Channel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(Channel_ShellToastNotificationReceived);
        Channel.HttpNotificationReceived+=new EventHandler<HttpNotificationEventArgs>(Channel_HttpNotificationReceived);
        ChannelUri = Channel.ChannelUri;
    }
}

L’oggetto fulcro dell’operazione è Channel, di tipo HttpNotificationChannel. Ogni canale è identificato da un nome ben preciso, che nel nostro caso abbiamo memorizzato in una costante chiamata CHANNEL_NAME.

Come prima cosa, viene richiesto al Microsoft Push Notification Server se esiste già un canale con quel nome, sfruttando il metodo statico Find esposto dalla classe HttpNotificationChannel. In caso non esista, la richiesta non ritornerà alcun oggetto e perciò il nostro oggetto Channel, non essendo mai stato istanziato, sarà a null. In questo caso, andremo a creare il canale prima di effettuare qualsiasi altra operazione, altrimenti sfrutteremo quello già esistente.

Il canale viene creato semplicemente istanziando il nostro oggetto Channel e specificandone il nome. Dopodichè dobbiamo aprire la connessione (tramite il metodo Open) e scegliere a quali notifiche push vogliamo sottoscrivere l’applicazione. Per le notifiche di tipo RAW non c’è bisogno di specificare alcunchè, altrimenti possiamo usare i metodi BindToShellToast per iscriverci alle notifiche toast e BindToShellTile per iscriverci alle notifiche tile.

Dopodichè abbiamo a disposizione una serie di eventi che possiamo sottoscrivere, sia in caso il canale sia appena stato creato sia che esista già.

L’evento ChannelUriUpdated

L’evento principale è ChannelUriUpdated, che viene invocato nel momento in cui la richiesta di apertura del canale è stata elaborata e il MPNS ce ne ha restituito l’URL. Vediamo cosa succede nel momento in cui viene scatenato questo evento:

void Channel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
    ChannelUri = e.ChannelUri;
    PushServiceClient client = new PushServiceClient("BasicHttpBinding_IPushService");

    IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;

    Guid guid;

    if (settings.Contains("guid"))
        guid = (Guid)settings["guid"];
    else
    {
        guid = Guid.NewGuid();
        settings.Add("guid", guid);
    }

    client.SaveChannelUriCompleted += (obj, args) => MessageBox.Show("Channel saved");
    client.SaveChannelUriAsync(e.ChannelUri.ToString(), guid);
}

Il metodo restituisce tra gli argomenti di ritorno, all’interno della proprietà ChannelUri, l’URL del canale, che provvediamo a memorizzare nella variabile ChannelUri. Quello che dobbiamo fare ora è comunicare al nostro servizio WCF che abbiamo un nuovo device che si è registrato da memorizzare nel database: ecco perciò che creiamo una nuova istanza del servizio PushServiceClient, così da poterne utilizzare il metodo SaveChannelUri definito qualche post fa.

Se vi ricordate, abbiamo deciso in fase di definizione del servizio WCF di utilizzare il tipo Guid per identificare univocamente il device: lo stratagemma che utilizziamo è quello, quando il canale viene creato per la prima volta, di salvare nell’Isolated Storage l’id, così che quando l’applicazione verrà avviata le volte successive venga mantenuto sempre lo stesso id. Ecco perciò che andiamo a controllare se tale id esiste nell’Isolated Storage (grazie alla classe IsolatedStorageSettings): in caso negativo ne generiamo uno nuovo. In qualsiasi caso, questo sarà l’id che passeremo al servizio: se ci ricordiamo la definizione del metodo SaveChannelUri, ci penserà lui a determinare se si tratta di una operazione di aggiornamento o di inserimento ex-novo.

Infine, chiamiamo il metodo SaveChannelUriAsync (generato in fase di importazione del servizio da Visual Studio) passando come parameri l’URL del canale e l’id. Ci sottoscriviamo anche all’evento SaveChannelUriCompleted, che viene invocato nel momento in cui il device è stato salvato sul database: il metodo non include alcuna informazione di ritorno, perciò ci limitiamo a mostrare un messaggio a video che notifica l’esito dell’operazione.

Nota importante: ci siamo sottoscritti a questo evento sia in caso di creazione ex-novo del canale che in caso questi esista già. Questo perchè l’URL associato al canale potrebbe cambiare: quello che ci aspettiamo è che, alla creazione del canale, l’evento ChannelUriUpdated venga sempre scatenato. Se il canale esiste già, invece, questo evento potrebbe non essere invocato, nel caso in cui l’URL restituito dal MPNS rimanga invariato.

L’evento ShellToastNotificationReceived

Sappiamo bene che la caratteristica principale delle notifiche toast è quella di poter essere ricevute anche (e soprattutto) quando l’applicazione è chiusa: non tutti sanno però che tali notifiche possono essere intercettate anche ad applicazione aperta, nel caso in cui l’invio della notifica da parte dell’applicazione server coincida con un momento in cui l’utente sta utilizzando la nostra app.

L’evento ShellToastNotificationReceived serve proprio a questo: viene scatenato nel momento in cui riceviamo una notifica toast relativa all’app che stiamo usando in quel momento e possiamo gestirlo nel modo che riteniamo più adatto.

void Channel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
{
    Dispatcher.BeginInvoke(() => MessageBox.Show("Toast received"));
}

In questo semplicissimo esempio ci limitamo a mostrare un messaggio a video, utilizzando il Dispatcher di Silverlight dato che l’evento di callback viene eseguito in un thread diverso da quello che gestisce la UI (e quindi non sarebbe in grado di mostrare il MessageBox).

L’evento HttpNotificationReceived

Le notifiche RAW, al contrario di quelle toast e tile, possono essere ricevute solo ad applicazione aperta: l’evento HttpNotificationReceived viene scatenato proprio nel momento in cui è stata ricevuta una notifica di tipo RAW. Occhio che c’è un particolare rispetto alle altre notifiche: la notifica RAW, potendo veicolare qualsiasi tipo di informazione, contiene uno stream di dati generico e non un on oggetto specifico (come una stringa). Nell’esempio che vediamo qui di seguito, prendiamo lo stream in arrivo e lo convertiamo in una stringa, dato che nell’applicazione server abbiamo fatto l’opposto, ovvero abbiamo convertito la stringa in un array di byte, come possiamo vedere di seguito:

RawPushNotificationMessage raw = new RawPushNotificationMessage
{
    RawData = Encoding.ASCII.GetBytes(rawMessage),
    SendPriority = MessageSendPriority.High
};

Ecco invece l’evento HttpNotificationReceived vero e proprio:

void Channel_HttpNotificationReceived(object sender, HttpNotificationEventArgs e)
{
    string message;
    using (StreamReader reader = new StreamReader(e.Notification.Body))
    {
        message = reader.ReadToEnd();
    }
    Dispatcher.BeginInvoke(() => MessageBox.Show(message));
}

E per quanto riguarda le notifiche tile?

Per le notifiche tile non esiste alcun evento dedicato, dato che non possono essere intercettate all’interno dell’applicazione: se vogliamo usarle, l’importante è abilitare l’applicazione alla ricezione chiamando il metodo BindToShellTile in fase di creazione del canale.

Testiamo il tutto!

Testare se tutto funziona correttamente è molto semplice: lanciamo contemporaneamente sia l’applicazione client che quella server (facendo tasto destro su entrambi i progetti e scegliendo Debug – Start new istance siamo in grado di lanciarle entrambe, mantenedo il debugger di Visual Studio collegato a tutte e due). Una volta aperto l’emulatore di Windows Phone, premiamo sul pulsante Register channel e rimaniamo in attesa del messaggio di conferma di registrazione del canale. A questo punto possiamo usare l’applicazione server per spedire i tre tipi di notifiche: ricordiamoci che per testare le notifiche tile dobbiamo prima pinnare l’icona in home page, altrimenti l’esito dell’invio sarà negativo.

toast tile raw

Conclusione

E’ stato lungo ma è stato un bel viaggio: spero che questa serie di tutorial vi sia servita per familiarizzare con le notifiche push. Ovviamente non vuole essere un tutorial esaustivo al 100%, ma spero che vi abbia fornito almeno le basi per gestire gli scenari reali che andrete a realizzare nelle vostre applicazioni.

Di seguito trovate il link per scaricare il codice sorgente della soluzione con tutti i progetti: client WPF, client Windows Phone e servizio WCF.

Scarica il codice sorgente


Windows Phone , Microsoft , Push notifications

1 comments

Related Post


(will not be published)
(es: http://www.mysite.com)