[Win Store App] 對於IAP範例程式碼的研究(1)

不小心把自己的文章刪了,只好重寫一次。
這篇是研究微軟win store app的IAP範例程式碼,以下文章會包含裡面兩個頁面:TrialMode和InAppPurchase
InAppPurchase
變數:
  • rootPage:為了使用MainPage的方法所建立的變數
  • licenseChangeHandler:為LicenseChangedEventHandler型別的變數,處理license改變的事件。
方法
- InAppPurchase 初始子
- OnNavigatedTo 此頁面開啟前會呼叫此方法,是為了做一些準備才要進入此頁面
- OnNavigatingFrom 離開此頁面前呼叫,就好像是收拾善後
- LoadInAppPurchaseProxyFileAsync 讀取App購買的資料
- InAppPurchaseRefreshScenario 更新畫面
- TestProduct1_Click 商品一,測試
- BuyProduct1Button_Click 商品一,購買
- TestProduct2_Click 商品二,測試
- BuyProduct2_Click 商品二,購買
來看看方法吧。首先是公用的方法OnNavigatedTo和OnNavigatingFrom。OnNavigatedTo長這樣:
    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        await LoadInAppPurchaseProxyFileAsync();
    }
這邊只是單純讀取商品資料的檔案,讀取的過程全在LoadInAppPurchaseProxyFileAsync方法內。
再來是OnNavigatingFrom:
    protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
        if (licenseChangeHandler != null)
        {
            CurrentAppSimulator.LicenseInformation.LicenseChanged -= licenseChangeHandler;
        }
        base.OnNavigatingFrom(e);
    }
這邊是解除license改變的通知,然後呼叫父層的OnNavigatingFrom方法。
再來看看LoadInAppPurchaseProxyFileAsync方法:
    private async Task LoadInAppPurchaseProxyFileAsync()
    {
        StorageFolder proxyDataFolder = await Package.Current.InstalledLocation.GetFolderAsync("data");
        StorageFile proxyFile = await proxyDataFolder.GetFileAsync("in-app-purchase.xml");
        licenseChangeHandler = new LicenseChangedEventHandler(InAppPurchaseRefreshScenario);
        CurrentAppSimulator.LicenseInformation.LicenseChanged += licenseChangeHandler;
        await CurrentAppSimulator.ReloadSimulatorAsync(proxyFile);

        // setup application upsell message
        try
        {
            ListingInformation listing = await CurrentAppSimulator.LoadListingInformationAsync();
            var product1 = listing.ProductListings["product1"];
            var product2 = listing.ProductListings["product2"];
            Product1SellMessage.Text = "You can buy " + product1.Name + " for: " + product1.FormattedPrice + ".";
            Product2SellMessage.Text = "You can buy " + product2.Name + " for: " + product2.FormattedPrice + ".";
        }
        catch (Exception)
        {
            rootPage.NotifyUser("LoadListingInformationAsync API call failed", NotifyType.ErrorMessage);
        }
    }
這邊很單純,我分行來講:
  • 第一行讀取名為data的資料夾。
  • 第二行讀取該資料夾內名為in-app-purchase.xml的檔案。
  • 第三行建立license改變的事件處理通知,會使用方法InAppPurchaseRefreshScenario
  • 第四行就是註冊此事件。
  • 第五行,呼叫ReloadSimulatorAsync,他是使用包含WindowsStoreProxy.xml的StorageFile來重新載入模擬器。
再來就進入try-catch的部分:
首先呼叫LoadListingInformationAsync,它是非同步的載入模擬的app列表資訊。他所回傳的ListingInformation物件會包含許多資訊,當然包括了in-app購買的商品列表。然後它取出product1/product2的購買資訊,並且更新頁面上的訊息。最後於丟出例外時,通知使用者一個錯誤訊息。
再來看第一個測試按鈕TestProduct1_Click的內容:
    private void TestProduct1_Click(object sender, RoutedEventArgs e)
    {
        LicenseInformation licenseInformation = CurrentAppSimulator.LicenseInformation;
        var productLicense = licenseInformation.ProductLicenses["product1"];
        if (productLicense.IsActive)
        {
            rootPage.NotifyUser("You can use Product 1.", NotifyType.StatusMessage);
        }
        else
        {
            rootPage.NotifyUser("You don't own Product 1. You must buy Product 1 before you can use it.", NotifyType.ErrorMessage);
        }
    }
首先獲得模擬器的LicenseInformation,然後取得商品1的license。檢查該license是否已啟動,若是,則通知使用者可以使用。
再來看購買商品的按鈕BuyProduct1Button_Click:
    private async void BuyProduct1Button_Click(object sender, RoutedEventArgs e)
    {
        LicenseInformation licenseInformation = CurrentAppSimulator.LicenseInformation;
        if (!licenseInformation.ProductLicenses["product1"].IsActive)
        {
            rootPage.NotifyUser("Buying Product 1...", NotifyType.StatusMessage);
            try
            {
                await CurrentAppSimulator.RequestProductPurchaseAsync("product1");
                if (licenseInformation.ProductLicenses["product1"].IsActive)
                {
                    rootPage.NotifyUser("You bought Product 1.", NotifyType.StatusMessage);
                }
                else
                {
                    rootPage.NotifyUser("Product 1 was not purchased.", NotifyType.StatusMessage);
                }
            }
            catch (Exception)
            {
                rootPage.NotifyUser("Unable to buy Product 1.", NotifyType.ErrorMessage);
            }
        }
        else
        {
            rootPage.NotifyUser("You already own Product 1.", NotifyType.ErrorMessage);
        }
    }
一開始一樣是取得license,然後檢查商品1的license是否可使用,若否,通知使用者需要購買。反之則是通知使用者你已擁有。
然後在第一個情況內(未購買)呼叫RequestProductPurchaseAsync,模擬購買商品1。然後如果該商品的license啟用了,就通知使用者你已購買。反之,則通知未被購買。並捕捉例外狀況。
剩下兩個按鈕同上,不贅述。
TrialMode
變數:
  • rootPage:為了使用MainPage的方法所建立的變數
  • licenseChangeHandler:為LicenseChangedEventHandler型別的變數,處理license改變的事件。
方法
- TrialMode 初始子
- OnNavigatedTo 此頁面開啟前會呼叫此方法,是為了做一些準備才要進入此頁面
- OnNavigatingFrom 離開此頁面前呼叫,就好像是收拾善後
- LoadTrialModeProxyFileAsync 讀取App購買的資料
- TrialModeRefreshScenario 更新畫面
- TrialTime_Click 按鈕
- TrialProduct_Click 按鈕
- FullProduct_Click 按鈕
- ConvertTrial_Click 按鈕
方法有許多重複的部分就不講了,直接看按鈕。
首先是TrialTime_Click:
                var remainingTrialTime = (licenseInformation.ExpirationDate - DateTime.Now).Days;
重要的就是那個顯示時間的部分。獲得模擬器的license後,使用ExpirationDate欄位取得日期,減去現在日期DateTime.Now,然後轉換成日數,就得到剩餘天數了。
再來看看ConvertTrial_Click:
                    await CurrentAppSimulator.[RequestAppPurchaseAsync][2](false);
這是模擬購買完整版app的動作,false是說不用回傳收據。

留言