Un système animé et dynamique, troisième partie : notifications Push et services mobiles Windows Azure

Blog des développeurs d'applications Windows 8

Indications sur la conception d'applications de style Metro pour Windows 8, par l'équipe d'ingénierie de Windows 8

Un système animé et dynamique, troisième partie : notifications Push et services mobiles Windows Azure

  • Comments 0

Dans la première partie de cette série, nous avons étudié ce que représente un système « animé et dynamique » pour un utilisateur, ainsi que le rôle joué par les applications au sein du système. Dans la deuxième partie, nous avons examiné comment écrire et déboguer des services Web afin de mettre à jour périodiquement les vignettes dynamiques. Dans cette troisième partie, nous allons clore la série en expliquant comment fournir à la demande des mises à jour de vignette, des toasts et des notifications brutes à des périphériques client donnés via les services de notifications Push Windows (WNS) et comment les services mobiles Windows Azure simplifient l'ensemble du processus.

Notifications Push

Les mises à jour périodiques, comme nous l'avons vu dans la deuxième partie, sont initiées côté client et offrent une méthode d'interrogation visant à mettre à jour une vignette ou un badge. Les notifications « Push » ont lieu lorsqu'un service envoie directement une mise à jour à un périphérique et si cette mise à jour est susceptible de s'appliquer à un utilisateur, à une application ou même à une vignette secondaire en particulier.

Contrairement à l'interrogation, les notifications Push peuvent se produire à tout moment avec une fréquence bien supérieure. Vous devez toutefois garder à l'esprit que Windows limite le volume du trafic des notifications Push sur un périphérique si ce dernier est sur batterie, en mode de veille connectée ou si le trafic des notifications devient excessif. En d'autres termes, rien ne garantit que toutes les notifications parviendront à destination (en particulier si le périphérique est hors tension).

Par conséquent, ne pensez pas que vous pouvez utiliser les notifications Push pour implémenter une vignette d'horloge ou d'autres gadgets de vignette avec une fréquence ou une résolution temporelle similaire. En revanche, envisagez la manière dont vous pouvez utiliser les notifications Push pour connecter des vignettes et notifications à un service principal doté d'informations intéressantes et utiles à communiquer à l'utilisateur, ce qui l'incite à utiliser le plus souvent possible votre application.

Avant d'entrer dans les détails, il est important de comprendre qu'il existe deux types de notifications Push :

  1. Mises à jour XML contenant des mises à jour de vignette ou de badge ou des charges utiles de notification toast : Windows peut traiter ces notifications Push et émettre la mise à jour ou le toast au nom d'une application. Une application peut également gérer ces notifications directement, le cas échéant.
  2. Notifications binaires ou brutes contenant les données que le service souhaite envoyer : elles doivent être gérées par un code propre à l'application, car sinon, Windows ne sait pas comment traiter les données. Pour plus d'informations sur les tailles limites (5 Ko) et l'encodage (base64), voir Recommandations et liste de vérification sur les notifications brutes.

Dans les deux cas, une application en cours d'exécution (au premier plan) peut gérer les notifications Push directement par l'intermédiaire de la classe PushNotificationChannel et de son événement PushNotificationReceived. Pour les charges utiles XML, l'application peut modifier le contenu, changer les balises et ainsi de suite, avant de les émettre en local (ou de les ignorer). Pour les notifications brutes, l'application traite le contenu, puis choisit les notifications à émettre (ou n'en émet aucune).

Si l'application est suspendue ou n'est pas en cours d'exécution, elle peut également fournir une tâche en arrière-plan à cet effet. L'application doit demander et obtenir l'accès à l'écran de verrouillage, ce qui permet ensuite au code propre à l'application de s'exécuter lorsqu'une notification est reçue.

Une tâche en arrière-plan réalise en général une ou deux opérations lorsque la notification arrive. D'abord, elle peut enregistrer certaines informations pertinentes de la notification dans les données d'application locales, que l'application peut récupérer lors de sa prochaine activation ou reprise. Ensuite, la tâche en arrière-plan peut émettre des mises à jour de vignette et de badge locales et/ou des notifications toast.

Pour mieux comprendre les notifications brutes, prenez une application de messagerie électronique classique. Lorsque son service principal détecte de nouveaux messages pour un utilisateur, il envoie une notification Push brute aux services de notifications Push Windows (WNS) contenant un certain nombre d'en-têtes de messages électroniques. Le service effectue cette opération à l'aide d'un URI de canal qui est connecté à l'application spécifique sur le périphérique de cet utilisateur.

Les services de notifications Push Windows (WNS) tentent ensuite de transmettre cette notification au client. En cas de succès de l'opération, Windows reçoit cette notification et recherche l'application qui est associée à l'URI de canal en question. S'il ne parvient pas à trouver l'application appropriée, la notification est ignorée. Si une application existe et qu'elle est en cours d'exécution, Windows déclenche l'événement PushNotificationReceived. Sinon, Windows recherche et appelle une tâche en arrière-plan disponible pour cette application.

Dans tous les cas, la notification brute se retrouve dans le code d'une application, qui traite ensuite les données, émet une mise à jour de badge à destination de la vignette de l'application pour indiquer le nombre de nouveaux messages, puis émet jusqu'à cinq mises à jour de vignette cycliques avec des en-têtes de messages. L'application peut également émettre des notifications toast pour chaque nouveau message arrivé ou au moins une indiquant la présence de nouveaux messages.

En conséquence, les toasts indiquent à l'utilisateur que de nouveaux messages électroniques sont arrivés et la vignette de l'application sur l'écran d'accueil présente une vue rapide et immédiate de l'activité des nouveaux messages.

Pour en savoir plus sur ces gestionnaires d'événements côté client et sur les tâches en arrière-plan, consultez l'exemple de notifications brutes, le billet Rester productif lorsque votre application n'est pas à l'écran : tâches en arrière-plan de ce blog et le livre blanc sur le réseau en arrière-plan. Dans le cadre de ce billet, examinons maintenant le côté service.

Utilisation des services de notifications Push Windows (WNS)

Grâce à la coopération de Windows, des applications, des services et de WNS, il est possible de fournir à une vignette d'application précise (ou à un gestionnaire de notification toast ou brute) des données spécifiques à l'utilisateur sur un périphérique spécifique pour un utilisateur donné. Les relations entre tous ces composants sont illustrées ci-dessous.

 

Diagramme illustrant comment Windows, les applications, les services et WNS fonctionnent ensemble pour fournir des données à une vignette d'application spécifique

 

Il est évident que des liaisons sont nécessaires pour que tous ces composants fonctionnent harmonieusement :

  1. Vous (le développeur) inscrivez l'application dans le Windows Store afin d'utiliser les notifications Push. Cette opération permet d'obtenir un identifiant de sécurité (SID) et une clé secrète client que le service utilise pour s'authentifier auprès des services de notifications Push Windows (WNS). Pour des raisons de sécurité, ces informations ne doivent jamais être stockées sur les périphériques client.
  2. Au moment de l'exécution, l'application demande un URI de canal de notifications Push Windows (WNS) auprès de Windows pour chacune de ses vignettes dynamiques (principales et secondaires) ou un seul pour les notifications brutes. Une application doit également actualiser ces URI de canaux tous les 30 jours, pour lesquels vous pouvez utiliser une autre tâche en arrière-plan.
  3. Le service de l'application fournit un URI par l'intermédiaire duquel l'application peut charger ces URI de canaux avec les données qui décrivent son utilisation (par exemple un lieu géographique pour les bulletins météo ou une activité et un compte d'utilisateur précis). Dès réception, le service stocke ces URI de canaux et les données associées pour les utiliser ultérieurement.
  4. Le service recherche sur le service principal les modifications à appliquer à chaque combinaison utilisateur/périphérique/application/vignette particulière. Lorsque le service détecte une condition qui déclenche une notification pour un canal particulier, il crée le contenu de cette notification (XML ou brute), s'authentifie auprès des services de notifications Push Windows (WNS) à l'aide de l'identifiant de sécurité (SID) et de la clé secrète client, puis il envoie la notification aux services de notifications Push Windows (WNS) avec l'URI de canal.

Examinons chaque étape en détail. (Si le fait d'aborder les requêtes HTTP vous inquiète, soyez rassuré car les services mobiles Windows Azure vous décharge d'un grand nombre de tâches, comme nous allons le voir.)

Inscription de l'application auprès du Windows Store

Pour obtenir l'identifiant de sécurité et la clé secrète client de votre service, consultez l'article Comment s’authentifier auprès des services de notifications Push Windows (WNS) sur le Centre de développement Windows. L'identifiant de sécurité permet d'identifier votre application auprès des services de notifications Push Windows (WNS) et la clé secrète client permet à votre service d'indiquer aux services de notifications Push Windows (WNS) qu'il est autorisé à envoyer des notifications pour votre application. Là encore, ces informations doivent uniquement être stockées dans le service.

Notez que vous ne devez suivre l'étape 4 de l'article Comment s’authentifier auprès des services de notifications Push Windows (WNS), intitulée « Envoyer les informations d’identification du serveur nuage à WNS » que lorsque votre service envoie une notification Push. Nous y reviendrons ultérieurement, car pour le moment, votre service ne dispose pas encore de l'élément essentiel à l'envoi d'une notification, c'est-à-dire un URI de canal.

Obtention et actualisation des URI de canaux

L'application client obtient des URI de canaux au moment de l'exécution via l'objet Windows.Networking.PushNotifications.PushNotificationChannelManager. Cet objet ne possède que deux méthodes :

  • createPushNotificationChannelForApplicationAsync : crée un URI de canal pour la vignette principale de l'application, ainsi que pour les toasts et les notifications brutes.
  • createPushNotificationChannelForSecondaryTileAsync : crée un URI de canal pour une vignette secondaire spécifique qui est identifiée par un argument tileId.

Le résultat des deux opérations asynchrones est un objet PushNotificationChannel. Cet objet contient l'URI de canal dans sa propriété Uri , ainsi qu'un élément ExpirationTime pour indiquer le délai d'actualisation du canal. Une méthode Close met fin spécialement au canal si cela est nécessaire et l'événement PushNotificationReceived est déclenché lorsque l'application se trouve au premier plan et qu'une notification Push est reçue à travers ce canal.

La durée de vie d'un URI de canal est de 30 jours, au terme desquels les services de notifications Push Windows (WNS) rejettent les requêtes formulées pour ce canal. Le code de l'application doit par conséquent actualiser ces URI avec les méthodes create ci-dessus au moins une fois tous les 30 jours et envoyer ces URI à son service. Voici comment procéder :

  • Lors du premier lancement, demandez un URI de canal et enregistrez la chaîne dans la propriété Uri de vos données d'application locales. Comme les URI de canaux sont spécifiques à un périphérique, ne les stockez pas dans vos données d'application itinérantes.
  • Lors des lancements suivants, redemandez un URI de canal et comparez-le avec celui qui a été enregistré auparavant. S'il est différent, communiquez-le au service ou envoyez-le et laissez le service en remplacer un plus ancien si cela est nécessaire.
  • Réalisez également l'étape précédente dans le gestionnaire Resuming de votre application (consultez l'article Lancement, reprise et multitâche), car il est possible que l'application ait été suspendue pendant plus de 30 jours.
  • Si vous pensez que l'application risque de ne pas être exécutée dans les 30 jours, implémentez une tâche en arrière-plan avec un déclencheur de maintenance devant s'exécuter à intervalle régulier ou une fois par semaine. Pour en savoir plus, reportez-vous à nouveau au billet Rester productif lorsque votre application n'est pas à l'écran : tâches en arrière-plan. La tâche en arrière-plan dans ce cas exécutera simplement le même code que l'application pour demander un canal et l'envoyer à votre service.

Envoi d'URI de canaux au service

En règle générale, les canaux des notifications Push fonctionnent avec des mises à jour propres à l'utilisateur (statut du courrier électronique, messages instantanés et autres informations personnalisées). Il est peu probable que votre service doive diffuser la même notification à chaque utilisateur et/ou chaque vignette. C'est pour cette raison que le service doit associer chaque URI de canal à des informations plus spécifiques. Pour une application de messagerie électronique, l'identificateur d'utilisateur est d'une importance capitale, car il indique quel compte vérifier. Une application de météo, quant à elle, associera probablement chaque URI de canal à une latitude et une longitude données, afin que chaque vignette (principales et secondaires) reflètent un lieu géographique différent.

L'application inclura ensuite ces détails lors de l'envoi d'un URI de canal à son service et le service devra les stocker pour les utiliser ultérieurement.

En ce qui concerne l'identité de l'utilisateur, il est préférable que l'application authentifie l'utilisateur séparément auprès du service, à l'aide des informations d'identification propres au service ou via un fournisseur OAuth, tel que Facebook, Twitter, Google ou le compte Microsoft de l'utilisateur (OAuth est utile avec les services mobiles Windows Azure, comme nous le verrons plus tard). Si cela n'est pas possible, veillez à chiffrer les identificateurs d'utilisateurs que vous communiquez au service ou envoyez-les avec le protocole HTTPS.

Dans tous les cas, c'est à vous de déterminer la manière dont vous envoyez toutes ces informations à votre service (dans les en-têtes, via des données dans le corps du message ou en tant que paramètres dans l'URI du service). Cette partie de la communication se passe strictement entre l'application et son service.

Prenons un exemple simple. Supposons que nous ayons un service doté d'une page nommée receiveuri.aspx (comme nous le verrons dans la prochaine section), dont l'adresse complète se trouve dans la variable url. Le code suivant demande un URI de canal principal auprès de Windows pour l'application et le publie sur cette page via HTTP. (Ce code, qui provient de manière simplifiée de l'exemple côté client des notifications Push et périodiques où la variable itemId est définie ailleurs, permet d'identifier les vignettes secondaires. L'exemple dispose également d'une variante C++, non illustrée ici) :

JavaScript :

 
Windows.Networking.PushNotifications.PushNotificationChannelManager
.createPushNotificationChannelForApplicationAsync()
.done(function (channel) {
//Typically save the channel URI to appdata here.
WinJS.xhr({ type: "POST", url:url,
headers: { "Content-Type": "application/x-www-form-urlencoded" },
data: "channelUri=" + encodeURIComponent(channel.uri)
+ "&itemId=" + encodeURIComponent(itemId)
}).done(function (request) {
//Typically update the channel URI in app data here.
}, function (e) {
//Error handler
});
});
           
C# :
 
using Windows.Networking.PushNotifications;

PushNotificationChannel channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
byte[] channelUriInBytes = Encoding.UTF8.GetBytes("ChannelUri=" + WebUtility.UrlEncode(newChannel.Uri) + "&ItemId=" + WebUtility.UrlEncode(itemId));

Task<Stream> requestTask = webRequest.GetRequestStreamAsync();
using (Stream requestStream = requestTask.Result)
{
requestStream.Write(channelUriInBytes, 0, channelUriInBytes.Length);
}

Le code ASP.NET suivant est une implémentation basique d'une page receiveuri.aspx qui traite cette requête HTTP POST, en s'assurant de recevoir un URI de canal valide, un utilisateur et un identifiant pour l'élément.

Je tiens à souligner la nature « basique » de ce code, car comme vous pouvez le voir, la fonction SaveChannel écrit simplement le contenu de la requête dans un fichier texte fixe, dont il est clair qu'il ne peut s'adapter qu'à un seul utilisateur ! Un service réel utiliserait évidemment une base de données à cet effet, mais la structure est similaire.

<%@ Page Language="C#" AutoEventWireup="true" %>

<script runat="server">

protected void Page_Load(object sender, EventArgs e)
{
//Output page header
Response.Write("<!DOCTYPE html>\n<head>\n<title>Register Channel URI</title>\n</head>\n<html>\n<body>");

//If called with HTTP GET (as from a browser), just show a message.
if (Request.HttpMethod == "GET")
{
Response.StatusCode = 400;
Response.Write("<p>This page is set up to receive channel URIs from a push notification client app.</p>");
Response.Write("</body></html>");
return;
}

if (Request.HttpMethod != "POST") {
Response.StatusCode = 400;
Response.Status = "400 This page only accepts POSTs.";
Response.Write("<p>This page only accepts POSTs.</p>");
Response.Write("</body></html>");
return;
}

//Otherwise assume a POST and check for parameters
try
{
//channelUri and itemId are the values posted from the Push and Periodic Notifications Sample in the Windows 8 SDK
if (Request.Params["channelUri"] != null && Request.Params["itemId"] != null)
{
// Obtain the values, along with the user string
string uri = Request.Params["channelUri"];
string itemId = Request.Params["itemId"];
string user = Request.Params["LOGON_USER"];

//TODO: validate the parameters and return 400 if not.

//Output in response
Response.Write("<p>Saved channel data:</p><p>channelUri = " + uri + "<br/>" + "itemId = " + itemId + "user = " + user + "</p>");

//The service should save the URI and itemId here, along with any other unique data from the app such as the user;
SaveChannel(uri, itemId, user);

Response.Write("</body></html>");
}
}
catch (Exception ex)
{
Trace.Write(ex.Message);
Response.StatusCode = 500;
Response.StatusDescription = ex.Message;
Response.End();
}
}
</script>

protected void SaveChannel(String uri, String itemId, String user)
{
//Typically this would be saved to a database of some kind; to keep this demonstration very simple, we'll just use
//the complete hack of writing the data to a file, paying no heed to overwriting previous data.

//If running in the debugger on localhost, this will save to the project folder
string saveLocation = Server.MapPath(".") + "\\" + "channeldata_aspx.txt";
string data = uri + "
~" + itemId + "~" + user;

System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] dataBytes = encoding.GetBytes(data);

using (System.IO.FileStream fs = new System.IO.FileStream(saveLocation, System.IO.FileMode.Create))
{
fs.Write(dataBytes, 0, data.Length);
}

return;
}

Le code de ce service se trouve au Chapitre 13 de mon livre électronique gratuit intitulé Programming Windows 8 Apps in HTML, CSS, and JavaScript, en particulier dans l'exemple HelloTiles des contenus d'accompagnement. Il est conçu pour fonctionner avec l'exemple SDK côté client référencé ci-dessus. Si vous exécutez HelloTiles dans le débogueur (Visual Studio 2012 Ultimate ou Visual Studio Express 2012 pour le Web) avec le localhost activé, vous obtenez une URL du type http://localhost:52568/HelloTiles/receiveuri.aspx que vous pouvez coller dans l'exemple SDK côté client. Lorsque l'exemple effectue ensuite une requête sur cette URL, vous vous arrêtez sur les points d'arrêt du service et pouvez exécuter le code pas à pas.

Envoi de la notification

Dans un service réel, un processus continu surveille ses sources de données et envoie des notifications Push à des utilisateurs spécifiques lorsque cela est requis. Ceci peut se produire de différentes manières :

  • Une tâche planifiée peut rechercher des alertes météo pour un lieu précis, disons, toutes les 15-30 minutes, selon la fréquence à laquelle ces alertes sont émises, et émettre des notifications Push en réponse.
  • Un autre service, tel qu'un service de messagerie principale, peut effectuer une requête sur une page de votre serveur lorsqu'un nouveau message est disponible. Cette page peut ensuite émettre la notification appropriée.
  • Des utilisateurs peuvent interagir avec des pages Web de votre serveur et leurs activités déclenchent des notifications Push vers des canaux précis.

En résumé, plusieurs déclencheurs peuvent être à l'origine des notifications Push, tout dépend entièrement de la nature de votre service principal ou du site Web. Dans le cadre de cet article, le même service d'exemple HelloTiles du Chapitre 13 de Programming Windows 8 Apps in HTML, CSS, and JavaScript comporte une page intitulée sendBadgeToWNS.aspx qui envoie une notification Push à chaque fois que vous consultez cette page dans un navigateur, à l'aide de l'URI de canal qui a été enregistré plus tôt dans le fichier texte. Un service réel effectue une recherche dans la base de données pour obtenir les URI de canaux au lieu de lire le contenu d'un fichier, mais je le répète, la structure globale est très similaire.

Page ASP.NET :

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="sendBadgeToWNS.aspx.cs" Inherits="sendBadgeToWNS" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Send WNS Update</title>
</head>
<body>
<p>Sending badge update to WNS</p>
</body>
</html>
 

code-behind C# :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;

public partial class sendBadgeToWNS : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//Load our data that was previously saved. A real service would do a database lookup here
//with user- or tile-specific criteria.
string loadLocation = Server.MapPath(".") + "\\" + "channeldata_aspx.txt
byte[] dataBytes;

using (System.IO.FileStream fs = new System.IO.FileStream(loadLocation, System.IO.FileMode.Open))
{
dataBytes = new byte[fs.Length];
fs.Read(dataBytes, 0, dataBytes.Length);
}

if (dataBytes.Length == 0)
{
return;
}

System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();

string data = encoding.GetString(dataBytes);
string[] values = data.Split(new Char[] { '~' });
string uri = values[0]; //Channel URI
string secret = "9ttsZT0JgHAFveYahK1B6jQbvMOIWYbm";
string sid = "
ms-app://s-1-15-2-2676450768-845737348-110814325-22306146-1119600341-293560589-2707026538";

//Create some simple XML for a badge update
string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
xml += "<badge value='alert'/>";

PostToWns(secret, sid, uri, xml, "wns/badge");
}
}

 

Nous extrayons ici l'URI de canal, créons la charge utile XML, puis nous authentifions auprès des services de notifications Push Windows (WNS) et envoyons une requête HTTP POST à cet URI de canal. Les deux dernières étapes s'effectuent dans la fonction PostToWns qui provient de la rubrique Démarrage rapide : envoi d’une notification Push sur le Centre de développement Windows. Je ne mentionne pas la liste complète, car l'authentification s'effectue simplement auprès des services de notifications Push Windows (WNS) via OAuth (sur https://login.live.com/accesstoken.srf) à l'aide de votre clé secrète client et de votre identifiant de sécurité obtenus dans le Windows Store. Cette authentification permet d'obtenir un jeton d'accès qui est ensuite intégré à la requête HTTP POST que nous envoyons à l'URI de canal :

C# :

public string PostToWns(string secret, string sid, string uri, string xml, string type = "wns/badge")
{
try
{
// You should cache this access token
var accessToken = GetAccessToken(secret, sid);

byte[] contentInBytes = Encoding.UTF8.GetBytes(xml);

// uri is the channel URI
HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
request.Method = "POST";
request.Headers.Add("X-WNS-Type", type);
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken));

using (Stream requestStream = request.GetRequestStream())
requestStream.Write(contentInBytes, 0, contentInBytes.Length);

using (HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse())
return webResponse.StatusCode.ToString();
}
catch (WebException webException)
{
// Implements a maximum retry policy (omitted)
}
}

Dans cet exemple, notez que l'en-tête X-WNS-Type dans la requête HTTP est défini sur wns/badge et que l'en-tête Content-Type est défini par défaut sur text/xml. Pour les vignettes, le type doit être wns/tile. Les toasts utilisent wns/toast. Concernant les notifications brutes, utilisez le type wns/raw et définissez Content-Type sur application/octet-stream. Pour plus d'informations sur les en-têtes, consultez la page En-têtes des demandes et des réponses des services de notifications Push de la documentation.

Échec des notifications Push

L'envoi d'une requête HTTP ne fonctionne évidemment pas toujours et plusieurs raisons peuvent expliquer pourquoi WNS peut répondre avec un code autre que le code 200 (réussite). Pour plus d'informations, consultez la section « Code de réponse » de la page En-têtes des demandes et des réponses des services de notifications Push. Vous y trouverez des erreurs communes et les causes :

  • L'URI de canal n'est pas valide (404 Introuvable) ou a expiré (410 Supprimé). Dans ce cas, le service doit supprimer l'URI de canal de sa base de données et ne plus lui envoyer de requêtes.
  • La clé secrète client et l'identifiant de sécurité ne sont peut-être pas valides (401 Non autorisé) ou l'identifiant du package de l'application dans le manifeste et celui qui se trouve dans le Windows Store ne correspondent pas (403 Interdit). Pour s'assurer qu'ils correspondent, il est préférable d'utiliser la commande de menu Windows Store > Associer l'application au Windows Store dans Visual Studio (cette commande se trouve dans le menu Projet de Visual Studio 2012 Ultimate).
  • La charge utile de la notification brute dépasse 5 Ko (413 Entité de demande trop grande).
  • Le client peut être hors connexion, auquel cas WNS réessaie automatiquement, mais finit par signaler un échec. Pour les notifications XML, le comportement par défaut est que les notifications Push sont mises en cache et livrées lorsque le client se reconnecte. Pour les notifications brutes, la mise en cache est désactivée par défaut. Vous pouvez modifier ce comportement en définissant l'en-tête X-WNS-Cache-Policy sur cache dans la requête envoyée à l'URI de canal.

Pour les autres erreurs (400 Requête incorrecte), veillez à ce que les charges utiles XML contiennent du texte encodé en UTF-8 et que les notifications brutes soient en base64 avec l'en-tête Content-Type défini sur application/octet-stream. Il est également possible que WNS limite l'aboutissement des requêtes parce que vous essayez simplement d'envoyer trop de notifications Push au sein d'une période donnée.

Une notification Push brute peut également être rejetée si l'application ne se trouve pas sur l'écran de verrouillage et si l'appareil se trouve en mode de veille connectée. Comme Windows bloque les notifications brutes sur les applications qui ne se trouvent pas sur l'écran de verrouillage dans cet état (et à chaque fois que l'application n'est pas au premier plan), WNS supprime les notifications qui, d'après lui, ne parviendront pas à destination.

Services mobiles Windows Azure

Maintenant que nous avons passé en revue tous les détails de l'utilisation des notifications Push, même sans mentionner la question du stockage, vous vous demandez probablement s'il existe un moyen de simplifier tout cela ? Imaginez ce que cela serait de gérer des milliers ou des millions d'URI de canaux pour une clientèle vaste et grandissante !

Heureusement, la question s'est déjà posée. Outre les solutions tierces, telles que celles proposées par Urban Airship, les services mobiles Windows Azure peuvent simplifier énormément les choses.

Les services mobiles Windows Azure offrent une solution prédéfinie (en fait, plusieurs points de terminaison REST) pour la plupart des détails des services que nous allons aborder. Un « service mobile » gère une base de données en votre nom et offre des fonctions de bibliothèque afin d'envoyer facilement les charges utiles à WNS. Les services mobiles Windows Azure sont présentés dans le billet Connectez votre application au cloud avec les services mobiles Windows Azure.

Pour les notifications Push en particulier, récupérez d'abord la bibliothèque côté client dans le SDK des services mobiles Windows Azure pour Windows 8. Reportez-vous ensuite à la rubrique Get started with push notifications in Mobile Services sur l'utilisation des notifications Push dans les services mobiles (notez qu'il existe également une version JavaScript de cette rubrique) pour savoir comment les services mobiles Windows Azure peuvent vous aider à remplir toutes les conditions que nous avons vues plus tôt en terme de liaisons :

  • Inscription de l'application auprès du Windows Store : après avoir obtenu la clé secrète client et l'identifiant de sécurité de votre application auprès du Windows Store, enregistrez ces données dans la configuration des services mobiles. Consultez la section « Register your app for the Windows Store » (Inscription de votre application pour le Windows Store) de la rubrique Get started que nous venons de mentionner.
  • Obtention et actualisation des URI de canaux : la demande et la gestion des URI de canaux dans l'application s'effectuent uniquement côté client et sont les mêmes qu'auparavant.
  • Envoi d'URI de canaux au service : cette étape devient beaucoup plus facile avec les services mobiles Windows Azure. Vous commencez par créer une table de base de données dans le service mobile (via le portail Windows Azure). Ensuite, l'application peut simplement insérer des enregistrements dans cette table avec les URI de canaux et toute autre information importante que vous devez joindre. La bibliothèque cliente des services mobiles Windows Azure se charge de la requête HTTP en arrière-plan et actualise même l'enregistrement côté client en intégrant les modifications effectuées sur le serveur. En outre, les services mobiles Windows Azure peuvent gérer automatiquement l'authentification via le compte Microsoft de l'utilisateur ou via trois autres fournisseurs OAuth (Facebook, Twitter ou Google) si vous avez inscrit votre application auprès de l'un d'eux. Consultez la rubrique Get started with authentication in Mobile Services sur l'authentification dans les services mobiles.
  • Envoi de la notification : au sein du service mobile, vous pouvez joindre des scripts (écrits dans la variante de JavaScript connue sous le nom de Node.js) à des opérations de base de données, ainsi que des tâches planifiées créées dans JavaScript. Dans ces scripts, un simple appel à l'objet push.wns avec un URI de canal et une surcharge génère la requête HTTP nécessaire sur le canal. Il est également simple de capturer les échecs des notifications Push et d'enregistrer la réponse avec console.log. Ces journaux sont facilement consultables sur le portail Windows Azure.

Pour en savoir plus, consultez des deux didacticiels d'exemple : Tile, Toast, and Badge Push Notifications using Windows Azure Mobile Services et Raw Notifications using Windows Azure Mobile Services. Au lieu de répéter toutes ces instructions, passons en revue certains des points principaux.

Lorsque vous configurez un service mobile, il est doté d'une URL de service spécifique. Elle vous permettra de créer une instance de l'objet MobileServiceClient dans le SDK des services mobiles Windows Azure :

JavaScript :

var mobileService = new Microsoft.WindowsAzure.MobileServices.MobileServiceClient(
"https://{mobile-service-url}.azure-mobile.net/",
"{mobile-service-key}");

C# :

using Microsoft.WindowsAzure.MobileServices;

MobileServiceClient MobileService = new MobileServiceClient(
"https://{mobile-service-url}.azure-mobile.net/",
"{mobile-service-key}");

C++ (issu d'un exemple supplémentaire) :

using namespace Microsoft::WindowsAzure::MobileServices;

auto MobileService = ref new MobileServiceClient(
ref new Uri(L" https://{mobile-service-url}.azure-mobile.net/"),
ref new String(L"{mobile-service-key}"));

Cette classe encapsule toute la communication HTTP avec le service, ce qui vous permet d'éviter tous les tâches de niveau inférieur sur lesquelles vous préférez probablement ne pas vous pencher.

Pour vous authentifier auprès d'un fournisseur OAuth précis, utilisez la méthode login ou LoginAsync, qui permet d'obtenir un objet User qui communique cette information à l'application. (Une fois l'authentification réalisée, la propriété CurrentUser de l'objet client contient également l'identificateur d'utilisateur.) Lorsque vous authentifiez le service mobile directement comme ceci, le service a accès à l'identificateur d'utilisateur et le client n'a pas besoin de l'envoyer explicitement :

JavaScript :

mobileService.login("facebook").done(function (user) { /* ... */ });
mobileService.login("twitter").done(function (user) { /* ... */ });
mobileService.login("google").done(function (user) { /* ... */ });
mobileService.login("microsoftaccount").done(function (user) { /* ... */ });

C# :

MobileServiceUser user = await MobileService.LoginAsync(MobileServiceAuthenticationProvider.Facebook);
MobileServiceUser user = await MobileService.LoginAsync(MobileServiceAuthenticationProvider.Twitter);
MobileServiceUser user = await MobileService.LoginAsync(MobileServiceAuthenticationProvider.Google);
MobileServiceUser user = await MobileService.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);

C++ :

task<MobileServiceUser^> (MobileService->LoginAsync(MobileServiceAuthenticationProvider::Facebook))
.then([this](MobileServiceUser^ user) { /* */ } );
task<MobileServiceUser^> (MobileService->LoginAsync(MobileServiceAuthenticationProvider::Twitter))
.then([this](MobileServiceUser^ user) { /* */ } );
task<MobileServiceUser^> (MobileService->LoginAsync(MobileServiceAuthenticationProvider::Google))
.then([this](MobileServiceUser^ user) { /* */ } );
task<MobileServiceUser^> (MobileService->LoginAsync(MobileServiceAuthenticationProvider::MicrosoftAccount))
.then([this](MobileServiceUser^ user) { /* */ } );

L'envoi d'un URI de canal au service est simple : un enregistrement est stocké dans la base de données du service et l'objet client effectue les requêtes HTTP. Pour ce faire, demandez simplement l'objet de base de données et insérez l'enregistrement comme illustré dans les exemples ci-dessous issus du didacticiel d'exemple sur les notifications Push référencés plus haut. Dans chaque extrait de code, supposons que ch contient l'objet PushNotificationChannel des API WinRT. Vous pouvez également inclure d'autres propriétés dans l'objet channel qui est élaboré, par exemple un identifiant de vignette secondaire ou d'autres données permettant d'identifier l'objectif du canal.

JavaScript :

var channelTable = MobileServicesSample.mobileService.getTable('Channels');

var channel = {
uri: ch.uri,
expirationTime: ch.expirationTime.
};

channelTable.insert(channel).done(function (item) {

},
function () {
// Error on the insertion.
});
}

C# :

var channel = new Channel { Uri = ch.Uri, ExpirationTime = ch.ExpirationTime };
var channelTable = privateClient.GetTable<Channel>();

if (ApplicationData.Current.LocalSettings.Values["ChannelId"] == null)
{
// Use try/catch block here to handle exceptions
await channelTable.InsertAsync(channel);
}

C++ :

auto channel = ref new JsonObject();
channel->Insert(L"Uri", JsonValue::CreateStringValue(ch->Uri));
channel->Insert(L"ExpirationTime", JsonValue::CreateBooleanValue(ch->ExpirationTime));

auto table = MobileService->GetTable("Channel");
task<IJsonValue^> (table->InsertAsync(channel))
.then([this, item](IJsonValue^ V) { /* ... */ });

Notez qu'une fois l'enregistrement de canal inséré, les modifications ou ajouts que ce service a pu apporter à cet enregistrement seront répercutés dans le client.

De plus, si vous orthographiez incorrectement le nom de la base de données dans l'appel GetTable/getTable, vous ne verrez aucune exception tant que vous n'essayez pas d'insérer un enregistrement. Ce problème pouvant être difficile à déceler, si vous êtes convaincu que tout devrait fonctionner alors que tel n'est pas le cas, vérifiez le nom de cette base de données.

Je le répète, ces insertions côté client sont converties en requêtes HTTP pour le service, mais même côté service, vous ne pouvez pas voir ce processus. Au lieu de recevoir et de traiter les requêtes, vous joignez des scripts personnalisés à chaque opération de base de données (insertion, lecture, mise à jour et suppression).

Ces scripts sont écrits sous forme de fonctions JavaScript à l'aide des mêmes objets et méthodes intrinsèques qui sont disponibles dans Node.js (aucun d'entre eux n'a quoi que ce soit à voir avec JavaScript côté client dans l'application). Chaque fonction reçoit les paramètres appropriés : insert et update reçoivent un nouvel enregistrement, delete reçoit l'identifiant de l'élément et read reçoit une requête. Toutes les fonctions reçoivent également un objet user si l'application a authentifié l'utilisateur auprès du service mobile et un objet request qui vous permet d'exécuter l'opération et de générer ce qui devient la réponse HTTP.

Le script le plus simple (celui par défaut insert exécute simplement la requête et insère l'enregistrement item tel quel :

function insert(item, user, request) {
request.execute();
}

Si vous souhaitez joindre un horodateur et un identificateur d'utilisateur à l'enregistrement, il suffit d'ajouter ces propriétés au paramètre item avant d'exécuter la requête :

function insert(item, user, request) {
item.user = user.userId;
item.createdAt = new Date();
request.execute();
}

Notez que les modifications apportées à item dans ces scripts avant l'insertion dans la base de données sont automatiquement repropagées dans le client. Dans le code ci-dessus, l'objet channel dans le client contient les propriétés user et createdAt une fois l'insertion réussie. Très pratique !

Les scripts de service peuvent également effectuer des actions supplémentaires après request.execute, en particulier suite à une réussite ou à un échec, mais vous trouverez tous les détails dans la documentation Server script example how tos.

Pour en revenir aux notifications Push, l'enregistrement d'URI de canaux dans une table ne constitue qu'une partie de l'équation et le service peut ou non envoyer des notifications en réponse à cet événement précis. Il est plus probable que le service dispose d'autres tables avec des informations complémentaires, et que les opérations effectuées dans ces tables déclenchent des notifications vers un sous-ensemble d'URI de canaux. Nous aborderons quelques exemples dans la section suivante. Quoi qu'il en soit, vous envoyez une notification Push à partir d'un script à l'aide de l'objet push.wns. Il existe là encore de nombreuses méthodes pour envoyer des types spécifiques de mises à jour (notamment brutes), où les vignettes, toasts et badges utilisent des méthodes de noms qui correspondent aux modèles disponibles. Par exemple :

push.wns.sendTileSquarePeekImageAndText02(channel.uri, {
image1src: baseImageUrl + "image1.png",
text1: "Notification Received",
text2: item.text
}, {
success: function (pushResponse) {
console.log("Sent Tile Square:", pushResponse);
},
error: function (err) {
console.log("Error sending tile:", err);
}

});

push.wns.sendToastImageAndText02(channel.uri, {
image1src: baseImageUrl + "image2.png",
text1: "Notification Received",
text2: item.text
}, {
success: function (pushResponse) {
console.log("Sent Toast:", pushResponse);
}
});

push.wns.sendBadge(channel.uri, {
value: value,
text1: "Notification Received"
}, {
success: function (pushResponse) {
console.log("Sent Badge:", pushResponse);
}
});

La fonction console.log crée là encore une entrée dans les journaux que vous pouvez consulter sur le portail des services Azure Mobile. En règle générale, il convient d'inclure les appels de journaux dans des gestionnaires d'erreurs, comme illustré dans la notification de vignette ci-dessous.

Vous avez peut-être remarqué que les méthodes send* sont chacune liées à un modèle particulier. Pour les vignettes, cela signifie que les charges utiles larges et carrées doivent être envoyées séparément sous forme de deux notifications. N'oubliez pas qu'il est presque toujours préférable d'envoyer les deux tailles ensemble, car c'est l'utilisateur qui détermine la manière dont la vignette s'affiche sur son écran d'accueil. Avec les fonctions send de push.wns spécifiques au modèle, cela implique l'émission de deux appels séquentiels qui génèrent chacun une notification Push distincte.

Pour combiner plusieurs mises à jour, ce qui implique l'envoi simultané de plusieurs mises à jour de vignettes avec différentes balises ou l'envoi de plusieurs toasts, utilisez les méthodes push.wns.sendTile et push.wns.sendToast. Par exemple :

var channel = '{channel_url}';

push.wns.sendTile(channel,
{ type: 'TileSquareText04', text1: 'Hello' },
{ type: 'TileWideText09', text1: 'Hello', text2: 'How are you?' },
{ client_id: '{your Package Security Identifier}', client_secret: '{your Client Secret}' },

function (error, result) {
// ...
});

Si l'on se place à un niveau encore plus bas, la méthode push.wns.send vous permet d'être très exact en ce qui concerne le contenu des notifications. La méthode push.wns.sendRaw permet quant à elle de réaliser des notifications brutes. Pour en savoir plus, reportez-vous à nouveau à la documentation sur l'objet push.wns.

Scénarios réels avec les services mobiles Windows Azure

L'application d'exemple de la page Tile, Toast, and Badge Push Notifications using Windows Azure Mobile Services illustre comment envoyer des notifications Push en réponse à l'insertion d'un nouveau message dans une table de base de données. Cela signifie toutefois que l'application finit par s'envoyer une notification Push à elle-même, ce qui n'est en général pas nécessaire (sauf peut-être pour envoyer des notifications à la même application sur les autres périphériques de l'utilisateur).

Le plus probable, c'est que le service envoie des notifications Push en réponse à des événements qui se produisent en dehors de l'application/vignette qui reçoit ces notifications. Prenons ces scénarios :

  • Utilisation des réseaux sociaux :

Les applications peuvent utiliser le réseau social d'un utilisateur pour implémenter des fonctionnalités, par exemple pour mettre au défi les amis d'un utilisateur. Lorsqu'un utilisateur parvient à un nouveau score élevé dans un jeu, vous pouvez lancer des défis via des mises à jour de vignettes ou des toasts aux amis de l'utilisateur qui ont également installé ce jeu. Cela est également possible dans les applications de remise en forme, où vous pouvez par exemple publier un nouveau meilleur résultat pour un certain type d'activité.

Pour ce faire, l'application peut insérer un nouvel enregistrement dans la table du service mobile approprié (Scores, BestTimes, etc.). Au sein du script d'insertion, le service interroge sa base de données pour connaître les amis appropriés de l'utilisateur en cours, puis envoie des notifications à ces URI de canaux. Des critères de requête supplémentaires décrivent l'aspect exact d'un jeu, le type précis d'exercice (pour les vignettes secondaires), etc.

  • Bulletins et alertes météo :

Les application de météo vous permettent en général d'attribuer un lieu géographique à la vignette principale de l'application et de créer des vignettes secondaires pour d'autres lieux. Les informations importantes dans chaque vignette sont la latitude et la longitude du lieu, que l'application envoie au service avec chaque URI de canal (en les insérant dans une table). Pour déclencher une mise à jour sur ce canal, le service peut faire appel à un autre processus (par exemple une tâche planifiée décrite ci-dessus) qui interroge régulièrement un service de météo central pour connaître les bulletins et les alertes, puis traite ces réponse et insère les messages appropriés dans une table d'alertes du service mobile. Le script d'insertion récupère ensuite les URI de canaux appropriés et envoie les bulletins. De même, si un service de météo lui-même vous permet de vous inscrire à des alertes ou à des bulletins réguliers, une autre page du service reçoit ces requêtes (HTTP PUT, très probablement), les traite, puis appelle le service mobile pour insérer un enregistrement, ce qui déclenche une mise à jour.

  • Messages :

La gestion des messages instantanés ressemble beaucoup à la réception des bulletins météo. Pourtant, un autre processus surveille la réception de nouveaux messages, par exemple celui qui vérifie régulièrement les messages entrants ou s'inscrit auprès de la source des messages pour recevoir des alertes lorsque de nouveaux messages arrivent. Dans tous les cas, l'arrivée d'un nouveau message déclenche des notifications Push sur les canaux appropriés. Dans ce cas, les URI de canaux sont associés à la vignette d'un utilisateur pour un type particulier de messages. Il convient ici d'utiliser les notifications brutes, car ce cas ressemble au scénario de messagerie électronique décrit au début de ce billet.

Dans tous ces scénarios, notez qu'il n'est en fait pas nécessaire d'insérer quoi que ce soit dans une table de base de données. Si vous n'appelez pas request.execute dans le script d'insertion, rien ne se retrouve dans la base de données, mais vous pouvez toute de même effectuer d'autres tâches au sein de ce script, par exemple envoyer des notifications. En d'autres termes, il n'est pas nécessaire de renseigner une base de données avec des enregistrements que vous n'allez pas utiliser, en particulier parce que le stockage de données entraîne un certain coût.

Notez par ailleurs que les services mobiles Azure disposent d'une fonction de planification des tâches. Consultez la page Schedule recurring jobs in Mobile Services pour en savoir plus sur la planification des tâches récurrentes dans les services mobiles. Ces tâches sont capables d'extraire régulièrement des données d'autres services, de les traiter et d'insérer des enregistrements dans la base de données du service, ce qui déclenche à nouveau des notifications Push. De même, comme nous l'avons indiqué dans la deuxième partie de cette série, d'autres pages Web et applications mobiles peuvent également apporter des modifications dans cette base de données et déclencher des notifications Push. Les scripts de base de données dans le service mobile s'exécuteront dans tous ces cas.

Pour conclure

Pour conclure cette série, nous avons exploré toute l'étendue de ce qu'implique un « système animé et dynamique » du côté des utilisateurs, des développeurs, des applications et des services. Nous avons vu les fonctionnalités des mises à jour de vignette, de badge et de toast, comment configurer des notifications périodiques, comment utiliser des tâches d'arrière-plan dans le cadre de ce processus, ainsi que la structure des services pour gérer les notifications périodiques et Push. Il se dégage clairement que les services mobiles Windows Azure offrent une vision de niveau bien supérieur de tout le processus d'utilisation des notifications Push. Ils peuvent sans aucun doute vous aider à être beaucoup plus productif qu'en écrivant des services entièrement nouveaux.

Kraig Brockschmidt
Chef de projet, équipe Écosystème Windows
Auteur de Programming Windows 8 Apps in HTML, CSS, and JavaScript

  • Loading...
Leave a Comment
  • Please add 6 and 3 and type the answer here:
  • Post