Partager via


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 tester des démonstrations de PC et d’appareils. Ils passent souvent une partie considérable de leur temps à jouer avec des applications via l’expérience de démonstration commerciale (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 commercial et préremplir l’application avec des exemples de données et des paramètres par défaut afin qu’elle puisse 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 que pendant que votre application soit en mode vente au détail, elle affiche le mot « Retail » en évidence dans la barre de titre ou dans un emplacement approprié.

Outre les exigences du Microsoft Store pour les applications, les applications prenant en charge RDX doivent également être compatibles avec les processus de configuration, de nettoyage et de mise à jour rdX pour garantir que les clients ont une expérience positive cohérente dans le magasin de vente au détail.

Principes de conception

  • Affichez votre meilleur. Utilisez l’expérience de démonstration de vente au détail pour montrer pourquoi votre application roche. C’est probablement la première fois que votre client verra votre application, afin de leur montrer la meilleure pièce !

  • Affichez-le rapidement. Les clients peuvent être impatients : plus un utilisateur peut expérimenter la valeur réelle de votre application, mieux c’est.

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

  • Concentrez-vous sur l’expérience. Donnez à l’utilisateur le temps de digester votre contenu. Tout en les rendant dans la meilleure partie rapide est important, la conception de pauses appropriées peut les aider à profiter pleinement de l’expérience.

Exigences techniques

Comme les applications prenant en charge 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 de confidentialité que le Microsoft Store a pour toutes les applications de démonstration commerciale.

Cela peut être utilisé comme liste de contrôle pour vous aider à préparer le processus de validation et à fournir une clarté dans le processus de test. Notez que ces exigences doivent être conservées, non seulement pour le processus de validation, mais pour toute la durée de vie de l’application d’expérience de démonstration commerciale ; tant que votre application reste en cours d’exécution sur les appareils de démonstration de vente au détail.

Exigences critiques

Les applications prenant en charge 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 personnelle (PII). Cela inclut les informations de connexion, les informations de compte Microsoft ou les informations de contact.

  • Expérience sans erreur. Votre application doit s’exécuter sans erreur. En outre, aucune fenêtre contextuelle d’erreur ou notification ne doit être affichée aux clients à l’aide des appareils de démonstration de vente au détail. Les erreurs 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’essai. Les clients ne cherchent pas à payer pour une expérience dans un magasin de détail.

Exigences de priorité élevée

Les applications prenant en charge RDX qui ne répondent pas à ces exigences de haute priorité doivent être examinées immédiatement pour obtenir un correctif. Si aucun correctif immédiat n’est trouvé, cette application peut être supprimée de tous les appareils de démonstration de vente au détail.

  • Expérience hors connexion mémorable. Votre application doit démontrer une expérience hors connexion exceptionnelle, car environ 50 % des appareils sont hors connexion aux emplacements de vente au détail. Cela permet de s’assurer que les clients qui interagissent avec votre application hors connexion sont toujours en mesure d’avoir une expérience significative et positive.

  • Expérience de contenu mise à jour. Votre application ne doit jamais être invité à entrer des mises à jour 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 utilisant un appareil de démonstration commerciale est un utilisateur anonyme, il ne doit pas être en mesure de communiquer ou de partager du contenu à partir de l’appareil.

  • Fournir des expériences cohérentes à l’aide du processus de nettoyage. Chaque client doit avoir la même expérience lorsqu’il accède à un appareil de démonstration de vente au détail. Votre application doit utiliser le processus de nettoyage pour revenir à l’é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 tableaux de bord, les réalisations et les déverrouillages.

  • Vieillir le contenu approprié. Tout le contenu de l’application doit être attribué à une catégorie d’évaluation ado ou inférieure. Pour plus d’informations, consultez Obtention de votre application évaluée par les évaluations IARC et ESRB.

Exigences de priorité moyenne

L’équipe du Windows Retail Store peut contacter directement les développeurs pour configurer une discussion sur la façon de résoudre ces problèmes.

  • Capacité à 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 page. Si l’application est installée sur des appareils qui ne répondent pas aux spécifications minimales, l’application doit clairement informer l’utilisateur de ce problème. La configuration minimale requise pour les appareils doit être connue afin que l’application puisse toujours s’exécuter 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 l’équipe du Windows Retail Store directement pour en savoir plus si votre application prenant en charge RDX ne répond pas aux exigences de taille.

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

IsDemoModeEnabled

La propriété IsDemoModeEnabled dans la classe de l’utilitaire RetailInfo, qui fait partie de l’espace de noms Windows.System.Profile dans le Kit de développement logiciel (SDK) Windows 10 et Windows 11, est utilisée comme indicateur booléen pour spécifier le chemin d’accès du code sur lequel votre application s’exécute - le mode normal ou le mode commercial.

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

Lorsque IsDemoModeEnabled retourne la valeur 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 acheteur cesse d’interagir avec l’appareil. La démonstration commerciale est lue et Windows commence à réinitialiser tous les exemples de données dans les contacts, les photos et d’autres applications. En fonction de l’appareil, cela peut prendre entre 1 et 5 minutes pour réinitialiser entièrement tout ce qui est normal. 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 Store sont fermées
  • Tous les fichiers des dossiers connus tels que Images, Vidéos, Musique, Documents, SavedPictures, CameraRoll, Desktop et Downloads sont supprimés
  • Les états itinérants 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 dans 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 étendue, le téléchargement et la mise en cache de données, ou la suppression de données LocalState .

Étape 1 : Déclarez le service Microsoft-RetailDemo-Cleanup dans votre manifeste d’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émenter 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;
        }
    }
}