Agregar características de prueba comercial (RDX) a la aplicación

Incluye un modo de prueba comercial en la aplicación de Windows para que los clientes que prueben equipos PC y dispositivos en la zona de ventas puedan comenzar de inmediato.

Cuando los clientes están en una tienda minorista, esperan poder probar demostraciones de equipos y dispositivos. A menudo pasan un fragmento considerable de su tiempo jugando con aplicaciones a través de la experiencia de demostración comercial (RDX).

Puedes configurar la aplicación para proporcionar diferentes experiencias en los modos normales o comerciales . Por ejemplo, si la aplicación comienza con un proceso de configuración, puede omitirlo en modo comercial y rellenar previamente la aplicación con datos de ejemplo y la configuración predeterminada para que puedan saltar directamente.

Desde la perspectiva de nuestros clientes, solo hay una aplicación. Para ayudar a los clientes a distinguir entre los dos modos, se recomienda que mientras la aplicación esté en modo comercial, muestra la palabra "Retail" destacadamente en la barra de título o en una ubicación adecuada.

Además de los requisitos de Microsoft Store para las aplicaciones, las aplicaciones compatibles con RDX también deben ser compatibles con los procesos de configuración, limpieza y actualización de RDX para garantizar que los clientes tengan una experiencia positiva coherente en la tienda minorista.

Principios de diseño

  • Muestre lo mejor. Usa la experiencia de demostración comercial para mostrar por qué las rocas de la aplicación. Esto es probable que la primera vez que el cliente vea la aplicación, así que muéstrales la mejor pieza.

  • Muestrelo rápido. Los clientes pueden ser impacientes: cuanto más rápido pueda experimentar un usuario el valor real de la aplicación, mejor.

  • Mantenga la historia sencilla. La experiencia de demostración comercial es un lanzamiento de ascensor para el valor de la aplicación.

  • Céntrese en la experiencia. Conceda al usuario tiempo para resúmenes del contenido. Aunque obtenerlos a la mejor parte rápido es importante, el diseño de pausas adecuadas puede ayudarles a disfrutar completamente de la experiencia.

Requisitos técnicos

Como las aplicaciones compatibles con RDX están diseñadas para mostrar lo mejor de la aplicación a los clientes minoristas, deben cumplir los requisitos técnicos y cumplir las regulaciones de privacidad que Microsoft Store tiene para todas las aplicaciones de experiencia de demostración comercial.

Esto se puede usar como una lista de comprobación para ayudarle a prepararse para el proceso de validación y para proporcionar claridad en el proceso de prueba. Tenga en cuenta que estos requisitos deben mantenerse, no solo para el proceso de validación, sino para toda la duración de la aplicación de experiencia de demostración comercial; siempre que la aplicación permanezca ejecutándose en los dispositivos de demostración comercial.

Requisitos críticos

Las aplicaciones compatibles con RDX que no cumplen estos requisitos críticos se quitarán de todos los dispositivos de demostración comercial lo antes posible.

  • No solicite información de identificación personal (PII). Esto incluye información de inicio de sesión, información de cuenta Microsoft o detalles de contacto.

  • Experiencia sin errores. La aplicación debe ejecutarse sin errores. Además, no se deben mostrar elementos emergentes o notificaciones de error a los clientes que usan los dispositivos de demostración comercial. Los errores se reflejan negativamente en la propia aplicación, la marca del dispositivo, la marca del dispositivo, la marca del fabricante del dispositivo y la marca de Microsoft.

  • Las aplicaciones de pago deben tener un modo de prueba. La aplicación debe ser gratuita o incluir un modo de evaluación. Los clientes no buscan pagar una experiencia en una tienda minorista.

Requisitos de alta prioridad

Las aplicaciones compatibles con RDX que no cumplen estos requisitos de prioridad alta deben investigarse para una corrección inmediatamente. Si no se encuentra ninguna corrección inmediata, esta aplicación se puede quitar de todos los dispositivos de demostración comercial.

  • Experiencia sin conexión memorable. La aplicación debe demostrar una excelente experiencia sin conexión, ya que aproximadamente el 50 % de los dispositivos están sin conexión en ubicaciones comerciales. Esto es para asegurarse de que los clientes que interactúan con la aplicación sin conexión todavía pueden tener una experiencia significativa y positiva.

  • Experiencia de contenido actualizada. La aplicación nunca debe solicitar actualizaciones cuando esté en línea. Si se necesitan actualizaciones, se deben realizar de forma silenciosa.

  • Ninguna comunicación anónima. Dado que un cliente que usa un dispositivo de demostración comercial es un usuario anónimo, no debe poder enviar mensajes ni compartir contenido desde el dispositivo.

  • Ofrezca experiencias coherentes mediante el proceso de limpieza. Cada cliente debe tener la misma experiencia cuando pase a un dispositivo de demostración comercial. La aplicación debe usar el proceso de limpieza para volver al mismo estado predeterminado después de cada uso. No queremos que el siguiente cliente vea lo que el último cliente ha dejado atrás. Esto incluye cuadros de mandos, logros y desbloqueos.

  • Contenido adecuado para la edad. Todo el contenido de la aplicación debe asignarse a una categoría adolescente o de clasificación inferior. Para obtener más información, consulta Obtención de la aplicación calificada por las clasificaciones de IARC y ESRB.

Requisitos de prioridad media

El equipo de la Tienda minorista de Windows puede ponerse en contacto con los desarrolladores directamente para configurar una explicación sobre cómo solucionar estos problemas.

  • Capacidad de ejecutarse correctamente en una gama de dispositivos. Las aplicaciones deben ejecutarse bien en todos los dispositivos, incluidos los dispositivos con especificaciones de gama baja. Si la aplicación está instalada en dispositivos que no cumplen las especificaciones mínimas, la aplicación debe informar claramente al usuario sobre esto. Se deben conocer los requisitos mínimos del dispositivo para que la aplicación siempre se pueda ejecutar con un alto rendimiento.

  • Cumple los requisitos de tamaño de la aplicación de la tienda minorista. La aplicación debe ser inferior a 800 MB. Póngase en contacto directamente con el equipo de la Tienda comercial de Windows para obtener más información si la aplicación compatible con RDX no cumple los requisitos de tamaño.

RETAILInfo API: Preparación del código para el modo de demostración

IsDemoModeEnabled

La propiedad IsDemoModeEnabled de la clase de utilidad RetailInfo, que forma parte del espacio de nombres Windows.System.Profile en el SDK de Windows 10 y Windows 11, se usa como indicador booleano para especificar en qué ruta de acceso de código se ejecuta la aplicación: el modo normal o el modo comercial.

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

Cuando IsDemoModeEnabled devuelve true, puede consultar un conjunto de propiedades sobre el dispositivo mediante RetailInfo.Properties para crear una experiencia de demostración comercial más personalizada. Estas propiedades incluyen ManufacturerName, Screensize, Memory , etc.

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

Proceso de limpieza

La limpieza comienza dos minutos después de que un comprador deje de interactuar con el dispositivo. La demostración comercial se reproduce y Windows comienza a restablecer los datos de ejemplo en los contactos, fotos y otras aplicaciones. Dependiendo del dispositivo, esto puede tardar entre 1 y 5 minutos en restablecerse completamente todo a la normalidad. Esto garantiza que todos los clientes de la tienda minorista puedan caminar hasta un dispositivo y tener la misma experiencia al interactuar con el dispositivo.

Paso 1: Limpieza

  • Todas las aplicaciones win32 y store están cerradas
  • Se eliminan todos los archivos de carpetas conocidas como Imágenes, Vídeos, Música, Documentos, SavedPictures, CameraRoll, Escritorio y Descargas.
  • Se eliminan los estados de itinerancia no estructurados y estructurados.
  • Se eliminan los estados locales estructurados

Paso 2: Configuración

  • Para dispositivos sin conexión: las carpetas permanecen vacías
  • Para dispositivos en línea: los recursos de demostración comercial se pueden insertar en el dispositivo desde Microsoft Store.

Almacenamiento de datos entre sesiones de usuario

Para almacenar datos entre sesiones de usuario, puede almacenar información en ApplicationData.Current.TemporaryFolder , ya que el proceso de limpieza predeterminado no elimina automáticamente los datos de esta carpeta. Tenga en cuenta que la información almacenada mediante LocalState se elimina durante el proceso de limpieza.

Personalización del proceso de limpieza

Para personalizar el proceso de limpieza, implemente app Microsoft-RetailDemo-Cleanup service en la aplicación.

Los escenarios en los que se necesita una lógica de limpieza personalizada incluyen ejecutar una amplia configuración, descargar y almacenar datos en caché, o no desea que se eliminen los datos de LocalState .

Paso 1: Declarar el servicio Microsoft-RetailDemo-Cleanup en el manifiesto de la aplicación.

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

Paso 2: Implemente la lógica de limpieza personalizada en la función de caso AppdataCleanup mediante la plantilla de ejemplo siguiente.

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