Aggiungere le funzionalità demo negozio all'app

Includi una modalità demo negozio nella tua app di Windows in modo che i clienti che provano PC e dispositivi presso il punto vendita possano testare subito l'esperienza.

Quando i clienti si trovano in un negozio al dettaglio, si aspettano di poter provare demo di PC e dispositivi. Spesso trascorrono una parte significativa del loro tempo giocando con le app attraverso l'esperienza demo di vendita al dettaglio (RDX) .

Puoi configurare la tua app per offrire esperienze diverse mentre è in modalitànormale o commerciale. Ad esempio, se la tua app inizia con un processo di configurazione, potresti saltarlo in modalità vendita al dettaglio e precompilare l'app con dati di esempio e impostazioni predefinite in modo che possano iniziare subito.

Dal punto di vista dei nostri clienti, esiste una sola app. Per aiutare i clienti a distinguere tra le due modalità, consigliamo che, mentre la tua app è in modalità commerciale, mostri chiaramente la parola "Commerciale" nella barra del titolo o in una posizione adatta.

Oltre ai requisiti di Microsoft Store per le app, le app compatibili con RDX devono anche essere compatibili con i processi di configurazione, pulizia e aggiornamento di RDX per garantire che i clienti abbiano un'esperienza costantemente positiva nello store

Principi di progettazione

  • Mostra il meglio. Utilizza l'esperienza demo commerciale per mostrare perché la tua app è eccezionale. Questa è probabilmente la prima volta che il tuo cliente vedrà la tua app, quindi mostragli il meglio!

  • Mostralo velocemente. I clienti possono essere impazienti: più velocemente un utente può sperimentare il valore reale della tua app, meglio è.

  • Mantieni la storia semplice.. L'esperienza demo commerciale è un riassunto conciso del valore della tua app.

  • Concentrati sull'esperienza. Dai all'utente il tempo di elaborare i contenuti. Sebbene sia importante portarli rapidamente alla parte migliore, progettare pause adeguate può aiutarli a godersi appieno l'esperienza.

Requisiti tecnici

Poiché le app RDX-aware sono destinate a mostrare il meglio della tua app ai clienti al dettaglio, devono soddisfare requisiti tecnici e rispettare normative sulla privacy che il Microsoft Store ha per tutte le app dell'esperienza demo commerciale.

Può essere utilizzata come lista di controllo per aiutarti a prepararti per il processo di convalida e per fornire chiarezza nel processo di test. È importante sottolineare che questi requisiti devono essere rispettati per l'intera durata dell'app dell'esperienza demo commerciale, non solo durante il processo di convalida, ma anche mentre l'app continua a essere utilizzata sui dispositivi demo al dettaglio.

Requisiti fondamentali

Le app RDX-aware che non soddisfano questi requisiti critici saranno rimosse da tutti i dispositivi demo al dettaglio il prima possibile.

  • Non chiedere informazioni di identificazione personale (PII). Ciò include informazioni di accesso, informazioni sull'account Microsoft o dettagli di contatto.

  • Esperienza senza errori. La tua app non deve presentare errori. Inoltre, ai clienti che utilizzano i dispositivi demo al dettaglio non devono essere mostrati popup o notifiche di errore. Gli errori si riflettono negativamente sull'app stessa, sul tuo marchio, sul marchio del dispositivo, sul marchio del produttore del dispositivo e sul marchio Microsoft.

  • Le app a pagamento devono avere una modalità di prova. La tua app deve essere gratuita o includere unperiodo di prova. I clienti non vogliono pagare per vivere un'esperienza in uno store.

Requisiti ad alta priorità

Le app compatibili con RDX che non soddisfano questi requisiti ad alta priorità devono essere esaminate immediatamente per una soluzione. Se non viene trovata alcuna soluzione immediata, questa app potrebbe essere rimossa da tutti i dispositivi demo al dettaglio.

  • Esperienza offline memorabile. La tua app deve offrire un'esperienza offline eccellente, poiché circa il 50% dei dispositivi è offline nei punti vendita al dettaglio. Questo per garantire che i clienti che interagiscono con la tua app offline siano comunque in grado di vivere un'esperienza significativa e positiva.

  • Esperienza con contenuti aggiornati. Alla tua app non dovrebbero mai essere richiesti aggiornamenti quando è online. Se sono necessari aggiornamenti, dovrebbero essere eseguiti in modalità silenziosa.

  • Nessuna comunicazione anonima. Poiché un cliente che utilizza un dispositivo demo al dettaglio è un utente anonimo, non dovrebbe essere in grado di inviare messaggi o condividere contenuti dal dispositivo.

  • Offrire esperienze coerenti utilizzando il processo di pulizia.. Ogni cliente dovrebbe avere la stessa esperienza quando si avvicina a un dispositivo demo al dettaglio. La tua app dovrebbe utilizzare il processo di pulizia per tornare allo stato predefinito dopo ogni utilizzo. Non vogliamo che il prossimo cliente veda ciò che l'ultimo cliente ha lasciato. Ciò include tabelloni segnapunti, risultati e sblocchi.

  • Contenuti adatti all'età. A tutti i contenuti dell'app deve essere assegnata una categoria di classificazione per adolescenti o inferiore. Per saperne di più, vedereOttenere la valutazione della tua app da IARC e classificazione ESRB.

Requisiti di media priorità

Il team del Windows Retail Store potrebbe contattare direttamente gli sviluppatori per organizzare una discussione su come risolvere questi problemi.

  • Capacità di funzionare con successo su una vasta gamma di dispositivi. Le app devono funzionare correttamente su tutti i dispositivi, compresi i dispositivi con specifiche di fascia bassa. Se l'app è installata su dispositivi che non soddisfano le specifiche minime, l'app deve informarne chiaramente l'utente. È necessario rendere noti i requisiti minimi del dispositivo in modo che l'app possa sempre funzionare con prestazioni elevate.

  • Soddisfa i requisiti relativi alle dimensioni delle app del negozio al dettaglio. L'app deve essere inferiore a 800 MB. Contatta direttamente il team del Windows Retail Store per ulteriori discussioni se la tua app RDX-aware non soddisfa i requisiti di dimensione.

API RetailInfo: preparazione del codice per la modalità demo

IsDemoModeEnabled

La proprietà IsDemoModeEnabled nella classe di utilità RetailInfo che fa parte del Windows.System.Profile nome spazio in 10 e Windows 11 SDK, viene utilizzato come indicatore booleano per specificare su quale percorso di codice viene eseguita la tua app: modalità normale o commerciale.

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

Qunado IsDemoModeEnabled restituisce true, puoi eseguire una query per un set di proprietà sul dispositivo utilizzandoRetailInfo.Properties per creare un'esperienza demo di vendita al dettaglio più personalizzata. Queste proprietà includono ManufacturerName, Screensize, Memory e altre..

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
    {
    }
}

Processo di pulizia

Cleanup begins two minutes after a shopper stops interacting with the device. La demo commerciale viene eseguita e Windows inizia a ripristinare eventuali dati di esempio nei contatti, nelle foto e in altre app. A seconda del dispositivo, potrebbero essere necessari da 1 a 5 minuti per ripristinare completamente tutto alla normalità. Ciò garantisce che ogni cliente nel negozio al dettaglio possa avvicinarsi a un dispositivo e avere la stessa esperienza quando interagisce con il dispositivo.

Passaggio 1: pulizia

  • Tutte le app Win32 e Store sono chiuse
  • Tutti i file nelle cartelle conosciute comeFoto, Video, Musica, Documenti, SavedPictures, CameraRoll, Desktop e Downloads sono cancellati.
  • Gli stati di roaming non strutturato e strutturato vengono eliminati
  • Gli stati locali strutturati vengono eliminati

Passaggio 2: configurazione

  • Per i dispositivi offline: le cartelle rimangono vuote
  • Per i dispositivi online: Gli asset della demo commerciale possono essere inviati al dispositivo direttamente dal Microsoft Store.

Archiviare i dati tra le sessioni utente

Archiviare i dati tra sessioni utente, è possibile archiviare informazioni in ApplicationData.Current.TemporaryFolder poiché il processo di pulizia predefinito non elimina automaticamente i dati in questa cartella. Tieni presente che le informazioni archiviate utilizzandoLocalState vengono cancellate con il processo di pulizia.

Personalizza il processo di pulizia

Per personalizzare il processo di pulizia, implementa il Microsoft-RetailDemo-Cleanupservizio app nella tua app.

Gli scenari in cui è necessaria una logica di pulizia personalizzata includono l'esecuzione di una configurazione completa, il download e la memorizzazione nella cache dei dati o il rifiuto dell'eliminazione dei dati LocalState.

Passaggio 1: dichiarare il servizioMicrosoft-RetailDemo-Cleanup nel manifest dell'app.

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

Passaggio 2: implementa la logica di pulizia personalizzata nella funzione del caso AppdataCleanup utilizzando il modello di esempio riportato di seguito.

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;
        }
    }
}