Windows Phone 8: Faites le plein de nouveautés rapide à intégrer dans votre application

Windows Phone 8 offre un grand nombre de nouvelles APIs qui vont permettre aux développeurs de proposer de nouvelles expériences à leurs utilisateurs, et améliorer grandement l’intégration dans l’OS. Le but de cet article est de faire le tour des plus faciles et rapides à intégrer.

Ou sont les outils ?

Tous les liens importants sont listés dans cet article, alors lancez les téléchargements/installations pendant que vous lisez cet article !

Les liens utiles du SDK Windows Phone 8

Que faire du code existant ?

Réponse courte : on peut tout garder ! 100% des API de Windows Phone 7.0/7.1 sont présentes dans Windows Phone 8. Ceci étant dit, le passage à une nouvelle version et l’ajout de fonctionnalités est souvent l’occasion de ré-architecturer un peu son code. Pourquoi ne pas le rendre plus portable, par exemple pour être présent aussi sous Windows 8 ? Pour cela je vous réfère à la série d’articles sur le portage et le partage de code entre Windows 8 et Windows Phone :

Stratégies et Techniques de Partage et de Portage de code entre Windows Phone et Windows 8

Que vous décidiez de modifier votre code existant ou pas, vous pouvez par ailleurs tester votre application sur un Windows Phone 8 et constater que sans rien changer, elle fonctionne, voire noter un gain de performance significatif, principalement dû au nouveau matériel, et aux optimisations réalisées sur l’OS et le Runtime.

Si vous préférez un document offline et l’application exemple:

Voici le lien vers le dossier Skydrive contenant les deux:

https://sdrv.ms/Sx5VsO

 

Quels sont les nouveaux scénarios possibles ?

Passons maintenant aux nouveaux scénarios, que nous allons étudier en commençant par les plus rapides à intégrer (de l’ordre de quelques minutes !!) et en poussant vers les plus compliqués.

En moins d’une heure…

Vous pourrez avoir intégrer des nouvelles vignettes dynamiques, animées, et de différentes tailles, et de l’intégration sur l’écran de verrouillage. Vous pourrez également profiter des nouveaux launchers et choosers, de l’expérience Nokia Maps, des fonctionnalités de reconnaissance et synthèse vocales, d’un gain de performance non négligeable sur le LongListSelector… et aussi éventuellement revoir vos layouts et vos assets pour les nouvelles résolutions J

En une demi-journée…

Associez votre application à des types de fichiers ou des schémas d’URL, devenez une application « Lens » intégrée à l’appareil photo, ou bien un fournisseur de contact pour le hub contacts/people. Profitez de la nouvelle option de géolocalisation en background. Monétisez votre contenu et les bonus de vos applications avec les nouvelles options d’achat In-App.

Et pour aller plus loin…

Intégrez de nouvelles fonctionnalités ou du code existant avec le nouveau modèle de développement en C++, tirez parti de la technologie NFC pour s’identifier, payer ou établir une communication entre 2 appareils et profiter ensuite du Bluetooth ou du Wifi pour échanger des données, Intégrez-vous au wallet pour offrir à l’utilisateur d’y retrouver ses cartes de fidélité, cartes de membres, et éventuellement des coupons de réduction… Autoriser l’application à tourner 100% du temps en background pour faire de la géolocalisation… Ces points-là méritent des articles à part entière, nous ne les traiterons donc pas dans cet article-ci.

Passons à la pratique

Les nouvelles vignettes dynamiques

Le nouvel écran d’accueil supporte 3 tailles de vignettes :

  • Les petites, d’environ ¼ de la taille des vignettes « normales »
  • Les vignettes carrées, auxquelles nous étions déjà habituées
  • Les vignettes larges, qui font la taille de deux vignettes carrées

Avec ces nouvelles tailles viennent de nouveaux modèles, à l’instar des vignettes de Windows 8, qui permettent d’animer (ou pas) votre vignette principale et les vignettes secondaires.

  • StandardTile, qui permet d’avoir une icône, un titre, éventuellement du texte au dos, et un compteur
  • FlipTile, qui se retournera aléatoirement et supporte des contenus sur l’avant et l’arrière de la vignette.
  • CycleTile, qui permettra de faire défiler verticalement du contenu (texte ou photos)
  • IconicTile, qui mettra en valeur votre icône et éventuellement du texte ou un compteur associé.

 

Chacun de ces modèles existe dans les formats normaux et larges, le petit format étant déduit du premier. A chaque modèle est associé une structure de donnée contenant le texte et éventuellement l’adresse des images qu’on veut afficher, il s’agit des classes héritant de la classe abstraite ShellTileData.

Comme avant, on pourra donc créer une telle structure de donnée, la remplir avec les informations à afficher, et créer une nouvelle vignette correspondante en appelant la méthode ShellTile.Create( …) pour une nouvelle tuile secondaire, ou bien la méthode Update() pour les vignettes existantes.

 

 FlipTileData ftd = new FlipTileData();
ftd.Title = "Flip Tile Title";
ftd.Count = 42;
ftd.BackBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileMedium.png", UriKind.Relative);
ftd.WideBackContent = "Flip Tile Wide Back Content";
ftd.WideBackBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileLarge.png", UriKind.Relative);
ftd.SmallBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileSmall.png", UriKind.Relative);

ShellTile.Create(new Uri("/Pages/TilesAPI.xaml", UriKind.Relative), ftd, true);
 
 
 IconicTileData itd = new  IconicTileData();
itd.BackgroundColor = Colors.DarkGray;
itd.Title = "Iconic Tile Title";
itd.IconImage = new Uri("/Assets/Tiles/IconicTileMediumLarge.png", UriKind.Relative);
itd.SmallIconImage = new Uri("/Assets/Tiles/IconicTileSmall.png", UriKind.Relative);
itd.Count = 42;
itd.WideContent1 = "Wide Content 1";
itd.WideContent2 = "Wide Content 2";
itd.WideContent3 = "Wide Content 3";

ShellTile.Create(new Uri("/Pages/TilesAPI.xaml", UriKind.Relative), itd, true);
 var images = new List<Uri>();
images.Add(new Uri("/Assets/Tiles/FlipCycleTileLarge.png", UriKind.Relative));
images.Add(new Uri("/Assets/Tiles/FlipCycleTileMedium.png", UriKind.Relative));
images.Add(new Uri("/Assets/Tiles/FlipCycleTileSmall.png", UriKind.Relative));

CycleTileData ctd = new CycleTileData();
ctd.Count = 42;
ctd.CycleImages = images;
ctd.SmallBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileSmall.png", UriKind.Relative);
            
ctd.Title = "Cycle Tile Title";
            
ShellTile.Create(new Uri("/Pages/TilesAPI.xaml", UriKind.Relative), ctd, true);

Changer le contenu de l’écran de verrouillage

Une nouvelle API de Windows Phone 8 permet de changer l’image de fond de l’écran de verrouillage, ainsi que les 3 lignes de texte qui apparaissent sous l’heure, et éventuellement un compteur avec une mini-icône, comme les applications mails.

Le changement de l’image de fond se fait en appelant d’abord l’API du LockScreenManager pour récupérer l’autorisation de changer celui-ci, puis il suffit de lui indiquer l’URL (locale) de l’image à utiliser. Moins de 10 lignes de code :

 

 try
{
    if (!LockScreenManager.IsProvidedByCurrentApplication)
    {
        await LockScreenManager.RequestAccessAsync();
    }

    if (LockScreenManager.IsProvidedByCurrentApplication)
    {
        Uri imageUri = new Uri("ms-appx:///Assets/wpbackground.png", UriKind.RelativeOrAbsolute);
        Windows.Phone.System.UserProfile.LockScreen.SetImageUri(imageUri);
    }
}
catch (Exception ex)
{
    // Handle exception
}
 

Pour ce qui est du texte et éventuellement du compteur, en fait c’est encore plus simple (et logique) : le lockscreen reprendra le texte et le compteur de la vignette dynamique principale de l’application. Il faut donc que l’application soit épinglée sur l’écran d’accueil et que l’utilisateur ait choisi d’avoir ces notifications sur son écran de verrouillage.

Devenir un Store de contacts

Avec la version précédente du SDK, il était possible d’accéder à la liste de contacts (avec des API LINQ) en lecture seule, et éventuellement d’écrire dans un store existant, avec le launcher SaveContactTask.

Il est maintenant possible de devenir un fournisseur de contacts, au même titre que les réseaux sociaux ou de comptes mails existants nativement. Il faut commencer par créer (ou ouvrir, s’il est déjà créer) le store de contacts propre à l’application :

 var store = await ContactStore.CreateOrOpenAsync();

Ensuite, on peut y faire des requêtes, pour par exemple afficher la liste des contacts déjà enregistrés par l’application :

 ContactQueryResult cqr = store.CreateContactQuery();
IReadOnlyList<StoredContact> contacts = await cqr.GetContactsAsync();
if (contacts.Count > 0)
    Dispatcher.BeginInvoke(() => lbxContacts.DataContext = contacts.ToList());

Enfin, on peut ajouter de nouveaux contacts simplement:

 

 StoredContact c = new StoredContact(store);
c.DisplayName = "John Doe";
            

IDictionary<string, object> props = await c.GetPropertiesAsync();
props.Add(KnownContactProperties.Email, "john@doe.com");
props.Add(KnownContactProperties.MobileTelephone, "118218");
            
await c.SaveAsync();

Facile, et on obtient ensuite une fiche contact dans le hub avec lequel l’utilisateur peut interagir, et éventuellement la lier aux autres fiches qu’il aurait de différentes sources sur le même contact :

wp_ss_20121031_0001

 

S’intégrer au calendrier

En plus des alarmes et des rappels, qui permettaient d’imiter l’expérience native du réveil ou du calendrier pour rappeler à l’utilisateur un évènement, et en plus de l’accès en lecture seule au calendrier, l’arrivée de Windows Phone 8 rajoute un launcher qui permet de sauvegarder un évènement dans le calendrier :

 SaveAppointmentTask sat = new SaveAppointmentTask();
sat.StartTime = DateTime.Now + TimeSpan.FromDays(1);
sat.Details = "Details of the appointment";
sat.Subject = "Appointment generated from an app";
sat.EndTime = sat.StartTime + TimeSpan.FromHours(2);

sat.Location = "location";
sat.Show();

Rajouter le partage de photos/vidéos sur les réseaux sociaux

A l’instar des ShareLinkTask et ShareStatusTask qui permettent, depuis Windows Phone 7.5, de partagere des liens et des statuts sur les réseaux sociaux, la nouvelle ShareMediaTask va permettre de partager des photos et des vidéos.

 

 ShareMediaTask smt = new ShareMediaTask();
smt.FilePath = "/Assets/ApplicationIcon.png";

smt.Show();

Profiter du LongListSelector natif

Ce contrôle, qui était avant fourni dans le Silverlight Toolkit (qui s’appelle maintenant le Windows Phone Toolkit) est maintenant natif. Au menu, le même usage, mais de meilleures performances. Changez juste l’assembly !

 <DataTemplate x:Key="AddrBookItemTemplate">
    <StackPanel VerticalAlignment="Top">
        <TextBlock FontWeight="Bold"  Text="{Binding Name}" />
    </StackPanel>
</DataTemplate>

<DataTemplate x:Key="AddrBookGroupHeaderTemmplate">
    <Border Background="Transparent" Padding="5">
        <Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Width="62" 
    Height="62" Margin="0,0,18,0" HorizontalAlignment="Left">
            <TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6" 
    FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
        </Border>
    </Border>
</DataTemplate>

<phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
<phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
<Style x:Key="AddrBookJumpListStyle" TargetType="phone:LongListSelector">
    <Setter Property="GridCellSize"  Value="113,113"/>
    <Setter Property="LayoutMode" Value="Grid" />
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Width="113" Height="113" Margin="6" >
                    <TextBlock Text="{Binding Key}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="48" Padding="6" 
        Foreground="{Binding Converter={StaticResource ForegroundConverter}}" VerticalAlignment="Center"/>
                </Border>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>
 
 

 

 <phone:LongListSelector x:Name="lls" 
                        GroupHeaderTemplate="{StaticResource AddrBookGroupHeaderTemmplate}"
                        ItemTemplate="{StaticResource AddrBookItemTemplate}"
                        JumpListStyle="{StaticResource AddrBookJumpListStyle}"
                        LayoutMode="List"
                        HideEmptyGroups="True"
                        IsGroupingEnabled="True" />

Comment gérer proprement les nouvelles résolutions ?

Les terminaux Windows Phone 7 et 7.5 n’avaient qu’une seule définition : WVGA, soit 800x480. Avec Windows Phone 8, les fabricants ont la possibilité d’utiliser 2 nouvelles définitions en plus : WXGA (1280x768) et 720p (1280x720). Dans le cas de la première, on garde le même ratio largeur/hauteur, mais pas dans le second ! Il va donc y avoir une petite bande noire en haut de l’écran (de 53px) si vous n’adaptez pas votre layout dynamiquement (la feinte principale consistant à utiliser des "*" et des "Auto" dans les propriétés des tailles de vos contrôles. Une page de la documentation est dédiée à ce sujet et vous permettra de comprendre ce qu’il faut faire pour tirer parti de toutes les résolutions au mieux :

Multi-Resolution Apps for Windows Phone

Pour ce qui est des assets graphiques, (images, etc) vous avez la possibilité de les resizer dynamiquement (dans ce cas je vous conseille de les prévoir pour la résolution 1280x768 et faire du downscaling plutôt que l’inverse), ou bien d’utiliser un petit helper qui permet de savoir sur quelle image se binder en fonction de la résolution :

Une classe statique, ResolutionHelper, qui retourne de manière lisible la définition de l’écran :

 public enum Resolutions { WVGA, WXGA, HD720p };

public static class ResolutionHelper
{
    private static bool IsWvga
    {
        get
        {
            return Application.Current.Host.Content.ActualHeight == 800
            && Application.Current.Host.Content.ScaleFactor == 100;
        }
    }

    private static bool IsWxga
    {
        get
        {
            return Application.Current.Host.Content.ScaleFactor == 160;
        }
    }

    private static bool Is720p
    {
        get
        {
            return Application.Current.Host.Content.ScaleFactor == 150;
        }
    }

    public static Resolutions CurrentResolution
    {
        get
        {
            if (IsWvga) return Resolutions.WVGA;
            else if (IsWxga) return Resolutions.WXGA;
            else if (Is720p) return Resolutions.HD720p;
            else throw new InvalidOperationException("Unknown resolution");
        }
    }
}

Ensuite une classe sur laquelle l’interface pourra se binder et qui renverra l’image adaptée :

 public class MultiResImageChooser
{
    public Uri BestResolutionImage
    {
        get
        {
            switch (ResolutionHelper.CurrentResolution)
            {
                case Resolutions.HD720p:
                    return new Uri("/Assets/ResolutionDependent/720x1280.jpg", UriKind.Relative);
                case Resolutions.WXGA:
                    return new Uri("/Assets/ResolutionDependent/768x1280.jpg", UriKind.Relative);
                case Resolutions.WVGA:
                    return new Uri("/Assets/ResolutionDependent/480x800.jpg", UriKind.Relative);
                default:
                    throw new InvalidOperationException("Unknown resolution type");
            }
        }
    }
}

Et pour finir, dans l’interface, instancier cette classe sous forme d’une StaticResource et se binder sur le champ approprié :

 
 
 <phone:PhoneApplicationPage.Resources>
    <helpers:MultiResImageChooser x:Key="MultiResImageChooser" />
</phone:PhoneApplicationPage.Resources>

<Image Source="{Binding BestResolutionImage, Source={StaticResource MultiResImageChooser}}"/>

Enfin, pour ce qui est du SplashScreen, il suffit de le mettre en 3 versions (pour les 3 résolutions) dans le XAP avec la convention de nommage suivante :

  • SplashScreenImage.Screen-WXGA.jpg
  • SplashScreenImage.Screen-WVGA.jpg
  • SplashScreenImage.Screen-720p.JPG

 

Et le système s’en sortira tout seul !

Passer à Nokia Maps

Si vous utilisez le contrôle Map, vous pouvez profiter de la qualité des cartes vectorielles de Nokia Maps quel que soit la marque du téléphone de votre utilisateur, en quelques étapes très simples :

  1. Migrer votre projet à Windows Phone 8
  2. Enlever la référence à l’assembly Bing Maps et changer les namespaces là où ça s’impose
  3. Rajouter la capability « ID_CAP_MAP » dans votre manifest
  4. Recompiler

 

Pas besoin de changer le code, sauf peut-être pour enlever la clef d’API ;)

Sachez que les launchers BingMapsTask et BingMapsDirectionTask ouvriront également automatiquement Nokia Maps et non plus Bing Maps.

Vous pouvez également profiter des nouveaux launchers MapsTask, MapsDirectionTask, et MapsDownloadTask,  qui offrent respectivement l’accès à l’application Nokia Maps, au guidage tour-par-tour, et au téléchargement de cartes pour une utilisation offline. Un exemple avec la MapsTask :

 MapsTask mt = new MapsTask();
mt.ZoomLevel = 15;
mt.SearchTerm = "Pizza";
            
mt.Show();

Rajouter la reconnaissance et la synthèse vocale

Avec la reconnaissance vocale, vous allez pouvoir demander à l’utilisateur de parler à votre application, et récupérer le texte déduit par le moteur intégré à Windows Phone. La synthèse vocale, quant à elle, vous permettra de faire lire à l’application du texte, ce qui améliorera l’accessibilité de votre application.

Reconnaissance vocale : avec l’interface standard, ou la vôtre !

Voici comment utiliser l’interface graphique du système pour lancer la reconnaissance vocale :

 // Create an instance of SpeechRecognizerUI.
var speechRecognizerWithUI = new SpeechRecognizerUI();

// Start recognition (load the dictation grammar by default).
SpeechRecognitionUIResult recoResult = await speechRecognizerWithUI.RecognizeWithUIAsync();

// Do something with the recognition result.
tbSpeechRecognized.Text = recoResult.RecognitionResult.Text + " || confidence: " + recoResult.RecognitionResult.TextConfidence;

Vous pouvez également lancer la reconnaissance vocale avec votre propre interface, mais attention à bien guider l’utilisateur ! Voici un exemple minimaliste, avec une boite de message indiquant juste que la reconnaissance vocale va démarrer :

 if (MessageBox.Show("Recognize?", "SpeechRecognizer", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
    speechRecognizer = new SpeechRecognizer();
    var recoResult = await speechRecognizer.RecognizeAsync();
    tbSpeechRecognized.Text = recoResult.Text + " || confidence: " + recoResult.TextConfidence;
}
Synthèse vocale : simple comme bonjour ;)

Pour vocaliser du texte, il suffit de le passer en argument à une instance de la classe SpeechSynthesizer, en ayant précisé la voix à utiliser… sachant que l’utilisateur peut choisir une langue dans les paramètres du téléphone indépendamment de la langue de son interface graphique. Voici un petit exemple qui lit le contenu d’une TextBox :

 // Initialize the SpeechSynthesizer object.
SpeechSynthesizer synth = new SpeechSynthesizer();

// Query for a voice that speaks French.
var Voices = from voice in InstalledVoices.All
                where voice.Id == (lbxVoices.SelectedItem as VoiceInformation).Id
                select voice;

// Set the voice as identified by the query.
synth.SetVoice(Voices.ElementAt(0));

await synth.SpeakTextAsync(tbxSpeech.Text);

L’association avec des extensions de fichier et des schémas d’URL

Voici une nouvelle option qui permettra à d’autres applications de lancer directement la vôtre, et d’avoir vos propres formats de fichier pour échanger des données d’un utilisateur à un autre.

S’associer avec des extensions de fichiers

Pour s’associer avec une extension, il faut signaler au système qu’on a cette capacité : cela se passe évidemment dans le manifest de l’application, dans lequel il faut rajouter, dans la partie extensions :

 <FileTypeAssociation Name="Windows Phone SDK test file type" TaskID="_default" NavUriFragment="fileToken=%s">
  <Logos>
    <Logo Size="small">/Assets/apitests-small-33x33.png</Logo>
    <Logo Size="medium">/Assets/apitests-medium-69x69.png</Logo>
    <Logo Size="large">/Assets/apitests-large-176x176.png</Logo>
  </Logos>
  <SupportedFileTypes>
    <FileType ContentType="application/text">.apitests</FileType>
  </SupportedFileTypes>
</FileTypeAssociation>

Quand un fichier est téléchargé, par le navigateur, par email ou par une autre application, et que l’utilisateur tente de l’ouvrir en tapant sur l’icône de celui-ci (fournie, au passage, également par votre application), le système lancera votre application, avec en paramètre, un « token » permettant de récupérer ce fichier. La bonne pratique est donc de vérifier, en utilisant un UriMapper, si un nom de fichier est passé en paramètre au lancement pour éventuellement rediriger vers la page idoine, et l’ouvrir.

 class ApiTestsUriMapper : UriMapperBase
{
    private string tempUri;

    public override Uri MapUri(Uri uri)
    {
        tempUri = System.Net.HttpUtility.UrlDecode(uri.ToString());
        
        if (tempUri.Contains("/FileTypeAssociation")) // File association launch
        {
            // Get the file ID (after "fileToken=").
            int fileIDIndex = tempUri.IndexOf("fileToken=") + 10;
            string fileID = tempUri.Substring(fileIDIndex);

            // Get the file name.
            string incomingFileName = SharedStorageAccessManager.GetSharedFileName(fileID);

            // Get the file extension.
            int extensionIndex = incomingFileName.LastIndexOf('.');
            string incomingFileType =
                incomingFileName.Substring(extensionIndex).ToLower();

            // Map the .apitests extension to the right page.
            switch (incomingFileType)
            {
                case ".apitests":
                    return new Uri("/Pages/FileAssociationPage.xaml?fileToken=" + fileID, UriKind.Relative);
                default:
                    return new Uri("MainPage.xaml", UriKind.Relative);
            }
        }
        // Otherwise perform normal launch.
        return uri;
    }
}

Une fois dans la page, il faut utiliser les APIs SharedFolder pour récupérer le fichier passé en paramètre :

 protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    try
    {
        var fileToken = NavigationContext.QueryString["fileToken"];
        this.fileName = SharedStorageAccessManager.GetSharedFileName(fileToken);
                
        var storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
                
        var localFile = await SharedStorageAccessManager.CopySharedFileAsync(storageFolder, this.fileName, NameCollisionOption.ReplaceExisting, fileToken);

        using(var content = await localFile.OpenReadAsync())
        {
            using (DataReader dr = new DataReader(content))
            {
                await dr.LoadAsync((uint)content.Size);
                fileContent = dr.ReadString((uint)content.Size);
            }
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }
    finally
    {
        base.OnNavigatedTo(e);
    }
}
S’associer avec des schemas d’URI

L’association avec des schémas d’URI fonctionne sur le même principe que l’association avec des extensions de fichier. On déclare le support dans le manifest :

 <Protocol Name="apitests" NavUriFragment="encodedLaunchUri=%s" TaskID="_default" />

Puis on utilise un UriMapper pour capturer le lancement éventuel avec une URI en paramètre, afin de le traiter :

 class ApiTestsUriMapper : UriMapperBase
{
    private string tempUri;

    public override Uri MapUri(Uri uri)
    {
        tempUri = System.Net.HttpUtility.UrlDecode(uri.ToString());
        
if (tempUri.Contains("apitests:UriAssociation?Parameter=")) // URI assocation launch
        {
            // Get the category ID (after "CategoryID=").
            int paramIndex = tempUri.IndexOf("Parameter=") + 10;
            string param = tempUri.Substring(paramIndex);

            // Map the show products request to ShowProducts.xaml
            return new Uri("/Pages/UriAssociationPage.xaml?Parameter=" + param, UriKind.Relative);
        }

        // Otherwise perform normal launch.
        return uri;
    }

}

Une fois la page chargée, il suffit de récupérer le paramètre dans le NavigationContext :

 protected override void OnNavigatedTo(NavigationEventArgs e)
{
    try
    {
        parameter = NavigationContext.QueryString["Parameter"];
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }
    finally
    {
        base.OnNavigatedTo(e);
    }
}
Lancer une application tierce depuis un fichier ou une URI dans l’application

Pour lancer une application tierce depuis un fichier ou une Uri, il suffit d’appeler une API du système, qui automatiquement proposera à l’utilisateur de télécharger une appli ayant la capacité d’ouvrir ce type du contenu si il n’y en a pas déjà d’installée. Ça tient en une ligne de code :

 

 await Windows.System.Launcher.LaunchUriAsync(new Uri("apitests:UriAssociation?Parameter=" + tbParameter.Text));
 
 

Il est également possible de lancer des pages de l’interface native (paramètres, etc) en suivant le même principe, avec les schémas d’uri réservés du système documentés.

Devenir une « Lens app » et s’intégrer à l’expérience de prise de photo

La photo est de plus en plus au cœur de Windows Phone : dorénavant, il existe un petit bouton (matérialisé par deux flèches) dans l’application-bar de l’application photo native, qui permet de choisir une application pour prendre la photo, en y appliquant des filtres par exemple pour modifier l’apparence de la photo, y appliquer un traitement, la partager directement… A vous d’inventer ces nouveaux usages !

Pour cela, vous devez vous enregistrer cette extension dans votre manifeste, puis vérifier au lancement de l’application, à l’aide d’un UriMapper par exemple, si la chaine de caractère « ViewfinderLaunch » est présente dans l’URL. et si c’est le cas, c’est que votre application est lancée depuis l’appareil photo. Dans ce cas-là, un simple UriMapper vous permettra de rediriger l’utilisateur vers une page de votre application qui appliquera votre traitement, tout en veillant de respecter les recommandations de design spécifique à ce type de page qui sont disponibles ici :

Lens Design Guidelines for Windows Phone

Voici l’exemple d’extension à rajouter dans le fichier WMAppManifest.xml :

 <Extension ExtensionName="Camera_Capture_App" ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5631}" TaskID="_default" />

Et celui de l’UriMapper :

 

 PrFont34Bin0BinSub0Frac0Def1Margin0Margin0Jc1Indent1440Lim0Lim1class ApiTestsUriMapper : UriMapperBase
{
    private string tempUri;

    public override Uri MapUri(Uri uri)
    {
        tempUri = System.Net.HttpUtility.UrlDecode(uri.ToString());
        // Look for a URI from the lens picker.
        if (tempUri.Contains("ViewfinderLaunch"))
        {
            // Launch as a lens, launch viewfinder screen.
            return new Uri("/Pages/Lense.xaml", UriKind.Relative);
        }

        // Otherwise perform normal launch.
        return uri;
    }

}

En enregistrant cette extension et cet UriMapper, la page « Lense.xaml » contenue dans le dossier « Pages » sera automatiquement lancée, si l’application est lancée depuis l’appareil photo. Attention à ne pas oublier d’inclure également l’iconographie correspondante pour que votre application apparaisse correctement dans la liste des lentilles (le LensPicker) : à savoir :

Phone resolution

Icon size (pixels)

Folder

File name

WVGA

173 x 173

Assets

Lens.Screen-WVGA.png

HD720p

259 x 259

Assets

Lens.Screen-720p.png

WXGA

277 x 277

Assets

Lens.Screen-WXGA.png

 

En plus de pouvoir être identifié dans le hub photo comme une application qui peut prendre des photos en entrée (PhotoViewer), ou les partager, vous pouvez maintenant également faire identifier votre application comme éditeur de photo, ou mieux, « appliquant un traitement riche sur une image ». Dans ce cas, les photos que vous aurez prise depuis votre application pourront être rééditez dans votre application directement depuis leur fiche dans le hub photo. Dans tous les cas, cela passe par un ajout d’extension à votre manifest :

 <!-- Extend the photo edit picker. -->
<!-- This is only for Windows Phone 8 apps. -->
<Extension ExtensionName="Photos_Extra_Image_Editor" 
            ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5632}" 
            TaskID="_default" />


<!-- Integrate as a rich media app. -->
<!-- This is only for Windows Phone 8 apps. -->
<Extension ExtensionName="Photos_Rich_Media_Edit" 
            ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5632}" 
            TaskID="_default" />

 

Puis un bout de code dans un UriMapper pour rouvrir la bonne page (vous allez commencer à connaitre le système ;)) :

 

 PrFont34Bin0BinSub0Frac0Def1Margin0Margin0Jc1Indent1440Lim0Lim1// Launch from the photo edit picker.
// This is only for Windows Phone 8 apps.
// Incoming URI example: /MainPage.xaml?Action=EditPhotoContent&FileId=%7Bea74a960-3829-4007-8859-cd065654fbbc%7D
if ((tempUri.Contains("EditPhotoContent")) && (tempUri.Contains("FileId")))
{
    // Redirect to PhotoEdit.xaml.
    mappedUri = tempUri.Replace("MainPage", "PhotoEdit");
    return new Uri(mappedUri, UriKind.Relative);
}


// Launch from the rich media "Open in" link.
// This is only for Windows Phone 8 apps.
// Incoming URI example: /MainPage.xaml?Action=RichMediaEdit&token=%7Bed8b7de8-6cf9-454e-afe4-abb60ef75160%7D
if ((tempUri.Contains("RichMediaEdit")) && (tempUri.Contains("token")))
{
    // Redirect to RichMediaPage.xaml.
    mappedUri = tempUri.Replace("MainPage", "RichMediaPage");
    return new Uri(mappedUri, UriKind.Relative);
}

Pour comprendre tout ce qu’on peut faire avec le hub photo, le mieux est encore de se référer au code d’exemple dédié à ça :

Photo Extensibility Sample

Il existe encore plein d’autres sujets et nouveautés, qui méritent des articles à part entière pour en faire le tour : In-App Purchase, Intégration avec le Wallet, Utilisation de NFC que ce soit avec des tags ou bien pour appairer des appareils entre eux et échanger des données… sans compter les nouveautés du support C++ (et l’arrivée de frameworks type Unity ou Havok) ou HTML5 avec IE10 ! Beaucoup d’autres articles en prévision donc ;)