Programowanie .NET

Archive for the month “Czerwiec, 2012”

Trial i Windows Store API

Cały czas rozpisuję się o nowościach i możliwościach jakie mają aplikacje metro wszystko fajnie jednak nie zapominajmy o rynku na jakim będą dostępne nasze aplikacje a mianowicie Windows Store. Obecnie na świecie jest ok 500 milionów komputerów PC z Windows 7. Niech nawet tylko 10%  z nich przejdzie na Windows 8 to i tak dostęp będziemy mieć do 50 milionów potencjalnych klientów. Nie ma co robi warzenie (przynajmniej na mnie).

Microsoft daje nam narzędzia do łatwiejszego testowania aplikacji w wersji płatnej i próbnej. W przeciwieństwie do Windows Phone 7 tutaj mamy możliwość testowania kupna aplikacji jak również co jest nowością symulowania kupna konkretnych elementów w aplikacji lub grze. Ta druga opcja przyda się szczególnie przy grach.

Tak więc przejdźmy do o kodowania funkcjonalności kupowania. Wszystkie informacje o naszej aplikacji znajdują się w specjalnie przygotowanym pliku którego używamy do symulowania połączenia się ze sklepem. Plik prezentuję poniżej.

<?xml version="1.0" encoding="utf-16" ?>
<CurrentApp>
  <ListingInformation>
    <App>
      <AppId>2B14D306-D8F8-4066-A45B-0FB3464C67F2</AppId>
      <LinkUri>http://apps.microsoft.com/app/2B14D306-D8F8-4066-A45B-0FB3464C67F2</LinkUri>
      <CurrentMarket>en-US</CurrentMarket>
      <AgeRating>3</AgeRating>
      <MarketData xml:lang="en-us">
        <Name>Contoso Cookbook</Name>
        <Description>Metro recipes for Metro developers</Description>
        <Price>08.99</Price>
        <CurrencySymbol>$</CurrencySymbol>
      </MarketData>
    </App>
    <Product ProductId="ItalianRecipes">
      <MarketData xml:lang="en-us">
        <Name>Italian Recipes</Name>
        <Price>0.99</Price>
        <CurrencySymbol>$</CurrencySymbol>
      </MarketData>
    </Product>
  </ListingInformation>
  
  <LicenseInformation>
    <App>
      <IsActive>true</IsActive>
      <IsTrial>true</IsTrial>
      <ExpirationDate>2022-12-31T23:59:59.00Z</ExpirationDate>
    </App>
    <Product ProductId="ItalianRecipes">
      <IsActive>false</IsActive>
    </Product>
  </LicenseInformation>
</CurrentApp>

 

Jak widać znajdują się tutaj dwie główne sekcje. Pierwsza <ListingInformation> przechowuje informacje na temat aplikacji i dodatkowych produktów jakie można kupić w ramach aplikacji. Natomiast drugi element <LicenseInformation> zawiera informacje na temat licencjonowania aplikacji i produktów. Normalnie te informacje będą pochodzić ze sklepu. Jednak w naszym przypadku symulacji będą kopiowane do pliku WindowsStoreProxy.xml (nazwa może być dowolna) z którego system z czyta informacje. W pliku App.xaml.cs odnajdujemy metodę OnLaunched do której wstawiamy następujący kawałek kodu.

// Inocjowanie WindowsStoreProxy.xml
var folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("Microsoft\\Windows Store\\ApiData", CreationCollisionOption.OpenIfExists);
var file = await Package.Current.InstalledLocation.GetFileAsync("Data\\license.xml");
var newfile = await folder.CreateFileAsync("WindowsStoreProxy.xml", CreationCollisionOption.ReplaceExisting);
await file.CopyAndReplaceAsync(newfile);

 

Te cztery linijki otwierają plik licencji jaki mamy w projekcie potem tworzą plik który będzie używany do symulowania zakupi i kopiują dane z pierwszego do drugiego.
Kolejnym krokiem jest stworzenie klasy która będzie przechowywać informacjie na temat licencji tak samo jak się robiło dla aplikacji WP7. Przykładową implementację prezentuję poniżej.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Store;
using Windows.Foundation;

namespace ContosoCookbook
{
    class AppLicenseDataSource : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private bool _licensed = false;
        private string _price;

        public AppLicenseDataSource()
        {
            if (CurrentAppSimulator.LicenseInformation.IsTrial)
            {
                CurrentAppSimulator.LicenseInformation.LicenseChanged += OnLicenseChanged;
                GetListingInformationAsync();
            }
            else
                _licensed = true;
        }

        private async void GetListingInformationAsync()
        {
            var listing = await CurrentAppSimulator.LoadListingInformationAsync();
            _price = listing.FormattedPrice;
        }
        
        private void OnLicenseChanged()
        {
            if (!CurrentAppSimulator.LicenseInformation.IsTrial)
            {
                _licensed = true;
                CurrentAppSimulator.LicenseInformation.LicenseChanged -= OnLicenseChanged;

                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("IsLicensed"));
                    PropertyChanged(this, new PropertyChangedEventArgs("IsTrial"));
                    PropertyChanged(this, new PropertyChangedEventArgs("LicenseInfo"));
                }
            }
        }

        public bool IsLicensed
        {
            get { return _licensed; }
        }

        public bool IsTrial
        {
            get { return !_licensed; }
        }

        public string LicenseInfo
        {
            get
            {
                if (!_licensed)
                    return "Trial Version";
                else
                    return ("Valid until " + CurrentAppSimulator.LicenseInformation.ExpirationDate.LocalDateTime.ToString("dddd, MMMM d, yyyy"));
            }
        }
        
        public string FormattedPrice
        {
            get
            {
                if (!String.IsNullOrEmpty(_price))
                    return "Upgrade to the Full Version for " + _price;
                else
                    return "Upgrade to the Full Version";
            }
        }
    }
}

 

W konstruktorze klasy pobierane są informacje z symulatora zakupu. Między innymi sprawdzana jest wersja w przypadku wersji trial dodawane jest zdarzenie zmiany wersji. Nie będę dokładnie opisywał ponieważ klasa jest prosta. Natomiast kod odpowiedzialny za zakup naszej aplikacji prezentuje się bardzo prosto.

using Windows.ApplicationModel.Store;

CurrentAppSimulator.RequestAppPurchaseAsync();

 

Potrzebujemy dodać jedną przestrzeń nazw i uruchomić jedną metodę. Zostało napisać wygląd prezentowania tych informacji ale to już zależy do każdej aplikacji indywidualnie. Po napisaniu wyglądu jesteśmy gotowi do uruchomienia. U mnie prezentuje się następująco.

Wersja trial
Untitled1

Okno symulujące zakup jak widać mamy kilka scenariuszy do wyboru.Untitled2

I wersja płatna
Untitled3

Ostatnim elementem symulacji zakupów o jakim chcę opowiedzieć jest kupowanie pojedynczych produktów które zwiększają funkcjonalność naszej aplikacji lub gry. Odbywa się to bardzo podobnie jak kupno aplikacji. Znów musimy stworzyć klasę która będzie informować o stanie danego produktu. Przykładowa implementacja.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Store;

namespace ContosoCookbook
{
    class ProductLicenseDataSource : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private const string _name = "ItalianRecipes";
        private bool _licensed = false;
        private string _price;

        public string GroupTitle
        {
            set
            {
                if (value != "Italian")
                    _licensed = true;
                else if (CurrentAppSimulator.LicenseInformation.ProductLicenses[_name].IsActive)
                    _licensed = true;
                else
                {
                    CurrentAppSimulator.LicenseInformation.LicenseChanged += OnLicenseChanged;
                    GetListingInformationAsync();
                }
            }
        }

        private async void GetListingInformationAsync()
        {
            var listing = await CurrentAppSimulator.LoadListingInformationAsync();
            _price = listing.ProductListings[_name].FormattedPrice;
        }
        
        private void OnLicenseChanged()
        {
            if (CurrentAppSimulator.LicenseInformation.ProductLicenses[_name].IsActive)
            {
                _licensed = true;
                CurrentAppSimulator.LicenseInformation.LicenseChanged -= OnLicenseChanged;

                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("IsLicensed"));
                    PropertyChanged(this, new PropertyChangedEventArgs("IsTrial"));
                }
            }
        }
        
        public bool IsLicensed
        {
            get { return _licensed; }
        }

        public bool IsTrial
        {
            get { return !_licensed; }
        }

        public string FormattedPrice
        {
            get
            {
                if (!String.IsNullOrEmpty(_price))
                    return "Purchase Italian Recipes for " + _price;
                else
                    return "Purchase Italian Recipes";
            }
        }
    }
}

 

W tej implementacji właściwość GroupTitle steruje tym czy dany element trzeba kupić. Jest tak ponieważ kod pochodzi od aplikacji kucharskiej a kupić można przepisy włoskie a inne są darmowe. Kod odpowiedzialny za uruchomienie kupna tego produktu jest następujący.

using Windows.ApplicationModel.Store;

CurrentAppSimulator.RequestProductPurchaseAsync("ItalianRecipes");

 

Jak widać Microsoft dał nam spory silnik do testowania kupowania aplikacji.

Suspended

Dzisiaj opiszę czym jest suspended. Pod tym tajemniczym wyrazem kryje się stan aplikacji która nie jest na pierwszym planie czyli użytkownik aktualnie z niej nie korzysta. Podobny stan posiadają aplikacje pisane na smartfony z Windows Phone 7. Po co wspominam o tym stanie? Ponieważ gdy aplikacja znajduje się w stanie zamrożenia (suspended) może nastąpić sytuacja, że system bez pytania zamknie aplikację a użytkownik gdy będzie chciał powrócić do niej z powrotem zdziwi się, że uruchamia się na nowo. Microsoft wprowadził ten stan aby lepiej kontrolować zasoby komputera. Ponieważ gdy aplikacja znajduje się w stanie suspended nie korzysta z żadnych zasobów jak np.: CPU, karta graficzna, kata sieciowa itd.. Korzysta jedynie z pamięci RAM. Natomiast aktualnie działająca aplikacja moze potrzebować więcej pamięci RAM i w tedy system przydzieli jej pamięć zajmowaną przez aplikacje w stanie zamrożenia.

W tym poście pokażę w jakich miejscach należy umieszczać kod aby móc reagować na takie sytuacje. Oczywiście sama reakcja będzie wyglądała inaczej w każdej aplikacji jednak miejsca osadzenia kodu są te same. W moim przypadku będę zapamiętywał stronę na której aktualnie znajduje się użytkownik.

Przed przystąpieniem do pracy warto zapoznać się jak aplikacja reaguje na sytuację  zamrożona i gwałtownego zakończenia. W tym celu wystarczy uruchomić spod Visual Studio aplikację w trybie debug. Po uruchomieniu wracamy do Visual Studio i naciskamy przycisk.

image

Jeśli go nie widzimy to trzeba dodać pasek o nazwie Debug Location.

Po tym jak umiemy już wywołać interesującą nas sytuację nadszedł czas na zapoznanie się gdzie możemy przechowywać informacje tak aby ich nie utracić. Platforma Windows Runtime daje nam dostęp do Windows.Storage.ApplicationData. Jest to klasa która umożliwia przechowywanie danych w następujący sposób:

  • Lokalny folder (LocalFoldet)
  • Lokalne ustawienia (LocatSettings)
  • Zdalny folder (RoamingFolder)
  • Zdalne ustawienia (RoamingSettings)
  • Folder czasowy (TemporaryFolder)

W przypadku zapisu danych na nośnikach zdalnych (przez Internet) Aplikacja może przywracać swój stan pomiędzy urządzeniami. Dodatkowo jeśli użytkownik nie jest zalogowany na koncie Live lub nie ma podłączenia do Internetu system przechowuje dane lokalnie. Aktualnie jest tylko jeden minus w wersji Windows Consumer Preview można przechowywać jedynie 100K danych.

Przejdźmy więc do kodu. W konstruktorze klasy App zobaczycie że jest już dodana obsługa zdarzenia Suspending tak więc w tej metodzie następuje dodanie kodu odpowiedzialnego za zapisanie stanu. W moim przypadku wygląda tak.

ApplicationData.Current.RoamingSettings.Values["Location"] = _location;

Zmienna _location przechowuje aktualną stronę i jest to zapisywane jako zdalne ustawienie. Ustawienia to para klucz/wartość. Tutaj klucz to: “Location” natomiast wartością jest to co przechowuje zmienna _location.

Ostatnim krokiem jest przywrócenie odpowiedniego stanu w przypadku zamrożenia i zamknięcia aplikacji. Dokonujemy tego w metodzie OnLaunched() poprzez dodanie jednego warunku if.

if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
    //TODO: Kod do przywrócenia stanu. U mnie taki
    var location = (string)ApplicationData.Current.RoamingSettings.Values["Location"];
    NavigateToLocation(location);

}

Tiles

Do tej pory cały czas pisałem o tematach cięższych wymagających więcej uwagi dlatego dziś postanowiłem opisać krótki i przyjemny temat. A jest to temat kafelka aplikacji. Spotykam się u wielu osób z podejściem iż kafelek aplikacji traktują po macoszemu to znaczy wstawiają obrazek który mniej lub bardziej pasuje do aplikacji. A trzeba pamiętać że kafelek aplikacji jest pierwszą rzeczą jaką widzi użytkownik i zarazem jedyną rzeczą jaka zachęci do wejścia w szczegóły aplikacji. Tak więc trzeba pamiętać aby projekt kafelka był przemyślany i przykuwający uwagę. Aplikacja może mieć kafelek w dwóch trybach.

  1. o wymiarach 150×150 pikseli
  2. o wymiarach 310×150 pikseli

Aby można było przełączać się pomiędzy małą a dużą ikonką wystarczy w pliku Package.appxmanifest ustawić pola dla małego i dużego kafelka.

image

Przejdźmy teraz do tworzenia dodatkowego kafelka. Tak samo jak na Windows Phone w Windows 8 można oprócz kafelka głównego można dodać sobie dodatkowe kafelki które przenoszą nas bezpośrednio do określonej części aplikacji. kod wstawiania takiego kafelka prezentuje się następująco.

var tile = new SecondaryTile(
    _item.UniqueId,             // Tile ID
    _item.ShortTitle,           // Tile short name
    _item.Title,                // Tile display name
    _item.UniqueId,             // Activation argument
    TileOptions.ShowNameOnLogo, // Tile options
    logo                        // Tile logo
);

tile.RequestCreateAsync();

 

Tak jak w WP7 i tu kafelek ma dwie strony tak więc można było by uzupełnić powyższy kod o drugą stronę. Jeśli ktoś pisał aplikacje na WP7 i tworzył tam dodatkowe kafelki widzi pewnie różnice. Nie ma podawania adresu Url do jakiej części aplikacji ma zostać użytkownik przekierowany. Taki kod musimy sami napisać. i umieszczamy go w metodzie OnLaunched z pliku App.xaml.cs. A tak wygląda.

if (!String.IsNullOrEmpty(args.Arguments))
    _args = args.Arguments;
else
{
    //kod w przypadku jeśli uruchomiliśmy z głównego kafelka.
}

 

Argument args metody OnLaunched ma właściwość Arguments jeśli ta właściwość nie jest pusta to znaczy że uruchomiono z kafelka dodatkowego.

Windows 8 Release Preview–wrażenia

Pod koniec zeszłego tyg. Microsoft udostępnił nam nową wersję Windows 8 oznaczoną jako Release Preview. Jest to wersja która nie równi się za mocno od finalnej. Oznacza to nie mniej nie więcej że to co widzimy nie różnić się będzie mocno od wersji finalnej. Przejdźmy więc do wrażeń jakie mam po instalacji nowego systemu.

Częściowe spolszczenie

Podstawowe aplikacje metro są spolszczone między innymi: Zdjęcia, Muzyka, Poczta, Kalendarz.
1

SkyDrive to jedna z aplikacji która mi najlepiej podoba się w tej wersji jest przejrzyście zrobiona i zarazem łatwa w użyciu i zachęca do korzystania.

Store

Sklepik tu są również duże zmiany. Najważniejszą jest wprowadzenie kategorii tematycznych dla aplikacji. Dostępnych jest 20 kategorii.2

Natomiast w każdej z kategorii można sortować i filtrowa.3

Semantic Zoom

Jest łatwiejszy w użyciu ponieważ ma swoją małą ikonkę w prawym dolnym rogu. Osobiście jednak uważam że ten przycisk jest i tak kiepski.
4

Areo

Wygląd Explorera Windows również się zmienił teraz kolory są jednolite nie ma gradientów czy prześwitywania. Korory są takie jak posiadają aplikacje metro. Mi się lepiej takie kolory podobają niż były w Windows 7. 5

Na koniec zachęcam do ściągnięcia nowego systemu i wypróbowania go samemu.

Post Navigation