Dziś chcę poruszyć temat sprzedawania aplikacji napisanych na Windows Phone 7. Wydaje mi się, że każda osoba tworząca jakiekolwiek oprogramowanie chce, aby oprócz satysfakcji ze zrobienia czegoś pożytecznego, uzyskać korzyści finansowe. W zależności od wybranego modelu sprzedaży istnieją różne sposoby zarabiania na stworzonych aplikacjach. Jednakże, w przypadku telefonów z Windows Phone 7 najpowszechniejsze są następujące dwa:

  • reklamy,
  • sprzedaż aplikacji na Windows Phone Marketplace.

W tym artykule chciałbym poruszyć dokładniej drugi sposób – sprzedaż aplikacji na Windows Phone Marketplace.

Mam nadzieję, że każdy zdaje sobie sprawę z tego, że skuteczna sprzedaż aplikacji zależy przede wszystkim od sposobu jej zaprezentowania. Na sposób ten składają się następujące czynniki:

  • tytuł programu,
  • opis programu,
  • materiały multimedialne,
  • wersja demonstracyjna.

Nikt przecież nie lubi kupować kota w worku i stara się wybrać program, który udało się najlepiej poznać. Z tego powodu należy się przyłożyć do sporządzenia dokładnego opisu oraz zdjęć programu. Plusem może być również przygotowanie krótkiej prezentacji programu w postaci filmu, na którym zostaną przedstawione najważniejsze jego funkcje i sposób działania. Nie bez znaczenia pozostaje też trafność wyboru nazwy programu. Im bardziej będzie ona trafiona w gusta użytkowników, tym łatwiej nasz program zostanie znaleziony w Internecie, a tym samym występuje większa szansa na jego zakup.

 

Wersja demonstracyjna

Tematem, któremu chcę poświęcić więcej uwagi jest wersja demonstracyjna programu. Przed programistą stoi wybór czy jego program będzie posiadał wersję demonstracyjną, czy też nie. W sytuacji, gdy odbiorcami jest duża ilość osób to wybór jest oczywisty – program musi być wyposażony w wersję demonstracyjną. Microsoft podaje następujące fakty dotyczące wersji demonstracyjnej:

  • Użytkownicy lubią programy wyposażone w wersję demonstracyjną. Takie programy są ściągane 70 razy częściej niż inne płatne programy bez wersji demonstracyjnej.
  • 1 na 10 ściągnięć wersji demonstracyjnej kończy się zakupem.
  • Programy wyposażone w wersję demonstracyjną generują średnio 10 razy większe zyski niż programy bez wersji demonstracyjnej.
  • Programy wyposażone w wersję demonstracyjną przynoszą zyski szybciej od programów bez wersji demonstracyjnej. W przypadku 50% programów wyposażonych w wersję demonstracyjną, zakup pełnej wersji następował w czasie krótszym niż jeden dzień, a większości przypadków w przeciągu 2 godzin od ściągnięcia.

Powyższe stwierdzenia powodują, że teoretycznie na ma wyboru i należy przygotować wersję demonstracyjną.

Zatem zacznijmy od początku przygotowywać aplikację wyposażoną w wersję demonstracyjną. W tym celu stworzymy klasę wraz w właściwością przechowującą informację o tym, czy program jest używany jako wersja demonstracyjna, czy też wersja pełna.

public static class VersionInfo
{
  /// <summary>
  /// Gets a value indicating whether this instance is trial version.
  /// </summary>
  /// <value>
  ///   <c>true</c> if this instance is trial version; otherwise, <c>false</c>.
  /// </value>
  public static bool IsTrialVersion { get; private set; }
}

Własność IsTrialVersion jest statyczna i niemodyfikowalna z zewnątrz klasy. Używamy jej w sytuacji, gdy chcemy nałożyć jakieś ograniczenia na użytkownika i sprawdzić, czy posiadany program jest w wersji pełnej, czy demonstracyjnej. Takimi ograniczeniami mogą być:

  • ograniczona ilość uruchomień,
  • wyłączenie, bądź też ograniczenie niektórych funkcjonalności,
  • określony czas działania,
  • wyświetlanie reklam.

 

Sprawdzanie licencji

W celu pełnego wykorzystanie wspomnianej właściwości należy sprawdzić jaki jest status naszej aplikacji. Microsoft w tym przypadku staną na wysokości zadania i przygotował bardzo łatwy mechanizm do zrobienia tego. Klasa Microsoft.Phone.Marketplace.LicenseInformation dostarcza metodę IsTrial(), która zwraca informację, czy program jest uruchomiony w wersji demonstracyjnej, czy też pełnej. Bardzo często popełnianym błędem jest nadużywanie metody IsTrial(). Ze względu na łatwość jej wywołania (new Microsoft.Phone.Marketplace.LicenseInformation()).IsTrial() programiści wykorzystują ją bezpośrednio do sprawdzenie statusu programu. Jest to błąd, który może znacząco obniżyć wydajność programu. Wywołanie metody IsTrial() może trwać 60 ms i więcej. Z tego powodu należy, wynik jej wywołania przechowywać lokalnie. Do tego celu zostanie użyta własność IsTrialVersion.

Drugą rzeczą o jakiej należy pamiętać jest fakt, że metoda IsTrial() w trybie debug zawsze zwraca wartość false. Powoduje to, że musimy użyć jakiś mechanizm, który pozwoli na przeprowadzenie testów aplikacji. Można zastosować dwa podejścia. Podejście pierwsze na podstawie przykładu z dokumentacji:

/// <summary>
/// Updates the information about trial status.
/// </summary>
public static void UpdateTrialInformation()
{
  #if DEBUG
    MessageBoxResult result = MessageBox.Show("CLICK OK TO SIMULATE FULL LICENSE",
               "BUY NOW!", MessageBoxButton.OKCancel);
    if (result == MessageBoxResult.OK)
    {
      IsTrialVersion = false;
    }
    else
    {
      IsTrialVersion = true;
    }
  #else
     IsTrialVersion = (new Microsoft.Phone.Marketplace.LicenseInformation()).IsTrial();
  #endif
}

Microsoft proponuje, aby za każdym razem, gdy jest odświeżana informacja o trybie działania programu wyświetlić okno z pytaniem, w jakiej wersji uruchomić program. W zależności od uzyskanej odpowiedzi program będzie działał w wersji demonstracyjnej, bądź też pełnej. Pytanie to pojawi się tylko w trybie debug.

 

Testowanie wersji demonstracyjnej

Drugim rozwiązaniem jest użycie konfiguracji projektu oraz dyrektyw preprocesora. Podobnie jak w poprzednim przypadku zostanie wykorzystana dyrektywa #if oraz dodatkowo zdefiniowany symbol TRIAL. Metoda UpdateTrialInformation() będzie wyglądać w następujący sposób:

/// <summary>
/// Updates the information about trial status.
/// </summary>
public static void UpdateTrialInformation()
{
  #if TRIAL
    IsTrialVersion = true;
  #else
    IsTrialVersion = (new Microsoft.Phone.Marketplace.LicenseInformation()).IsTrial();
  #endif
}

Pozostaje jeszcze tylko jeszcze odpowiednie skonfigurowanie projektu, aby można było przełączać pomiędzy wersją pełną i demonstracyjną programu. W tym celu należy wykonać następujące czynności:

  1. Otworzyć menadżera konfiguracji.
    Menadżer konfiguracji - wybór konfiguracji
  2. Dodać nową konfigurację do projektu wybierając z listy New.
    Okno menadżera konfiguracji - nowa konfiguracja
  3. Wpisać nazwę oraz wskazać, aby skopiowała ustawienia z konfiguracji o nazwie Debug.
    Nowa konfiguracja rozwiązania
  4. Po kliknięciu przycisku OK powinniśmy otrzymać następujący widok.
    Okno menadżera konfiguracji
  5. Na koniec pozostaje już tylko poprawienie ustawień projektu. W zakładce
    Build
    i polu Conditional compilation symbols należy dodać słowo TRIAL po średniku.
    Właściwości projektu

Po wykonaniu tych kroków będzie można wybrać czy aplikacją ma się uruchomić w trybie pełnym, czy też demonstracyjnym. Wystarczy tylko zmienić aktywną konfigurację

Menadżer konfiguracji - wybór konfiguracji dla wersji demonstracyjnej

Takie rozwiązanie wydaje mi się lepsze, ponieważ mamy zawsze 100% pewność w jakim trybie mamy uruchomioną daną aplikację.

 

Optymalizacja sprawdzania licencji

Podsumowując wcześniejsze rozważania do tej poru wiemy już jak sprawdzić czy aplikacją działa w trybie pełnym, czy też demonstracyjnym oraz w jaki sposób można emulować tryb demonstracyjny w aplikacji. Wiemy również, że nie należy nadużywać metody IsTrial() ponieważ działa ona zbyt wolno. Należy się, więc zastanowić kiedy powinno się sprawdzać, czy na daną aplikację została już wykupiona licencja. Odpowiedź wydaje się oczywista – przed uruchomieniem programu lub też przy pierwszym zapotrzebowaniu na tę informację. Oba rozwiązania są poprawne, ale proponowałbym wykorzystać pierwsze.

Wybór ten wynika ze sposobu działania aplikacji w Windows Phone 7. W pierwszym przypadku należy dodać sprawdzanie licencji w momencie uruchamiania programu, jak również jego ponownej aktywacji. W obu przypadkach kod jest taki sam. W przypadku drugiego rozwiązania – pobierania informacji w przypadku pierwszego zapotrzebowania – można zrezygnować ze sprawdzania licencji w momencie startu programu, ale za to trzeba dodać funkcjonalność sprawdzania licencji przed pierwszym zapotrzebowaniem na nią.

Jak widać w obu przypadkach dane o licencji pobierane są tyle samo razy, tylko w innych miejscach. Biorąc pod uwagę fakt, że wersja demonstracyjna powinna mieć wyłączone funkcjonalności, za które użytkownik jest gotów zapłacić, to można powiedzieć, że sprawdzanie licencji nastąpi zawsze. Oznacza to, że można sprawdzanie tylko opóźnić, ale nie wyeliminować.

Zastosowanie pierwszego rozwiązania spowoduje, że program będzie zawsze zachowywał się w ten sam sposób. Możliwie, że uruchomienie programu zajmie trochę więcej, ale zawsze powinien być to czas porównywalny. Oprócz tego należy mieć też na uwadze fakt, że użytkownicy są przyzwyczajeni do tego, że aplikacja potrzebuje trochę czasu na uruchomienie się.

Zastosowanie drugiego rozwiązania powinno przyśpieszyć start aplikacji, ale z drugiej strony może wprowadzić niewielki chaos w działaniu aplikacji. W zależności od wybranej ścieżki, sprawdzenie licencji, a tym samym spowolnienie działania aplikacji, może nastąpić w różnych miejscach. Doświadczenie uczy, że użytkownicy nie lubią losowości i na pewno zgłoszą błąd, że dana funkcjonalność potrafi czasami zadziałać wolniej. Z punktu widzenia programisty program działa poprawnie, ponieważ w tych momentach sprawdzana jest licencja. Z tego powodu lepiej wybrać pierwsze rozwiązanie – mogą pojawić się małe opóźnienia w starcie programu, ale przynajmniej pozostałe funkcjonalności będą zawsze działały z taką samą wydajnością.

Implementacja pierwszego rozwiązania jest bardzo prosta – wystarczy uruchomić metodę UpdateTrialInformation() w odpowiednich miejscach. Wystarczy podpiąć się pod zdarzenia:

  • Launching
  • Activated

 

Funkcjonalność – Kup teraz

Tak przygotowany program jest gotowy do ograniczania niektórych funkcjonalności. Robi się to poprzez sprawdzenie wartości własność VersionInfo.IsTrialVersion. W przypadku,  gdy otrzymamy wartość true należy zablokować daną funkcjonalność oraz poinformować użytkownika o tym fakcie. Dobrym rozwiązaniem jest dodanie funkcjonalności, która pozwoli na przejście do strony, gdzie można kupić pełną wersję programu. Dodatnie takiej funkcjonalności ułatwia biblioteka Coding4Fun, a dokładniej MessagePrompt. Jest to dobrze konfigurowalne okno powiadomienia. Poniższy kod przedstawia sposób jego użycia:

MessagePrompt prompt = new MessagePrompt();
prompt.HorizontalAlignment = HorizontalAlignment.Center;
prompt.VerticalAlignment = VerticalAlignment.Center;
prompt.Title = "Buy full version";
prompt.Message = "In trial version password length is limited to 7 characters. Please buy full version to unlock longer passwords. Also full version doesn’t contain ads.";
prompt.ActionPopUpButtons.Clear();
prompt.Overlay = new SolidColorBrush(Color.FromArgb(155, 41, 41, 41));
Button btnBuyFullVersion = new Button {Content = "Buy full version"};
btnBuyFullVersion.Click += new RoutedEventHandler(btnBuyFullVersion_Click);
prompt.ActionPopUpButtons.Add(btnBuyFullVersion);
prompt.Show();

Wynikiem działania tego kodu będzie następując okno.

Funkcjonalność - Kup pełną wersję

Uważny czytelnik zauważy, że w powyższym kodzie brakuje jednej metody – obsługi przycisku Buy full version. Metoda ta powinna umożliwić zakupienie aplikacji. Do tego celu należy wykorzystać zadanie MarketplaceDetailTask. Użycie jego jest bardzo proste, wystarczy podać tylko numer identyfikacyjny aplikacji. Metoda ta wygląda w następujący sposób:

/// <summary>
/// Handles the Click event of the btnBuyFullVersion control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
void btnBuyFullVersion_Click(object sender, RoutedEventArgs e)
{
  MarketplaceDetailTask task = new MarketplaceDetailTask();
  task.ContentType = MarketplaceContentType.Applications;
  task.ContentIdentifier = "f2f8c9d6-bc9a-e011-986b-78e7d1fa76f8";
  task.Show();
}

I tak oto otrzymujemy wszystkie elementy układanki, które są potrzebne, aby zrobić program posiadający wersję demonstracyjną.