コンシューマブルなアドオン購入の有効化Enable consumable add-on purchases

この記事では、Windows.Services.Store 名前空間の StoreContext クラスのメソッドを使って、ユーザーによる UWP アプリでのコンシューマブルなアドオンフルフィルメントを管理する方法を示します。This article demonstrates how to use methods of the StoreContext class in the Windows.Services.Store namespace to manage the user's fulfillment of consumable add-ons in your UWP apps. コンシューマブルなアドオンは、購入、使用、再購入可能なアイテムに使います。Use consumable add-ons for items that can be purchased, used, and purchased again. これは、購入して、特定のパワーアップを購入するために使うことができるゲーム内通貨 (ゴールド、コインなど) 用に特に便利です。This is especially useful for things like in-game currency (gold, coins, etc.) that can be purchased and then used to purchase specific power-ups.

注意

Windows.Services.Store 名前空間は、Windows 10 バージョン 1607 で導入され、Visual Studio で、Windows 10 Anniversary Edition (10.0、ビルド 14393) 以降のリリースをターゲットとするプロジェクトでのみ使用できます。The Windows.Services.Store namespace was introduced in Windows 10, version 1607, and it can only be used in projects that target Windows 10 Anniversary Edition (10.0; Build 14393) or a later release in Visual Studio. アプリが Windows 10 の以前のバージョンをターゲットとする場合、Windows.Services.Store 名前空間の代わりに Windows.ApplicationModel.Store 名前空間を使う必要があります。If your app targets an earlier version of Windows 10, you must use the Windows.ApplicationModel.Store namespace instead of the Windows.Services.Store namespace. 詳しくは、この記事をご覧ください。For more information, see this article.

コンシューマブルなアドオンの概要Overview of consumable add-ons

アプリは、フルフィルメントを管理する方法が異なる 2 種類のコンシューマブルなアドオンを提供することができます。Apps can offer two types of consumable add-ons that differ in the way that fulfillments are managed:

  • 開発者により管理されるコンシューマブルDeveloper-managed consumable. この種類のコンシューマブルでは、アドオンが表すユーザーのアイテムの残量を追跡し、ユーザーによってすべてのアイテムが消費されたらアドオンの購入をフルフィルメント完了としてストアに報告する義務が開発者にあります。For this type of consumable, you are responsible for keeping track of the user's balance of items that the add-on represents, and for reporting the purchase of the add-on as fulfilled to the Store after the user has consumed all of the items. 以前のアドオン購入をフルフィルメント完了としてアプリで報告するまで、ユーザーがそのアドオンを再購入することはできません。The user cannot purchase the add-on again until your app has reported the previous add-on purchase as fulfilled.

    たとえば、アドオンがゲーム内の 100 コインを表しており、ユーザーによって 10 コインが消費されている場合、アプリまたはサービスでは、ユーザーの 90 コインの残高を保持する必要があります。For example, if your add-on represents 100 coins in a game and the user consumes 10 coins, your app or service must maintain the new remaining balance of 90 coins for the user. ユーザーによって 100 コインすべてが消費されたら、アプリでそのアドオンをフルフィルメント完了として報告する必要があります。その後、ユーザーは 100 コイン アドオンを再購入できます。After the user has consumed all 100 coins, your app must report the add-on as fulfilled, and then the user can purchase the 100 coin add-on again.

  • ストアで管理されるコンシューマブルStore-managed consumable. この種類のコンシューマブルでは、アドオンが表すユーザーのアイテムの残量はストアで追跡します。For this type of consumable, the Store keeps track of the user's balance of items that the add-on represents. ユーザーによりアイテムが消費されたら、そのアイテムをフルフィルメント完了としてストアに報告する義務が開発者にあり、ストアによってユーザーの残量が更新されます。When the user consumes any items, you are responsible for reporting those items as fulfilled to the Store, and the Store updates the user's balance. ユーザーは、必要な回数だけアドオンを購入できます (最初にアイテムを使用する必要はありません)。The user can purchase the add-on as many times as they want (they do not need to consume the items first). アプリでは、ユーザーのアイテムの現在の残量をいつでも Microsoft Store に照会できます。Your app can query the Store for the current balance for the user at any time.

    たとえば、アドオンがゲーム内の 100 のコインの初期量を表しており、ユーザーによって 50 コインが消費された場合、そのアドオンの 50 ユニットがフルフィルメント完了したことをアプリで Microsoft Store に報告すると、Microsoft Store により残高が更新されます。For example, if your add-on represents an initial quantity of 100 coins in a game and the user consumes 50 coins, your app reports to the Store that 50 units of the add-on were fulfilled, and the Store updates the remaining balance. ユーザーがアドオンを再購入して 100 個以上のコインを獲得した場合、合計で 150 個のコインを手にします。If the user then repurchases your add-on to acquire 100 more coins, they will now have 150 coins total.

    注意

    Microsoft Store で管理されるコンシューマブルは Windows 10 バージョン 1607 で導入されました。Store-managed consumables were introduced in Windows 10, version 1607.

コンシューマブルなアドオンをユーザーに提供するには、この一般的なプロセスに従います。To offer a consumable add-on to a user, follow this general process:

  1. ユーザーがアプリからアドオンを購入するようにしてください。Enable users to purchase the add-on from your app.
  2. ユーザーがアドオンを消費するとき (たとえば、ゲームでコインを消費する場合)、アドオンをフルフィルメント完了として報告します。When the user consumes the add-on (for example, they spend coins in a game), report the add-on as fulfilled.

さらに、ストアで管理されるコンシューマブルの場合、いつでも残高を取得することができます。At any time, you can also get the remaining balance for a Store-managed consumable.

前提条件Prerequisites

これらの例には、次の前提条件があります。These examples have the following prerequisites:

  • Windows 10 Anniversary Edition (10.0、ビルド 14393) 以降のリリースをターゲットとするユニバーサル Windows プラットフォーム (UWP) アプリの Visual Studio プロジェクト。A Visual Studio project for a Universal Windows Platform (UWP) app that targets Windows 10 Anniversary Edition (10.0; Build 14393) or a later release.
  • Windows デベロッパー センター ダッシュボードでアプリの申請を作成し、このアプリが Microsoft Store で公開されている。You have created an app submission in the Windows Dev Center dashboard and this app is published in the Store. 必要に応じて、テスト中に Microsoft Store でアプリを検索できないようにアプリを構成することも可能です。You can optionally configure the app so it is not discoverable in the Store while you test it. 詳しくは、テスト ガイダンスをご覧ください。For more information, see our testing guidance.
  • デベロッパー センター ダッシュボードでアプリのコンシューマブルなアドオンを作成した。You have created a consumable add-on for the app in the Dev Center dashboard.

これらの例のコードは、次の点を前提としています。The code in these examples assume:

  • コードは、workingProgressRing という名前の ProgressRingtextBlock という名前の TextBlock を含む Page のコンテキストで実行されます。The code runs in the context of a Page that contains a ProgressRing named workingProgressRing and a TextBlock named textBlock. これらのオブジェクトは、それぞれ非同期操作が発生していることを示するためと、出力メッセージを表示するために使用されます。These objects are used to indicate that an asynchronous operation is occurring and to display output messages, respectively.
  • コード ファイルには、Windows.Services.Store 名前空間の using ステートメントがあります。The code file has a using statement for the Windows.Services.Store namespace.
  • アプリは、アプリを起動したユーザーのコンテキストでのみ動作するシングル ユーザー アプリです。The app is a single-user app that runs only in the context of the user that launched the app. 詳しくは、「アプリ内購入と試用版」をご覧ください。For more information, see In-app purchases and trials.

完全なサンプル アプリケーションについては、ストア サンプルをご覧ください。For a complete sample application, see the Store sample.

注意

デスクトップ ブリッジを使用するデスクトップ アプリケーションがある場合、これらの例には示されていないコードを追加して StoreContext オブジェクトを構成することが必要になることがあります。If you have a desktop application that uses the Desktop Bridge, you may need to add additional code not shown in these examples to configure the StoreContext object. 詳しくは、「デスクトップ ブリッジを使用するデスクトップ アプリケーションでの StoreContext クラスの使用」をご覧ください。For more information, see Using the StoreContext class in a desktop application that uses the Desktop Bridge.

コンシューマブルなアドオンをフルフィルメント完了として報告するReport a consumable add-on as fulfilled

ユーザーがアプリからアドオンを購入してアドオンを消費したら、StoreContext クラスの ReportConsumableFulfillmentAsync メソッドを呼び出すことでアドオンをフルフィルメント完了として報告する必要があります。After the user purchases the add-on from your app and they consume your add-on, your app must report the add-on as fulfilled by calling the ReportConsumableFulfillmentAsync method of the StoreContext class. 次の情報をこのメソッドに渡す必要があります。You must pass the following information to this method:

  • フルフィルメント完了として報告するアドオンのストア IDThe Store ID of the add-on that you want to report as fulfilled.
  • フルフィルメント完了として報告するアドオンの単位。The units of the add-on you want to report as fulfilled.
    • 開発者により管理されるコンシューマブルの場合、quantity パラメーターには 1 を指定します。For a developer-managed consumable, specify 1 for the quantity parameter. これにより、コンシューマブルのフルフィルメントが完了したことがストアに通知され、ユーザーがそのコンシューマブルをもう一度購入できるようになります。This alerts the Store that the consumable has been fulfilled, and the customer can then purchase the consumable again. ユーザーは、アプリがストアにフルフィルメント完了を通知するまで、コンシューマブルをもう一度購入することができません。The user cannot purchase the consumable again until your app has notified the Store that it was fulfilled.
    • ストアで管理されるコンシューマブルの場合、消費された単位の実際の数を指定します。For a Store-managed consumable, specify the actual number of units that have been consumed. ストアにより、コンシューマブルの残高が更新されます。The Store will update the remaining balance for the consumable.
  • フルフィルメントの追跡 ID。The tracking ID for the fulfillment. これは、開発者が指定する GUID で、追跡目的でフルフィルメント操作が関連付けられている特定のトランザクションを識別します。This is a developer-supplied GUID that identifies the specific transaction that the fulfillment operation is associated with for tracking purposes. 詳しくは、「ReportConsumableFulfillmentAsync」の解説をご覧ください。For more information, see the remarks in ReportConsumableFulfillmentAsync.

この例では、ストアで管理されるコンシューマブルをフルフィルメント完了として報告する方法を示します。This example demonstrates how to report a Store-managed consumable as fulfilled.

private StoreContext context = null;

public async void ConsumeAddOn(string storeId)
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
        // If your app is a desktop app that uses the Desktop Bridge, you
        // may need additional code to configure the StoreContext object.
        // For more info, see https://aka.ms/storecontext-for-desktop.
    }

    // This is an example for a Store-managed consumable, where you specify the actual number
    // of units that you want to report as consumed so the Store can update the remaining
    // balance. For a developer-managed consumable where you maintain the balance, specify 1
    // to just report the add-on as fulfilled to the Store.
    uint quantity = 10;
    string addOnStoreId = "9NBLGGH4TNNR";
    Guid trackingId = Guid.NewGuid();

    workingProgressRing.IsActive = true;
    StoreConsumableResult result = await context.ReportConsumableFulfillmentAsync(
        addOnStoreId, quantity, trackingId);
    workingProgressRing.IsActive = false;

    // Capture the error message for the operation, if any.
    string extendedError = string.Empty;
    if (result.ExtendedError != null)
    {
        extendedError = result.ExtendedError.Message;
    }

    switch (result.Status)
    {
        case StoreConsumableStatus.Succeeded:
            textBlock.Text = "The fulfillment was successful. " + 
                $"Remaining balance: {result.BalanceRemaining}";
            break;

        case StoreConsumableStatus.InsufficentQuantity:
            textBlock.Text = "The fulfillment was unsuccessful because the remaining " +
                $"balance is insufficient. Remaining balance: {result.BalanceRemaining}";
            break;

        case StoreConsumableStatus.NetworkError:
            textBlock.Text = "The fulfillment was unsuccessful due to a network error. " +
                "ExtendedError: " + extendedError;
            break;

        case StoreConsumableStatus.ServerError:
            textBlock.Text = "The fulfillment was unsuccessful due to a server error. " +
                "ExtendedError: " + extendedError;
            break;

        default:
            textBlock.Text = "The fulfillment was unsuccessful due to an unknown error. " +
                "ExtendedError: " + extendedError;
            break;
    }
}

ストアで管理されるコンシューマブルの残高の取得Get the remaining balance for a Store-managed consumable

この例では、StoreContext クラスの GetConsumableBalanceRemainingAsync メソッドを使って、ストアで管理されるコンシューマブルなアドオンを取得する方法を示します。This example demonstrates how to use the GetConsumableBalanceRemainingAsync method of the StoreContext class to get the remaining balance for a Store-managed consumable add-on.

private StoreContext context = null;

public async void GetRemainingBalance(string storeId)
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
        // If your app is a desktop app that uses the Desktop Bridge, you
        // may need additional code to configure the StoreContext object.
        // For more info, see https://aka.ms/storecontext-for-desktop.
    }

    string addOnStoreId = "9NBLGGH4TNNR";

    workingProgressRing.IsActive = true;
    StoreConsumableResult result = await context.GetConsumableBalanceRemainingAsync(addOnStoreId);
    workingProgressRing.IsActive = false;

    // Capture the error message for the operation, if any.
    string extendedError = string.Empty;
    if (result.ExtendedError != null)
    {
        extendedError = result.ExtendedError.Message;
    }

    switch (result.Status)
    {
        case StoreConsumableStatus.Succeeded:
            textBlock.Text = "Remaining balance: " + result.BalanceRemaining;
            break;

        case StoreConsumableStatus.NetworkError:
            textBlock.Text = "Could not retrieve balance due to a network error. " +
                "ExtendedError: " + extendedError;
            break;

        case StoreConsumableStatus.ServerError:
            textBlock.Text = "Could not retrieve balance due to a server error. " +
                "ExtendedError: " + extendedError;
            break;

        default:
            textBlock.Text = "Could not retrieve balance due to an unknown error. " +
                "ExtendedError: " + extendedError;
            break;
    }
}