Windowsストア アプリ 作り方解説 Line Attack編 第8回 ~アプリ内購入(アプリ内課金) ~

マイクロソフトの田中達彦です。
本連載では、Windowsストアアプリとして作成したパズルゲームである、Line Attackのプログラムを解説します。
Line Attack : https://apps.microsoft.com/webpdp/app/f11e327c-6228-4c8f-8245-ea57d65e0f09

[注意事項]
- この連載で提供するプロジェクトファイルは、サンプルとして提供しています。
- 毎回の記事で提供するプロジェクトファイルは、その時点でのソースコードです。最終バージョンのソースコードと異なる場合があります。

[今回のプロジェクトファイル]
今回提供するプロジェクトは、Windowsストアに上がっているものとほぼ同じものです。
このプロジェクトに最初に表示されるページと、タイルなどの画像ファイルを追加すると、ストア用に作成したリリース1になります。
このプロジェクトには、アプリ内購入の機能が追加され、ステージのデータも50面までは完成しています。

[アプリ内購入について]
Windowsストア アプリは、アプリ内でユーザーに課金することができるアプリ内購入(アプリ内課金、アプリ内販売、in-app purchaseとも言います)を実装できます。
Windowsストアが提供しているアプリ内購入は、開発者が価格と期間を決めることができます。
期間は購入した機能を使用できる期間で、以下の中から選択できます。

これらの期間は、Windowsストアにアプリを申請するときに設定するだけです。
期間限定で使用できる機能を実装するときに、プログラム側で日にちの設定等をする必要はありません。
使用できる期間が終了したときは、ユーザーが明示的に再度購入するまで、ユーザーはその機能を使えません。
ユーザーが意識しないところで課金が発生しないように、自動更新されない仕組みになっています。

アプリ内購入については、下記記事のアプリ内購入の項目もご参照ください。
https://blogs.msdn.com/b/windowsstore_ja/archive/2012/07/26/windows-making-money.aspx

[アプリ内購入の仕組み]
アプリ内購入は、特定の機能を使用できるかどうかのフラグを作成し、ユーザーが購入していたときにその機能を使用できるようにします。
すなわち、アプリ内にすべての機能を実装しておき、フラグによって特定の機能を使用できるか使用できないかを選択できるようにしておきます。
このフラグのことを製品IDと呼びます。
このブログ記事の執筆時では、製品IDは100個まで用意することができます。

製品IDは、ユーザーが未購入のときは無効に設定されています。
ユーザーが購入し、かつ有効期間内であれば、製品IDは有効になります。
コード内で製品IDが有効か無効かを判定し、特定の機能を使用できるように実装します。

ユーザーがアプリを使用しているときに、アプリ内購入の機能を使おうとしたときには以下のようなメッセージが出ます。

ここで[購入]を選択すると、購入のプロセスに進みます。
ここの「説明」と書かれている部分の右にある文章は、Windowsストアにアプリを申請するときに設定します。

[アプリ内購入の実装]
アプリ内購入を実装するには、Windows.ApplicationModel.Storeに含まれる機能を使用しますので、MainPage.xaml.csの最初のusing節が並んでいるところに、以下のようにこの名前空間を追加します。

using Windows.ApplicationModel.Store;

製品IDが有効かどうかを調べるために、以下のようにLicenseInfoというフィールドを用意して、CurrentAppSimulator.LicenseInformationを代入しています。

// in-app purchase
LicenseInformation LicenseInfo;

public MainPage()
{
    this.InitializeComponent();

    Timer.Interval = new TimeSpan(0, 0, 0, 0, 33);
    Timer.Tick += Timer_Tick;
    Timer.Start();

    // in-app purchase
    LicenseInfo = CurrentAppSimulator.LicenseInformation;
}

ここではアプリ内購入のテストを行うために、CurrentAppSimulatorというクラスを使用しています。
このクラスを使うことで、アプリ内購入のシミュレートを行えます。
Windowsストアにアプリを上げる際には、このCurrentAppSimulatorをCurrentAppに変更します。
もし変更を忘れていると、Windowsストアの審査に通りません。

製品IDが有効かどうかのコードは、NextStageメソッドに実装しています。
製品IDは、開発者が任意の文字列を設定します。
ここでは、LAPaidStage1という製品IDを使用しました。

private async void NextStage()
{
    if (LicenseInfo.ProductLicenses["LAPaidStage1"].IsActive)
    {
        if (StageNumber >= MaxStageNumber)
            return;
    }
    else
    {
        if (StageNumber >= MaxFreeStageNumber)
        {
            ListingInformation listing = await CurrentAppSimulator.LoadListingInformationAsync();
            ProductListing paidStage1 = listing.ProductListings["LAPaidStage1"];
            MessageDialog msgBox = new MessageDialog(StringPurchase + paidStage1.FormattedPrice);

            await msgBox.ShowAsync();

            try
            {

                await CurrentAppSimulator.RequestProductPurchaseAsync("LAPaidStage1", false);

                if (LicenseInfo.ProductLicenses["LAPaidStage1"].IsActive)
                {
                    // purchased
                    msgBox.Content = StringThankYou;
                    await msgBox.ShowAsync();
                }
                else
                {
                    return;
                }
            }
            catch
            {
                // in-app purchase does not complete
                return;
            }
        }
    }

    StageNumber++;

    SetPanel(StageNumber);
}

黄色くマーカーした部分で、製品IDが有効かどうかを判定し、もし有効であれば80面までプレイできるようにしています。
もし製品IDが無効の場合は、製品IDの価格の情報を取得し、その情報を一旦MessageDialogを使用して表示しています。
そして、水色でマーカーした部分でWindowsストアの機能を使って購入のためのメッセージを出します。
ただし、今回はCurrentAppSimulatorを使用しているため、Windowsストアのメッセージは出ません。
ユーザーの購入が完了したら、もう一度MessageDialogを表示させています。

[アプリ内購入のシミュレート]
今回公開しているプロジェクトを実行し、ステージ50まで進め、さらに次のステージに進もうとすると以下のように例外が発生します。
なお、ステージ50まで進めるには各ステージをクリアする必要はなく、アプリバーを出して次のステージに進んで行けばステージ50まで行きます。

この例外は、LAPaidStage1という製品IDが設定されていないために発生する例外です。
それでは、製品IDを設定するにはどうすればよいでしょうか?
CurrentAppSimulatorを使用しているときは、以下のフォルダーにあるWindowsStoreProxy.xmlというファイルの内容が、製品IDに関する情報になっています。

{ユーザーフォルダー}\AppData\Local\Packages\{アプリのフォルダー}\LocalState\Microsoft\Windows Store\ApiData

僕の環境の場合は、以下のフォルダーでした。

C:\Users\ttanaka\AppData\Local\Packages\0bd2b685-8093-435c-bd65-f0d9dc933287_ma2j4jc38wtnp\LocalState\Microsoft\Windows Store\ApiData

アプリのフォルダーは、Package.Appxmanifestを開き、[パッケージ化]タブのパッケージ名から推測できます。
AppData\Local\Packagesフォルダーの下には、インストールされているアプリのフォルダーが並んでいます。
その中から、以下のパッケージ名で始まるフォルダーがあれば、そのフォルダーがアプリのフォルダーです。

WindowsStoreProxy.xmlには、デフォルトで以下の情報が含まれています。

<?xml version="1.0" encoding="utf-16" ?>
<CurrentApp>
    <ListingInformation>
        <App>
            <AppId>00000000-0000-0000-0000-000000000000</AppId>
            <LinkUri>https://apps.microsoft.com/webpdp/app/00000000-0000-0000-0000-000000000000</LinkUri>
            <CurrentMarket>en-US</CurrentMarket>
            <AgeRating>3</AgeRating>
            <MarketData xml:lang="en-us">
                <Name>AppName</Name>
                <Description>AppDescription</Description>
                <Price>1.00</Price>
                <CurrencySymbol>$</CurrencySymbol>
                <CurrencyCode>USD</CurrencyCode>
            </MarketData>
        </App>
        <Product ProductId="1" LicenseDuration="0">
            <MarketData xml:lang="en-us">
                <Name>Product1Name</Name>
                <Price>1.00</Price>
                <CurrencySymbol>$</CurrencySymbol>
                <CurrencyCode>USD</CurrencyCode>
            </MarketData>
        </Product>
    </ListingInformation>
    <LicenseInformation>
        <App>
            <IsActive>true</IsActive>
            <IsTrial>true</IsTrial>
        </App>
        <Product ProductId="1">
            <IsActive>true</IsActive>
        </Product>
    </LicenseInformation>
</CurrentApp>

この中の黄色でマーカーした行にある

ProductId="1"

ProductId="LAPaidStage1"

に変更します。
そして、水色でマーカーした部分にある

<IsActive>true</IsActive>

<IsActive>false</IsActive>

に変更します。
これで、LAPainStage1という製品IDを購入していないことになりました。
この状態でアプリを実行し、ステージ50で次のステージに行こうとするとメッセージダイアログが表示された後で以下のテスト用のダイアログが表示されます。

公開しているプロジェクトでは、テスト用のダイアログで何を選択しても、購入が完了したことになりません。
テスト用ダイアログに対応したコードを実装していないためです。
ダイアログが表示されているときに、WindowsStoreProxy.xmlを書き換えてテストを行います。
もしIsActiveの部分をtrueに変更すると、もう一度メッセージダイアログが表示された後でステージ51以降が表示されます。

WindowsStoreProxy.xmlには、製品IDの価格等も設定することができます。
他の項目に関しては、下記サイトをご参照ください。
https://msdn.microsoft.com/ja-jp/library/windows/apps/windows.applicationmodel.store.currentappsimulator.aspx

[シミュレーターからストア用のコードへの変更]
シミュレーターを使用したテストが終わったら、ストア用のコードに変更します。
CurrentAppSimulator の部分を、すべて CurrentApp に変更して、ストア用のパッケージを作ります。

[Windowsストアの申請時の処理]
Windowsストアにアプリを申請するときに、高度な機能というページがあります。
アプリ内購入の情報は、このページで設定します。
なおこのページでは、アプリ内販売という言葉を使っています。

このページの製品IDの部分に、コードで使用した製品IDと同じものを入力します。
あとは価格と有効期間を設定します。
これでアプリ内購入の実装と処理が終わりました。

アプリ内購入については、下記サイトもご参照ください。
https://msdn.microsoft.com/ja-jp/library/windows/apps/hh694067.aspx

[前後の記事]
第7回 日本語と英語への対応
第9回 表紙ページの追加

マイクロソフト
田中達彦

 

Pazzle_idea1_201301211815_InAppPurchase_Stage80draft.zip