Ajouter des fonctionnalités de version de démonstration commerciale (RDX) à votre application

Incluez un mode de version de démonstration commerciale dans votre application Windows pour que les clients qui essaient des ordinateurs et des appareils sur le point de vente puissent y accéder.

Lorsque les clients se trouvent dans un magasin de vente au détail, ils s’attendent à pouvoir essayer des démonstrations de PC et d’appareils. Ils passent souvent une partie considérable de leur temps à jouer avec les applications via l’expérience de démonstration de vente au détail (RDX).

Vous pouvez configurer votre application pour fournir différentes expériences en mode normal ou de vente au détail . Par exemple, si votre application commence par un processus d’installation, vous pouvez l’ignorer en mode vente au détail et préremplir l’application avec des exemples de données et des paramètres par défaut afin qu’elle puisse y accéder directement.

Du point de vue de nos clients, il n’existe qu’une seule application. Pour aider les clients à faire la distinction entre les deux modes, nous vous recommandons d’afficher le mot « Vente au détail » bien en évidence dans la barre de titre ou dans un emplacement approprié.

En plus des exigences du Microsoft Store pour les applications, les applications compatibles RDX doivent également être compatibles avec les processus d’installation, de nettoyage et de mise à jour RDX pour garantir que les clients bénéficient d’une expérience toujours positive dans le magasin de vente au détail.

Principes de conception

  • Montrez le meilleur de vous-même. Utilisez l’expérience de démonstration pour montrer pourquoi votre application bascule. C’est probablement la première fois que votre client verra votre application, alors montrez-lui la meilleure pièce!

  • Montrez-le rapidement. Les clients sont parfois impatients. Plus un utilisateur peut constater rapidement les points forts de votre application, mieux c’est.

  • Gardez l’histoire simple. L’expérience de démonstration au détail est un pitch d’ascenseur pour la valeur de votre application.

  • Concentrez-vous sur l’expérience. Donnez à l’utilisateur le temps d’assimiler votre contenu. S’il est essentiel de les amener rapidement à découvrir les points forts, il faut également aménager des pauses pour leur permettre de profiter pleinement de l’expérience.

Exigences techniques

Étant donné que les applications RDX sont destinées à présenter le meilleur de votre application aux clients de vente au détail, elles doivent répondre aux exigences techniques et respecter les réglementations en matière de confidentialité du Microsoft Store pour toutes les applications d’expérience de démonstration de vente au détail.

Cela peut être utilisé comme une liste de contrôle pour vous aider à préparer le processus de validation et pour fournir de la clarté dans le processus de test. Notez que ces exigences doivent être satisfaites non seulement pendant le processus de validation, mais également pendant toute la durée de vie de l’application de démonstration commerciale tant qu’elle est exécutée sur les appareils de démonstration commerciale.

Exigences critiques

Les applications RDX qui ne répondent pas à ces exigences critiques seront supprimées de tous les appareils de démonstration de vente au détail dès que possible.

  • Ne demandez pas d’informations d’identification personnelles (PII). Cela inclut les informations de connexion, les informations de compte Microsoft ou les coordonnées.

  • Expérience sans erreur. Votre application doit s’exécuter sans erreur. En outre, aucune fenêtre ou notification d’erreur ne doit s’afficher lorsque les clients utilisent les appareils de démonstration commerciale. Les erreurs se reflètent négativement sur l’application elle-même, votre marque, la marque de l’appareil, la marque du fabricant de l’appareil et la marque de Microsoft.

  • Les applications payantes doivent avoir un mode d’évaluation. Votre application doit être gratuite ou inclure un mode d’évaluation. Les clients ne souhaitent pas payer pour une expérience en magasin.

Exigences hautement prioritaires

Les applications RDX qui ne répondent pas à ces exigences de priorité élevée doivent être examinées immédiatement pour obtenir un correctif. En l’absence de correctif applicable, cette application sera probablement supprimée des appareils de démonstration commerciale.

  • Expérience hors connexion mémorable. Votre application doit démontrer une excellente expérience hors connexion, car environ 50 % des appareils sont hors connexion dans des points de vente au détail. Vous devez vous assurer que les clients qui interagissent avec votre application hors connexion vivent une expérience positive et significative.

  • Expérience de contenu mise à jour. Votre application ne doit jamais être invité à effectuer des mises à jour lorsqu’elle est en ligne. Si des mises à jour sont nécessaires, elles doivent être effectuées en mode silencieux.

  • Aucune communication anonyme. Étant donné qu’un client qui utilise un appareil de démonstration de vente au détail est un utilisateur anonyme, il ne doit pas être en mesure de transmettre des messages ou de partager du contenu à partir de l’appareil.

  • Offrez des expériences cohérentes à l’aide du processus de nettoyage. Chaque client doit vivre la même expérience lorsqu’il utilise un appareil de démonstration commerciale. Votre application doit utiliser propre processus pour revenir au même état par défaut après chaque utilisation. Nous ne voulons pas que le client suivant voit ce que le dernier client a laissé derrière lui. Cela inclut les scores, les réussites et les déverrouillages.

  • Contenu adapté à l’âge. Tout le contenu de l’application doit se voir attribuer une catégorie d’évaluation adolescent ou inférieure. Pour plus d’informations, consultez Obtention d’une évaluation de votre application par les évaluations IARC et ESRB.

Exigences de priorité moyenne

L’équipe commerciale Windows Store peut contacter directement les développeurs pour discuter de la manière de corriger ces problèmes.

  • Possibilité de s’exécuter correctement sur une plage d’appareils. Les applications doivent s’exécuter correctement sur tous les appareils, y compris les appareils avec des spécifications bas de terminaison. Si l’application est installée sur des appareils qui ne répondent pas aux spécifications minimales, l’application doit en informer clairement l’utilisateur. La configuration minimale requise pour l’appareil doit être connue des clients afin qu’elle soit toujours exécutée avec des performances élevées.

  • Répondez aux exigences de taille d’application du Magasin de vente au détail. L’application doit être inférieure à 800 Mo. Contactez directement l’équipe du Windows Retail Store pour en savoir plus si votre application RDX ne répond pas aux exigences de taille.

API RetailInfo : préparation de votre code pour le mode de démonstration

IsDemoModeEnabled

La propriété IsDemoModeEnabled de la classe de l’utilitaire RetailInfo, qui fait partie de l’espace de noms Windows.System.Profile dans le sdk Windows 10 et Windows 11, est utilisée comme indicateur booléen pour spécifier le chemin de code sur lequel votre application s’exécute : le mode normal ou le mode de vente au détail.

using Windows.Storage;

StorageFolder folder = ApplicationData.Current.LocalFolder;

if (Windows.System.Profile.RetailInfo.IsDemoModeEnabled) 
{
    // Use the demo specific directory
    folder = await folder.GetFolderAsync("demo");
}

StorageFile file = await folder.GetFileAsync("hello.txt");
// Now read from file
using namespace Windows::Storage;

StorageFolder^ localFolder = ApplicationData::Current->LocalFolder;

if (Windows::System::Profile::RetailInfo::IsDemoModeEnabled) 
{
    // Use the demo specific directory
    create_task(localFolder->GetFolderAsync("demo").then([this](StorageFolder^ demoFolder)
    {
        return demoFolder->GetFileAsync("hello.txt");
    }).then([this](task<StorageFile^> fileTask)
    {
        StorageFile^ file = fileTask.get();
    });
    // Do something with file
}
else
{
    create_task(localFolder->GetFileAsync("hello.txt").then([this](StorageFile^ file)
    {
        // Do something with file
    });
}
if (Windows.System.Profile.retailInfo.isDemoModeEnabled) {
    console.log("Retail mode is enabled.");
} else {
    Console.log("Retail mode is not enabled.");
}

RetailInfo.Properties

Quand IsDemoModeEnabled retourne true, vous pouvez rechercher un ensemble de propriétés sur l’appareil à l’aide de RetailInfo.Properties pour créer une expérience de démonstration de vente au détail plus personnalisée. Ces propriétés incluent ManufacturerName, Screensize, Memory et ainsi de suite.

using Windows.UI.Xaml.Controls;
using Windows.System.Profile

TextBlock priceText = new TextBlock();
priceText.Text = RetailInfo.Properties[KnownRetailInfo.Price];
// Assume infoPanel is a StackPanel declared in XAML
this.infoPanel.Children.Add(priceText);
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::System::Profile;

TextBlock ^manufacturerText = ref new TextBlock();
manufacturerText.set_Text(RetailInfo::Properties[KnownRetailInfoProperties::Price]);
// Assume infoPanel is a StackPanel declared in XAML
this->infoPanel->Children->Add(manufacturerText);
var pro = Windows.System.Profile;
console.log(pro.retailInfo.properties[pro.KnownRetailInfoProperties.price);

IDL

//  Copyright (c) Microsoft Corporation. All rights reserved.
//
//  WindowsRuntimeAPISet

import "oaidl.idl";
import "inspectable.idl";
import "Windows.Foundation.idl";
#include <sdkddkver.h>

namespace Windows.System.Profile
{
    runtimeclass RetailInfo;
    runtimeclass KnownRetailInfoProperties;

    [version(NTDDI_WINTHRESHOLD), uuid(0712C6B8-8B92-4F2A-8499-031F1798D6EF), exclusiveto(RetailInfo)]
    [version(NTDDI_WINTHRESHOLD, Platform.WindowsPhone)]
    interface IRetailInfoStatics : IInspectable
    {
        [propget] HRESULT IsDemoModeEnabled([out, retval] boolean *value);
        [propget] HRESULT Properties([out, retval, hasvariant] Windows.Foundation.Collections.IMapView<HSTRING, IInspectable *> **value);
    }

    [version(NTDDI_WINTHRESHOLD), uuid(50BA207B-33C4-4A5C-AD8A-CD39F0A9C2E9), exclusiveto(KnownRetailInfoProperties)]
    [version(NTDDI_WINTHRESHOLD, Platform.WindowsPhone)]
    interface IKnownRetailInfoPropertiesStatics : IInspectable
    {
        [propget] HRESULT RetailAccessCode([out, retval] HSTRING *value);
        [propget] HRESULT ManufacturerName([out, retval] HSTRING *value);
        [propget] HRESULT ModelName([out, retval] HSTRING *value);
        [propget] HRESULT DisplayModelName([out, retval] HSTRING *value);
        [propget] HRESULT Price([out, retval] HSTRING *value);
        [propget] HRESULT IsFeatured([out, retval] HSTRING *value);
        [propget] HRESULT FormFactor([out, retval] HSTRING *value);
        [propget] HRESULT ScreenSize([out, retval] HSTRING *value);
        [propget] HRESULT Weight([out, retval] HSTRING *value);
        [propget] HRESULT DisplayDescription([out, retval] HSTRING *value);
        [propget] HRESULT BatteryLifeDescription([out, retval] HSTRING *value);
        [propget] HRESULT ProcessorDescription([out, retval] HSTRING *value);
        [propget] HRESULT Memory([out, retval] HSTRING *value);
        [propget] HRESULT StorageDescription([out, retval] HSTRING *value);
        [propget] HRESULT GraphicsDescription([out, retval] HSTRING *value);
        [propget] HRESULT FrontCameraDescription([out, retval] HSTRING *value);
        [propget] HRESULT RearCameraDescription([out, retval] HSTRING *value);
        [propget] HRESULT HasNfc([out, retval] HSTRING *value);
        [propget] HRESULT HasSdSlot([out, retval] HSTRING *value);
        [propget] HRESULT HasOpticalDrive([out, retval] HSTRING *value);
        [propget] HRESULT IsOfficeInstalled([out, retval] HSTRING *value);
        [propget] HRESULT WindowsVersion([out, retval] HSTRING *value);
    }

    [version(NTDDI_WINTHRESHOLD), static(IRetailInfoStatics, NTDDI_WINTHRESHOLD)]
    [version(NTDDI_WINTHRESHOLD, Platform.WindowsPhone), static(IRetailInfoStatics, NTDDI_WINTHRESHOLD, Platform.WindowsPhone)]
    [threading(both)]
    [marshaling_behavior(agile)]
    runtimeclass RetailInfo
    {
    }

    [version(NTDDI_WINTHRESHOLD), static(IKnownRetailInfoPropertiesStatics, NTDDI_WINTHRESHOLD)]
    [version(NTDDI_WINTHRESHOLD, Platform.WindowsPhone), static(IKnownRetailInfoPropertiesStatics, NTDDI_WINTHRESHOLD, Platform.WindowsPhone)]
    [threading(both)]
    [marshaling_behavior(agile)]
    runtimeclass KnownRetailInfoProperties
    {
    }
}

Processus de nettoyage

Le nettoyage commence deux minutes après qu’un client cesse d’interagir avec l’appareil. La démonstration au détail est lue et Windows commence à réinitialiser tous les exemples de données dans les contacts, les photos et d’autres applications. Selon l’appareil, cela peut prendre entre 1 et 5 minutes pour réinitialiser complètement tout à la normale. Cela garantit que chaque client du magasin de vente au détail peut marcher jusqu’à un appareil et avoir la même expérience lors de l’interaction avec l’appareil.

Étape 1 : Nettoyage

  • Toutes les applications Win32 et du Windows Store sont fermées
  • Tous les fichiers des dossiers connus comme Images, Vidéos, Musique, Documents, Photos enregistrées, Pellicule, Bureau et Téléchargements sont supprimés.
  • Les états d’itinérance non structurés et structurés sont supprimés
  • Les états locaux structurés sont supprimés

Étape 2 : Configuration

  • Pour les appareils hors connexion : les dossiers restent vides
  • Pour les appareils en ligne : les ressources de démonstration de vente au détail peuvent être envoyées à l’appareil à partir du Microsoft Store

Stocker des données entre les sessions utilisateur

Pour stocker des données entre les sessions utilisateur, vous pouvez stocker des informations dans ApplicationData.Current.TemporaryFolder , car le processus de nettoyage par défaut ne supprime pas automatiquement les données de ce dossier. Notez que les informations stockées à l’aide de LocalState sont supprimées pendant le processus de nettoyage.

Personnaliser le processus de nettoyage

Pour personnaliser le processus de nettoyage, implémentez le Microsoft-RetailDemo-Cleanup service d’application dans votre application.

Les scénarios où une logique de nettoyage personnalisée est nécessaire incluent l’exécution d’une configuration complète, le téléchargement et la mise en cache des données, ou la non-suppression des données LocalState .

Étape 1 : Déclarez le service Microsoft-RetailDemo-Cleanup dans le manifeste de votre application.

  <Applications>
      <Extensions>
        <uap:Extension Category="windows.appService" EntryPoint="MyCompany.MyApp.RDXCustomCleanupTask">
          <uap:AppService Name="Microsoft-RetailDemo-Cleanup" />
        </uap:Extension>
      </Extensions>
   </Application>
  </Applications>

Étape 2 : Implémentez votre logique de nettoyage personnalisée sous la fonction de cas AppdataCleanup à l’aide de l’exemple de modèle ci-dessous.

using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.Foundation.Collections;
using Windows.Storage;

namespace MyCompany.MyApp
{
    public sealed class RDXCustomCleanupTask : IBackgroundTask
    {
        BackgroundTaskCancellationReason _cancelReason = BackgroundTaskCancellationReason.Abort;
        BackgroundTaskDeferral _deferral = null;
        IBackgroundTaskInstance _taskInstance = null;
        AppServiceConnection _appServiceConnection = null;

        const string MessageCommand = "Command";

        public void Run(IBackgroundTaskInstance taskInstance)
        {
            // Get the deferral object from the task instance, and take a reference to the taskInstance;
            _deferral = taskInstance.GetDeferral();
            _taskInstance = taskInstance;
            _taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);

            AppServiceTriggerDetails appService = _taskInstance.TriggerDetails as AppServiceTriggerDetails;
            if ((appService != null) && (appService.Name == "Microsoft-RetailDemo-Cleanup"))
            {
                _appServiceConnection = appService.AppServiceConnection;
                _appServiceConnection.RequestReceived += _appServiceConnection_RequestReceived;
                _appServiceConnection.ServiceClosed += _appServiceConnection_ServiceClosed;
            }
            else
            {
                _deferral.Complete();
            }
        }

        void _appServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
        {
        }

        async void _appServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            //Get a deferral because we will be calling async code
            AppServiceDeferral requestDeferral = args.GetDeferral();
            string command = null;
            var returnData = new ValueSet();

            try
            {
                ValueSet message = args.Request.Message;
                if (message.ContainsKey(MessageCommand))
                {
                    command = message[MessageCommand] as string;
                }

                if (command != null)
                {
                    switch (command)
                    {
                        case "AppdataCleanup":
                            {
                                // Do custom clean up logic here
                                break;
                            }
                    }
                }
            }
            catch (Exception e)
            {
            }
            finally
            {
                requestDeferral.Complete();
                // Also release the task deferral since we only process one request per instance.
                _deferral.Complete();
            }
        }

        private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {
            _cancelReason = reason;
        }
    }
}