Création d'une expérience utilisateur optimale en matière de vignettes (deuxième partie)

Dans la première partie de ce billet, nous avons découvert comment concevoir des mises à jour pour les vignettes et choisir des modèles adaptés au contenu à afficher dans la vignette dynamique. Nous avons configuré l'application avec une vignette par défaut large et nous pouvons maintenant commencer à mettre à jour nos vignettes. Nous allons regarder le code de plus près. Nous commencerons par découvrir comment configurer l'interrogation dans la vignette de l'application Contoso Food Trucks et par examiner notamment le code de notre service Web. Nous ajouterons ensuite une vignette secondaire à l'application, que nous mettrons à jour en utilisant la bibliothèque NotificationsExtension fournie dans l'exemple de vignettes et de badges d'application créés avec le SDK Windows 8. Allons-y !

Choix du mode de distribution d'une notification

Maintenant que je sais à quoi mes vignettes doivent ressembler (voir la première partie), je dois déterminer quand les mettre à jour.

Une application peut mettre à jour sa vignette de quatre façons différentes (voir Sélection d'un mode de distribution des notifications dans le Centre de développement). Les applications peuvent utiliser des notifications locales pour mettre à jour leur vignette, ce qui est utile si les informations changent alors que l'application est en cours d'exécution. Les applications peuvent planifier des mises à jour de la vignette et du toast à des horaires bien précis. En outre, elles peuvent utiliser des notifications de type push ou des notifications par interrogation pour mettre à jour leurs vignettes à partir du cloud lorsqu'elles ne sont pas en cours d'exécution. L'interrogation est idéale pour les contenus de diffusion qui ne sont pas mis à jour très souvent. Le mode push est parfait pour l'envoi de notifications toast, qui doivent arriver immédiatement, mais aussi pour les mises à jour de vignette qui ciblent des utilisateurs individuels. Dans ce billet, j'aborde principalement les mises à jour par interrogation et les mises à jour locales.

Interrogation pour la détection des restaurants ambulants à proximité

Notre application dispose de deux types d'informations différents pour mettre à jour la vignette. Les restaurants ambulants à proximité du lieu de déjeuner par défaut de l'utilisateur constituent l'information la plus importante. Les utilisateurs définissent dans l'application le lieu par défaut où ils ont l'habitude de prendre leur déjeuner. Ce lieu par défaut est utilisé pour mettre à jour la vignette et indiquer à l'utilisateur quels restaurants ambulants se trouvent à proximité. Les images ci-dessous montrent les vignettes de l'application, issues de la première partie de ce billet. Examinons maintenant comment utiliser l'interrogation pour que ces vignettes s'affichent dans la vignette de notre application.

La vignette large rectangulaire affiche les informations suivantes : restaurants ambulant à proximité / Nom Nom Barbecue Truck / Sushi Truck / Macaroni Makin' Wagon    La vignette carrée affiche les informations suivantes : À proximité / Nom Nom / Sushi Truck

En général, les restaurants ambulants restent toute la journée au même endroit ou au moins pendant les heures de déjeuner. Comme la position ne change pas souvent, je n'ai pas besoin de mettre à jour la vignette en temps réel. Par conséquent, je peux d'ores et déjà éliminer les notifications de type push, qui sont plus utiles pour les notifications devant être transmises rapidement. Je souhaite cependant que les données soient mises à jour au moins une fois par jour. Dans ce cas, la meilleure solution consiste à utiliser des notifications périodiques qui interrogent mon service Web afin de détecter les modifications.

Implémentation côté client : interrogation pour la détection des restaurants ambulants à proximité

Quelques lignes de code suffisent pour implémenter des notifications périodiques côté client. Nous appelons la méthode TileUpdater.startPeriodicUpdate à chaque fois qu'un utilisateur lance l'application ou bascule vers cette application. L'URI transmis à l'API est ainsi interrogé immédiatement, et la vignette est mise à jour à chaque lancement de l'application ou à chaque basculement vers cette dernière. En effet, l'appel d'API contacte immédiatement l'URI du service cloud et met à jour la vignette. Ce comportement est très utile pour le débogage : nous pouvons tester l'interrogation de notre service cloud sans devoir attendre le prochain intervalle d'interrogation.

Une question importante se pose : quel URI faut-il fournir à l'API startPeriodicUpdate ? Dans notre cas, je souhaite que notre service cloud mette à jour la vignette en y insérant des informations sur un lieu spécifique. Pour protéger les informations de localisation de l'utilisateur, je ne souhaite pas envoyer la position exacte de l'utilisateur au service. Ainsi, j'identifie les lieux en fonction du code postal indiqué par l'utilisateur dans l'application.

Pour transmettre le code postal à mon service Web, j'ajoute une chaîne de requête à la fin de l'URI d'interrogation, pour indiquer au service cloud le lieu à afficher dans la vignette :

https://www.contoso.com/foodtrucks/tile.xml?zipcode=98052

En réponse à une requête HTTP GET ciblant cet URI, notre service Web renvoie le code XML de notification de vignette mise en forme, pour le code postal indiqué dans l'URI. Voici le code permettant de configurer l'interrogation, avec le code postal codé en clair dans la chaîne d'URI.

JavaScript :

 // update the tile poll URI
var notifications = Windows.UI.Notifications;
var polledUri = new Windows.Foundation.Uri("https://www.contoso.com/foodtrucks/tile.xml?zipcode=98052");
var recurrence = notifications.PeriodicUpdateRecurrence.hour;
var tileUpdater = notifications.TileUpdateManager.createTileUpdaterForApplication();
tileUpdater.startPeriodicUpdate(polledUri, recurrence);

C# :

 // update the tile poll URI
using Windows.UI.Notifications;
Uri polledUri = new Uri("https://www.contoso.com/foodtrucks/tile.xml?zipcode=98052");
PeriodicUpdateRecurrence recurrence = PeriodicUpdateRecurrence.Hour;
TileUpdateManager.CreateTileUpdaterForApplication().StartPeriodicUpdate(polledUri, recurrence);

Comme un restaurant ambulant est susceptible de se déplacer au cours de la journée, je souhaite mettre à jour la vignette assez fréquemment. Dans notre cas, j'utilise un intervalle de mise à jour d'une heure pour trouver un juste équilibre entre la charge imposée à notre service principal et le niveau d'actualisation des informations affichées dans la vignette.

À compter du premier appel de l'API startPeriodicUpdate, la vignette est mise à jour une fois par heure, même si l'application n'est pas en cours d'exécution. Si je souhaite modifier l'URI à interroger, il me suffit d'appeler à nouveau l'API en utilisant un autre URI. Par exemple, si l'utilisateur change le code postal de sa position par défaut, je peux mettre à jour l'URI en utilisant le code postal adéquat. Pour cela, j'appelle à nouveau la méthode startPeriodicUpdate. Si l'utilisateur efface sa position par défaut ou souhaite interrompre les mises à jour de la vignette, l'application peut mettre un terme aux mises à jour périodiques en appelant l'API startPeriodicUpdate.

Pour plus d'informations sur l'utilisation de l'API startPeriodicUpdate, consultez l'exemple de notifications de type push et de notifications périodiques côté client, ainsi que l'article Procédure de configuration des notifications périodiques des vignettes dans le Centre de développement.

Implémentation côté serveur : interrogation pour la détection des restaurants ambulants à proximité

Nous pouvons implémenter la partie serveur de notre interrogation de vignette dans presque n'importe quelle technologie de service. Voici un exemple de code PHP et ASP.NET.

Lorsque notre service Web est interrogé, il doit répondre à la requête HTTP GET en renvoyant du code XML adapté au schéma XML de la vignette. Vous pouvez également utiliser le protocole HTTPS, de sorte que le service Web puisse protéger le contenu pendant la transmission. Les cookies ne sont pas pris en charge. Toutes les informations dont votre service a besoin pour répondre à la requête doivent être incluses dans l'URI. Par conséquent, notre application utilise des chaînes de requête pour transmettre le code postal.

Dans le code PHP ci-dessous, je fais abstraction de l'accès à la base de données de notre service Web. En conditions réelles, la variable trucks renvoyée par la fonction get_trucks_from_database() contiendrait toutes les informations dont le service Web a besoin pour remplir le modèle de vignette pour un code postal donné. J'ai simplifié quelque peu ce code d'exemple de service, pour mettre l'accent sur le code XML renvoyé par le service. Un déploiement de service Web en conditions réelles prendrait en compte les performances, l'extensibilité, la sécurité, ainsi que les possibilités de maintenance de l'architecture.

PHP :

 <?php

//
// set default query string parameters
// process query string and set parameters
//
if($_GET['zipcode']){
  $zipcode = $_GET['zipcode'];
}
else{
  $zipcode = 'default';
}

//
// get item info from our database
// - this is placeholder code that you need to replace in a real implementation
// - the return value is a multidimensional array of the long and short strings
//   to place in the tile template
//
$trucks = get_trucks_from_database($zipcode);

?>
<?php echo '<?xml version="1.0" encoding="utf-8" ?>'?>
<tile>
  <visual>
    <binding template="TileWideText01">
      <text id="1">Food Trucks Near You</text>
      <text id="2"><?php echo $trucks[0][0]?></text>
      <text id="3"><?php echo $trucks[0][1]?></text>
      <text id="4"><?php echo $trucks[0][2]?></text>
    </binding>
    <binding template="TileSquareText03">
      <text id="1">Near You</text>
      <text id="2"><?php echo $trucks[1][0]?></text>
      <text id="3"><?php echo $trucks[1][1]?></text>
    </binding>
  </visual>
</tile>

L'exemple de code suivant équivaut au code PHP ci-dessus. Cet exemple ASP.NET Web Pages illustre l'implémentation rapide d'un service de vignette. Pour un service ASP.NET complet, vous utiliserez plutôt la nouvelle API Web ASP.NET. L'API Web ASP.NET est conçue spécialement pour les services HTTP comme celui-ci. Pour plus d'informations sur l'API Web ASP.NET, voir https://www.asp.net/web-api.

ASP.NET :

 @{
  //
  // set default query string parameters  
  // process query string and set parameters
  //
  var zipcode = Request["zipcode"] ?? "default";
  //
  // get item info from our database
  // - this is placeholder code that you need to replace in a real implementation
  // - the return value is a multidimensional array of the long and short strings
  // to place in the tile template
  var trucks = get_trucks_from_database(zipcode);
 
}<?xml version="1.0" encoding="utf-8" ?>'?>
<tile>
  <visual>
    <binding template="TileWideText01">
      <text id="1">Food Trucks Near You</text>
      <text id="2">@trucks[0,0]</text>
      <text id="2">@trucks[0,1]</text>
    </binding>
    <binding template="TileSquareText03">
      <text id="1">Near You</text>
      <text id="2">@trucks[1,0]</text>
      <text id="2">@trucks[1,1]</text>
    </binding>
  </visual>
</tile>

Restaurants ambulants préférés

Jusqu'à présent, nous avons examiné le contenu affiché par l'application dans la vignette principale. Il peut arriver qu'un utilisateur souhaite que la vignette de son écran d'accueil suive un restaurant ambulant en particulier. Dans notre application, j'utilise la barre des applications pour permettre à l'utilisateur de suivre un restaurant ambulant spécifique dans l'écran d'accueil. Ces vignettes épinglées sont appelées « vignettes secondaires ». Si un utilisateur épingle une vignette secondaire, nous mettons à jour cette vignette en insérant des informations sur un restaurant ambulant, à travers des notifications envoyées à la vignette.

Épinglage d'une vignette de restaurant ambulant

Grâce à l'épinglage des vignettes, l'utilisateur peut accéder à un contenu précis de notre application, directement à partir de l'écran d'accueil. Les vignettes secondaires peuvent être utilisées pour lancer notre application directement dans la partie de l'application consacrée au restaurant ambulant épinglé par l'utilisateur.

Les vignettes épinglées ne peuvent être créées qu'au sein même d'une application. Les utilisateurs souhaitent pouvoir épingler des vignettes en appelant la barre des applications. Celle-ci contient une icône standard représentant une punaise, indiquant à l'utilisateur qu'il peut épingler le contenu affiché.

Lorsque l'utilisateur appuie sur cette icône, un menu volant s'ouvre et affiche un aperçu de la vignette sur le point d'être épinglée.

Menu volant contenant une image du restaurant ambulant Nom Nom Barbecue Truck, ainsi qu'un bouton Épingler sur l'écran d'accueil

Nous devons maintenant :

  1. Ajouter une barre à l'application, qui contiendra l'icône représentant une punaise, permettant de réaliser les actions « Épingler sur l'écran d'accueil » et « Détacher du menu Démarrer ».
  2. Implémenter un gestionnaire d'événements pour gérer les clics sur le bouton Épingler/Détacher de la barre des applications.
  3. Ajouter la logique propre à l'application, afin d'épingler la nouvelle vignette suite à une action Épingler/Détacher.

Nous n'allons pas aborder ici les deux premières étapes consacrées à la création de la barre des applications, pour nous concentrer sur le processus d'épinglage des vignettes lui-même. Vous trouverez tous les détails consacrés à l'implémentation de la barre des applications dans les articles suivants :

À l'étape 3, notre application crée la vignette secondaire en configurant quelques propriétés.

JavaScript :

 // Keep track of your secondary tiles with a unique ID   
var nomNomTile = "SecondaryTile.NomNom";

// Set properties on the tile
var logo = new Windows.Foundation.Uri("ms-appx:///images/NomNomTruck-Logo.png");
var smallLogo = new Windows.Foundation.Uri("ms-appx:///images/NomNomTruck-SmallLogo.png");
var wideLogo = new Windows.Foundation.Uri("ms-appx:///images/NomNomTruck-WideLogo.png");
var TileActivationArguments = "TruckName=NomNom";

// Create the secondary tile
var tile = new Windows.UI.StartScreen.SecondaryTile(nomNomTile,
                                                    "Nom Nom",
                                                    "Nom Nom Barbecue Truck",
                                                    TileActivationArguments,
                                                    Windows.UI.StartScreen.TileOptions.sh
owNameOnWideLogo,
                                                    logo,
                                                    wideLogo);

tile.foregroundText = Windows.UI.StartScreen.ForegroundText.light;
tile.smallLogo = smallLogo;

// Request the user’s permission to create the secondary tile
// - we return the promise here, assuming that this code is embedded 
//   in a larger function. 
//   See the Windows 8 SDK Secondary Tiles sample for more info:
//   https://code.msdn.microsoft.com/windowsapps/Secondary-Tiles-Sample-edf2a178
return new WinJS.Promise(function (complete, error, progress) {
  tile.requestCreateAsync().then(function (isCreated) {
    if (isCreated) {
      complete(true);
    } else {
      complete(false);
    }
  });
});

C# :

 // Keep track of your secondary tiles with a unique ID   
const string nomNomTile = "SecondaryTile.NomNom"; 

// Set properties on the tile
Uri logo = new Uri("ms-appx:///images/NomNomTruck-Logo.png");
Uri smallLogo = new Uri("ms-appx:///images/NomNomTruck-SmallLogo.png");
Uri wideLogo = new Uri("ms-appx:///images/NomNomTruck-WideLogo.png");
string tileActivationArguments = "TruckName=NomNom";

// Create the secondary tile object
SecondaryTile secondaryTile = new SecondaryTile(nomNomTile,
                                                "Nom Nom",
                                                "Nom Nom Barbecue Truck",
                                                tileActivationArguments,
                                                Windows.UI.StartScreen.TileOptions.ShowNa
meOnWideLogo,
                                                logo,
                                                wideLogo);

secondaryTile.ForegroundText = Windows.UI.StartScreen.ForegroundText.Light;
secondaryTile.SmallLogo = smallLogo;

// Request the user’s permission to create the secondary tile
// - this code assumes that this code was called within an event handler which has
//   a ‘sender’ parameter.
//   See the Windows 8 SDK Secondary Tiles sample for more info:
//   https://code.msdn.microsoft.com/windowsapps/Secondary-Tiles-Sample-edf2a178
await secondaryTile.RequestCreateForSelectionAsync(MainPage.GetElementRect((FrameworkElement)se
nder), Windows.UI.Popups.Placement.Right);

Pour plus d'informations sur l'épinglage de vignettes secondaires, voir Consignes et liste de vérification pour les vignettes secondaires et Exemple de vignettes secondaires dans la version Consumer Preview.

Utilisation de notifications locales pour la mise à jour de la vignette épinglée

La vignette épinglée est une vignette supplémentaire que notre application doit mettre à jour dans l'écran d'accueil. Cette vignette est mise à jour de la même manière que la vignette principale de l'application. Dans cette application, j'utilise les API de notification locale pour mettre à jour les vignettes secondaires lorsque l'application est en cours d'exécution, en lieu et place des mécanismes de mise à jour utilisant le cloud. Je présente ici des notifications locales pour vous montrer le principe de fonctionnement. Vous pouvez procéder à des mises à jour à partir du cloud de la même manière. Cette application aurait également pu mettre en œuvre un scénario d'interrogation.

Dans le code figurant dans cette section, j'utilise la bibliothèque NotificationsExtensions, incluse dans l'exemple de vignettes et de badges d'application créés avec le SDK Windows 8. Vous pouvez inclure cette bibliothèque dans vos projets d'applications pour faciliter la mise à jour locale des vignettes. La bibliothèque offre un modèle d'objet en plus des API Windows de mise à jour des vignettes. Il vous évite de devoir manipuler du code XML à partir de vos applications JavaScript, C# et C++. Ce modèle facilite également le développement, à travers IntelliSense.

Grâce aux API de notification locale, je peux mettre à jour la vignette à tout moment, dès lors que l'application est en cours d'exécution. Dans le cas des vignettes épinglées consacrées à des restaurants ambulants, je souhaite mettre à jour la vignette en insérant les offres spéciales proposées par ce restaurant, chaque fois que l'utilisateur lance l'application.

Énumération des vignettes secondaires

Comme un utilisateur peut détacher des vignettes secondaires de l'écran d'accueil alors que l'application n'est pas en cours d'exécution, la première opération que l'application doit réaliser au lancement consiste à rechercher ses vignettes secondaires actuellement épinglées. Chaque vignette énumérée contient un identifiant tileId,qui l'identifie de façon unique. Comme l'application définit l'identifiant tileId lorsqu'elle est créée, nous pouvons utiliser l'ID pour savoir comment mettre à jour chaque vignette trouvée. Voici comment cela fonctionne :

JavaScript :

 // Get secondary tile ids
Windows.UI.StartScreen.SecondaryTile.findAllAsync().done(function (tiles) {
  if (tiles) {
    tiles.forEach(function (tile) {
      switch (tile.tileId) {
        case nomNomTile:
          updateNomNomTruck();
          break;
        // add cases for all the food trucks this app supports
        default:
          break;
      }
    });
  }
});

C# :

 // Get secondary tile ids
IReadOnlyList<SecondaryTile> tilelist = await 
Windows.UI.StartScreen.SecondaryTile.FindAllAsync();

foreach (var tile in tilelist)
{
  switch (tile.TileId)
  {
    case nomNomTile:
      updateNomNomTruck();
      break;
    // add cases for all the food trucks this app supports
    default:
      break;
  }
}

Mises à jour locales

Pour chaque vignette de restaurant ambulant épinglée, je mets à jour la vignette en insérant les informations à jour sur la position géographique de ce restaurant pour la journée. Si j'utilisais des mises à jour locales pour mettre à jour la vignette principale, nous n'aurions pas besoin d'énumérer les vignettes secondaires au préalable, car l'action par défaut de l'API consiste à mettre à jour la vignette principale de l'application appelante. À titre de rappel, voici à quoi ressemblent les vignettes de l'application étudiée dans la première partie.

Image présentant un filet de viande sur un grill, un camion, ainsi qu'un texte de mise à jour : Nom Nom Barbecue Truck, place Jean Jaurès, jusqu'au 3    Image présentant un filet de viande sur un grill, un camion, ainsi qu'un texte de mise à jour : Nom Nom @ place Jean Jaurès, jusqu'au 3

Voici la fonction appelée dans notre énumération, qui envoie la notification à la vignette secondaire.

JavaScript :       

 function updateNomNomTruck() {
  // Business logic for retrieving Nom Nom BBQ truck deals
  // ...
  var result = "Washer Ave and 3rd until 3";

  // We can send a notification only for a tile that is pinned. 
  // Lets make sure the tile is pinned before we try to send the notification.
  if (Windows.UI.StartScreen.SecondaryTile.exists(nomNomTile)) {

    // Construct the wide template
    var wideTile = 
NotificationsExtensions.TileContent.TileContentFactory.createTileWideImageAndText02();
    wideTile.image.src = "https://www.contoso.com/foodtrucks/nomnombbq.png";
    wideTile.textCaption1.text = "Nom Nom Barbecue Truck";
    wideTile.textCaption2.text = result;

    // Construct the square template
    var squareTile = 
NotificationsExtensions.TileContent.TileContentFactory.createTileSquarePeekImageAndText04
();
    squareTile.image.src = "https://www.contoso.com/foodtrucks/nomnombbq.png";
    squareTile.textBodyWrap.text = "Nom Nom @ " + result;

    // Attach the square template to the notification
    wideTile.squareContent = squareTile;

    // send the notification to the secondary tile
    Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForSecondaryTile(nomNomTi
le).update(wideTile.createNotification());
  }
}

C# :    

 private void updateNomNomTruck()
{
  // Business logic for retrieving Nom Nom BBQ truck deals
  // ...
  string result = "Washer Ave and 3rd until 3";

  // We can send a notification only for a tile that is pinned. 
  // Lets make sure the tile is pinned before we try to send the notification.
  if (Windows.UI.StartScreen.SecondaryTile.Exists(nomNomTile))
  {

    // Construct the wide template
    NotificationsExtensions.TileContent.ITileWideImageAndText02 wideTile = 
NotificationsExtensions.TileContent.TileContentFactory.CreateTileWideImageAndText02();
    wideTile.Image.Src = "https://www.contoso.com/foodtrucks/nomnombbq.png";
    wideTile.TextCaption1.Text = "Nom Nom Barbecue Truck";
    wideTile.TextCaption2.Text = result;

    // Construct the square template
    NotificationsExtensions.TileContent.ITileSquarePeekImageAndText04 squareTile = 
NotificationsExtensions.TileContent.TileContentFactory.CreateTileSquarePeekImageAndText04();
    squareTile.Image.Src = "https://www.contoso.com/foodtrucks/nomnombbq.png";
    squareTile.TextBodyWrap.Text = "Nom Nom @ " + result;

    // Attach the square template to the notification
    wideTile.SquareContent = squareTile;

    // Send the notification to the secondary tile
    Windows.UI.Notifications.TileUpdateManager.CreateTileUpdaterForSecondaryTile(nomNomTi
le).Update(wideTile.CreateNotification());
  }
}

Comme j'utilise la bibliothèque NotificationsExtensions, je n'ai pas besoin de manipuler le code XML dans mon code local. En revanche, j'utilise le modèle d'objet fourni par la bibliothèque NotificationsExtensions, qui me permet d'utiliser IntelliSense afin de découvrir les différentes propriétés de chaque modèle de notification.

Voici à quoi ressemble le code XML de la mise à jour de vignette :

 <?xml version="1.0" encoding="utf-8" ?>
<tile>
  <visual>
    <binding template="TileWideImageAndText02">
      <image id="1" src="https://www.contoso.com/foodtrucks/nomnombbq.png"/>
      <text id="1">Nom Nom Barbecue Truck</text>
      <text id="1">Washer Ave and 3rd until 3</text>
    </binding>
    <binding template="TileSquarePeekImageAndText04">
      <image id="1" src=" https://www.contoso.com/foodtrucks/nomnombbq-square.png"/>
      <text id="1">Nom Nom @ Washer Ave and 3rd until 3</text>
    </binding>
  </visual>
</tile>

Si vous utilisez la bibliothèque NotificationsExtensions, vous pouvez utiliser IntelliSense pour découvrir les propriétés des modèles de vignette, ce qui accélère significativement le développement des mises à jour locales des vignettes. J'espère que la bibliothèque NotificationsExtensions vous sera utile dans vos projets JavaScript, C# et C++.

Conclusion

Si les utilisateurs découvrent des informations amusantes et intéressantes dans leurs vignettes, ils sont plus enclins à ouvrir votre application pour en savoir plus. J'espère que ce billet vous a aidé à mieux comprendre comment vous pouvez enrichir votre application au moyen d'une vignette dynamique pour y présenter ses principaux avantages. Si vous souhaitez en savoir plus sur les notifications, consultez les articles Présentation des vignettes et des notificationset Sélection d'un mode de distribution des notifications dans le Centre de développement.

-- Kevin Michael Woley, chef de projet, Windows

Ce billet a été rédigé en équipe. Merci à Tyler Donahue, Daniel Oliver et Jon Galloway pour leur participation.