Trials en Windows Phone.

Si, lo sé. Gestionar que nuestra aplicación tenga o no capacidad de prueba no deja de ser algo muy trivial. Pero, de cosas triviales siempre se aprende algo…

Lo primero que debemos de hacer es controlar de alguna forma si nuestra aplicación esta en modo trial o no. Para ello usaremos la clase LicenseInformation contenida en el espacio de nombres Microsoft.Phone.MarketPlace.

Algún habido lector, habrá pensado, …..MarketPlace?, pero si eso suena a viejuno. Pues si, aunque con la aparición de Windows Phone 8 y el uso de WinRT existe un nuevo espacio de nombres para cualquier tipo de consulta relacionada con estos menesteres, concretamente Windows.ApplicationModel.Store, la clase LicenseInformation que deriva de dicho namespace no se puede usar en Windows Phone 7.x por lo que la mejor forma para hacer este trozo de código totalmente compatible tanto con Windows Phone 7.x como con Windows Phone 8, es usar la clase LicenseInformation de Microsoft.Phone.Marketplace.

Bueno, entonces está claro. Ahora, ¿cual debería de ser la mejor implementación?. Obviamente no quiero sentar cátedra pero siendo un poquito costosa, hablando de rendimiento, la labor de comprobar si nuestra aplicación es o no una versión de prueba. Lo suyo seria realizar esta consulta una sola vez y “archivar” esta información en algún lugar accesible.

Para ello, una de las mejores formas es disponer en nuestro fichero App.xaml.cs de una variable publica y estatica la cual implemente guarde dicha información.

private static bool isTrial;   
public static bool IsTrial   
{      
   get      
   {   
      return isTrial;      
   }   
}

Así mismo dispondremos de un procedimiento el cual comprobará mediante la clase LicenseInformation comentada anteriormente, si es o no, nuestra aplicación una versión de prueba. Le llamaremos por ejemplo CheckLicense.

private void CheckLicense()   
{   
   LicenseInformation license = new Microsoft.Phone.Marketplace.LicenseInformation();   
   isTrial = license.IsTral();      
}

Ok, perfecto. Simplemente implementamos la clase LicenseInformation y comprobamos su método isTrial, el cual nos devuelve un booleano indicándonos el estado.

Ahora debemos de lanzar en el lugar y momento correcto, el código anterior. Dos son los lugares en donde deberemos de lanzarlo. Por un lado el evento Launching de nuestra aplicación. De esta forma cada vez que lanzamos la aplicación comprobamos el valor.

private void Application_Launching(object sender, LaunchingEventArgs e)
{
    CheckLicense();
}

El otro punto sería el evento Activated. ¿Para que?, si nuestra aplicación no va a cambiar su estado constantemente. Pues básicamente para poder controlar de forma correcta que se haya podido adquirir la aplicación de forma completa mediante un enlace colocado en nuestra aplicación o cuando nuestra aplicación esta suspendida. De esta manera al volver a activarla desde el estado de tombstoning recogemos el valor de forma correcta y actuamos en consecuencia.

private void Application_Activated(object sender, ActivatedEventArgs e)
{
    CheckLicense();
}

Perfecto ya tenemos controlado el acceso a la comprobación solamente en dos puntos, accediendo a la información en cualquier momento sin consumo de recurso alguno.

Vamos a plantear una pantalla muy sencilla la cual, recoja este valor y realice una serie de acciones.

<Grid>
    <Grid Margin="0,0,0,0">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>

        <TextBlock Grid.Row="0" Text="Trial version example"
                    VerticalAlignment="Top"
                    Margin="12,12,0,12"
                    FontSize="42">
        </TextBlock>
            
        <StackPanel Grid.Row="1">
            <Button Content="action A"
                    Margin="0,130,0,0"
                    HorizontalAlignment="Center"
                    Width="350"
                    Command="{Binding ActionACommand}">
            </Button>
            <Button Content="action B"
                    HorizontalAlignment="Center"
                    Width="350"
                    Command="{Binding ActionBCommand}">
            </Button>
            <Button Content="purchase complete version"
                    Margin="0,130,0,0"
                    HorizontalAlignment="Center"
                    Visibility="{Binding TrialVersion, 

                                Converter={StaticResource BoolToVisibility}}"
                    Width="350"
                    Command="{Binding PurchaseCommand}">
            </Button>
        </StackPanel>
    </Grid>
</Grid>

Obviamente (faltaría más) todo nuestro XAML usa una ViewModel de MVVM para realizar toda la lógica de nuestra pagina. Como podéis ver disponemos de 3 sencillos botones. El ultimo de los botones usa un converter para convertir la propiedad TrialVersion de nuestra ViewModel en el correspondiente valor de la enumeración System.Windows.Visibility.

Veamos ahora nuestra ViewModel por partes.

public class VMMainPage : VMBase
{
    bool trialVersion = true;
    Lazy<DelegateCommand> actionACommand;
    Lazy<DelegateCommand> actionBCommand;
    Lazy<DelegateCommand> purchaseCommand;

    public VMMainPage()
    {
        this.trialVersion = App.IsTrial;    
        ........
    }

    public bool TrialVersion
    {
        get
        {
            return this.trialVersion;
        }
    }

    ...........
    ...........
}

Hemos creado una variable privada la cual en el momento de instanciar nuestra ViewModel toma el valor de la variable estática contenida en nuestro App.xaml.cs. Por otro lado hemos creado las variables privadas de los DelegateCommands que usaremos a continuación.

Podemos ver también la propiedad publica TrialVersion, que hemos usado en nuestra vista para visualizar o no, a través del converter, el botón de purchase o compra de la aplicación.

    private void ActionACommandExecute()
    {
        MessageBox.Show("Action A");
    }

    private void ActionBCommandExecute()
    {
        MessageBox.Show("Action B");
    }

    private bool ActionBCommandCanExecute()
    {
        return !this.trialVersion;
    }

Ahora vemos la implementación de los comandos asignados a los dos primeros botones. Estos simplemente muestran un mensaje en pantalla (esto lo deberíamos de hacer con un servicio, pero bueno para no complicar mas las cosas…) En la inicialización del primero de ellos, no hemos asignado nada a la función de retorno del CanExecute, pero si en el caso del segundo botón.

En el ejemplo dejamos el primer botón accesible a cualquiera de los dos tipos de estado de la aplicación, mientras que el segundo botón, estará deshabilitado si la aplicación está en versión Trial. Para ello retornamos el valor contrario a la variable privada isTrial como respuesta en el CanExecute de este segundo botón.

El resultado hasta el momento de nuestro pequeño ejemplo es el siguiente:

TrialAndComplete

La mejor forma de dirigir al usuario a comprar la versión completa de nuestra aplicación es utilizar el lanzador MarketPlaceDetailTask, como podemos ver en la implementación del comando que ejecuta nuestro tercer botón.

    private void PurchaseCommandExecute()
    {
        MarketplaceDetailTask market = new MarketplaceDetailTask();

        market.Show();
    }

Así de sencillo. Simplemente instanciamos el lanzador y lo ejecutamos con su método Show. La clase MarketplaceDetailTask dispone de una propiedad denominada ContentIdentifier, la cual acepta un valor string que representa el ID del producto del cual queremos mostrar sus características para proceder a la compra. Si este valor no es asignado o es asignado un valor nulo, el lanzador muestra los datos de la aplicación la cual le ha llamado.

Lamentablemente si la aplicación no esta publicada, ya estemos ejecutando en el emulador o en un dispositivo físico, la llamada al método show de la clase nos lanzara un error como el que vemos a continuación. Es algo que debemos de tener en cuenta.

MarketPlaceDetailTask

Bueno, pues llegados a este punto ya sabemos como controlar si nuestra aplicación esta en versión trial o versión completa. Como de forma muy sencilla poder gestionarlo con MVVM y como poder realizar la compra mostrando la correspondiente pagina de la Windows Phone Store de nuestra aplicación. Pero, ¿como podemos probar para dar valores según nos convenga a la variable IsTrial de nuestro App.xaml.cs?

Ya que si ejecutamos la aplicación tal y como la tenemos hasta el momento al leer el valor del método isTrial, de la clase LicenseInformation, este siempre nos devuelve false.

Para ello existen principalmente dos formas, que cada uno usa según le parezcan. Por un lado podríamos detectar si estamos en modo debug y preguntar si queremos ejecutar en modo trial o en modo full.

private void CheckLicenseWithQuestion()
{
#if DEBUG
    string message = "Pulsa 'OK' para simular el modo trial. Pulsa 'Cancel' para ejecutar la aplicación en modo normal.";
    if (MessageBox.Show(message, "Debug Trial",MessageBoxButton.OKCancel) == MessageBoxResult.OK)
    {
        isTrial = true;
    }
    else
    {
        isTrial = false;
    }
#else
    LicenseInformation license = new Microsoft.Phone.Marketplace.LicenseInformation();

    isTrial = license.IsTrial();
#endif
}

En el código anterior hemos modificado nuestro procedimiento CheckLicense para que, mediante el uso de directivas de compilación condicional, en el caso de que estemos compilando en modo debug, nos lance una pregunta para elegir el modo de prueba de la aplicación. Activado o desactivado. En el caso de que estemos compilando en versión release, directamente se comprobara el modo de ejecución a través de la clase LicenseInformation. El resultado seria el siguiente:

TrialWithQuestion

Pero este método solo funcionara en aplicaciones para Windows Phone 7.x, ya que la llamada al método Show, de nuestro MessageBox, en Windows Phone 8 no se puede hacer hasta que no se ha inicializado el elemento RootVisual de nuestra aplicación. Es decir para poder usar este método en WP8, no es posible indicar la llamada en el evento Launching, sino que lo deberemos de invocar en el evento CompleteInitializePhoneApplication, tras la asignación del RootVisual.

Esto trae mas problemas, ya que si llamamos en ese lugar al procedimiento CheckLicense, nuestra ViewModel principal ya a sido creada por lo que ya hemos recogido los valores de la propiedad IsTrial, sin haberla dado el valor que queremos. La implementación en este caso debe de ser diferente y deberíamos de comprobar los valores de dicha propiedad sobrescribiendo el evento OnNavigatedTo de nuestra pagina principal.

Otra forma seria seguir implementando el procedimiento CheckLicense como hasta el momento, y simplemente en el modo debug activar siempre el modo trial.

private void CheckLicense()
{
#if DEBUG
    isTrial = true;
#else
    LicenseInformation license = new Microsoft.Phone.Marketplace.LicenseInformation();

    isTrial = license.IsTrial();
#endif
}

Esto tiene un gran inconveniente y es que para poder probar la versión completa, deberemos de compilar en modo release, perdiendo todo lo que el modo debug nos aporta. Para solventar este problema podríamos crear en Visual Studio una nueva configuración de compilación. Para ello debemos de dirigirnos al menú “Build > Configuration Manager”. Dentro de él, seleccionamos del combo “Active solution configuration”, el valor “<New…>”.

ConfigurationManager

En la nueva pantalla que se abre, indicaremos un nombre para la nueva configuración, por ejemplo “Debug Trial” e indicaremos que queremos copiar todos los valores de la configuración ya existente “Debug”.

ConfigurationManager2

Una vez creada esta nueva configuración vamos a otorgarla una valor necesario para nuestro cometido. Para ello, entraremos en las propiedades de nuestro proyecto y en la pestaña de “Build” seleccionaremos la nueva configuración que acabamos de crear, en este caso “Debug Trial”.

ProjectConfiguration

Una vez seleccionada, solamente deberemos de añadir en la casilla de “Conditional compilation symbols:” la palabra “TRIAL” precedida de un punto y como para separarla de las que ya existen. Ojo en el ejemplo indico la palabra Trial, pero obviamente podríamos usar la que quisiéramos.

ProjectConfiguration2

Con nuestra nueva configuración ya creada y parame trizada a nuestro gusto, tan solo nos resta modificar definitivamente nuestro procedimiento para adecuarle a los nuevos cambios.

private void CheckLicense()
{
#if TRIAL
    isTrial = true;
#else
    LicenseInformation license = new Microsoft.Phone.Marketplace.LicenseInformation();

    isTrial = license.IsTrial();
#endif
}

Como vemos la directiva de compilación condicional, ahora busca la palabra “TRIAL” en vez de genéricamente “DEBUG” como anteriormente. Ahora cuando queramos ejecutar en modo debug versión trial, seleccionaremos una opción de compilación, en el caso de compilar en modo debug en versión completo, seleccionaremos otra. Según nos convenga en cada caso.

Execute

Ya tenemos todo nuestro código implementado. Como comento al principio esta es una de las muchas formas de realizar la gestión de las versiones trial de nuestras aplicaciones.

Pero una cosa es segura, cualquier aplicación de pago que se precie de disponer si o si de una versión Trial. Los datos aportados por la Windows Phone Store lo indican. Las aplicaciones con versiones trial son descargadas 70 veces mas que las que no las tienen. Con una media de un 10% de conversiones a versión completa. Lo que representa un 10 veces más ingresos que una aplicación que no disponga de versión trial.

Aquí os dejo el enlace a un ejemplo de código que muestra todo lo que he comentado hasta el momento.

Para cualquier cosa, ya sabéis donde estoy…. 

A pasarlo bien.

I APP YOU

Una vez mas vuelve el concurso semanal por excelencia de aplicaciones para Windows Phone de la mano de Microsoft Ibérica. A partir de hoy mismo, 1 de febrero y hasta el 15 de Mayo. Se sorteara una XBOX 360 por semana para todo aquel que desarrolle y publique en la Windows Phone Store una aplicación.

300x250-iapp

Pero este año disponemos de otra categoría. Y es que también cualquier persona que desarrolle y suba una aplicación para Windows 8, también tendrá su propio sorteo de otra XBOX 360 por semana.

La adjudicación de premios es por riguroso sorteo entre todos los participantes en la promoción, 1 premio para Windows Phone y otro para Windows 8. En esta ocasión no existirá ni jurado ni calificación de la aplicación, quien mas suerte tenga será quien se lleve el gato al agua.

A parte de esto si durante el transcurso de esta promoción es activada una subscripción a Windows Azure, podrás ganar una subscripción a MSDN.

Un aliciente mas para desarrollar……

Suerte a todos.