次の方法で共有


消費可能なアドオンの購入を有効化する

この記事では、Windows.Services.Store 名前空間の StoreContext クラスのメソッドを使用して、UWP アプリでユーザーの消費型アドオンのフルフィルメントを管理する方法について説明します。 購入、使用、再購入が可能なアイテムには、消耗品アドオンを使用します。 これは特に、ゲーム内通貨 (金、コインなど) などを購入し、特定のパワーアップを購入するために使用できる場合に便利です。

Windows.Services.Store 名前空間は Windows 10 バージョン 1607 で導入され、Windows 10 Anniversary Edition (10.0; Build 14393) またはそれ以降のリリースを対象とするプロジェクトでのみ、Visual Studioで使用できます。 アプリが以前のバージョンの Windows 10 を対象とする場合は、Windows.Services.Store 名前空間ではなく、Windows.ApplicationModel.Store 名前空間を使用する必要があります。 詳細については、こちらの記事を参照してください。

消耗品アドオンの概要

アプリでは、フルフィルメントの管理方法が異なる、2 種類の消費型アドオンを提供できます。

  • 開発者が管理する消耗品。 この種類の消耗品アイテムについては、アドオンが表すアイテムのユーザーの残高を追跡し、ユーザーがすべてのアイテムを消費した後に、ストアにフルフィルメントされたアドオンの購入を報告する責任があります。 アプリが以前のアドオンの購入をフルフィルメント完了として報告するまで、ユーザーはアドオンをもう一度購入できません。

    たとえば、アドオンがゲーム内で 100 コインを表し、ユーザーが 10 コインを消費する場合、アプリまたはサービスはユーザーの新しい残りの残高 90 コインを維持する必要があります。 ユーザーが 100 コインをすべて消費した後、アプリはアドオンをフルフィルメント済みとして報告する必要があります。その後、ユーザーは 100 コイン アドオンをもう一度購入できます。

  • ストアで管理されるコンシューマブル。 この種類の消耗品アイテムの場合、ストアはアドオンが表すアイテムのユーザーの残高を追跡します。 ユーザーがアイテムを使用する場合、ユーザーはそれらのアイテムをフルフィルメント済みとしてストアに報告する責任を負い、ストアはユーザーの残高を更新します。 ユーザーはアドオンを何度でも購入できます (最初にアイテムを使用する必要はありません)。 アプリでは、いつでもユーザーの現在の残高をストアに照会できます。

    たとえば、アドオンがゲームの初期数量 100 コインを表し、ユーザーが 50 コインを消費している場合、アプリは 50 ユニットのアドオンがフルフィルメントされたとストアに報告し、Store は残りの残高を更新します。 その後、ユーザーがアドオンを再購入してさらに100枚のコインを獲得すると、合計150コインになります。

    ストアで管理される消耗品アイテムは、Windows 10 バージョン 1607 で導入されました。

ユーザーに消耗品アドオンを提供するには、次の一般的なプロセスに従います。

  1. ユーザーがアプリからアドオン を 購入できるようにします。
  2. ユーザーがアドオンを使用すると (たとえば、ゲームでコインを使う)、、アドオンをフルフィルメント済みのとして報告します。

ストアで管理される消耗品アイテムの残りの残高 をいつでも取得

[前提条件]

これらの例には、次の前提条件があります。

  • Windows 10 Anniversary Edition (10.0; ビルド 14393) または 以降のリリースを対象とするユニバーサル Windows プラットフォーム (UWP) アプリ用の Visual Studio プロジェクト。
  • パートナー センターでアプリ申請 を作成 しました。このアプリはストアで公開されています。 必要に応じて、テスト中にストアで検出できないようにアプリを構成できます。 詳細については、テスト ガイダンスのを参照してください。
  • あなたはパートナー センターで アプリ用のコンシューマブル アドオンを 作成しました。

これらの例のコードは、次のことを前提としています。

  • このコードは、 という名前の ProgressRingworkingProgressRingという名前の TextBlock を含む textBlock のコンテキストで実行されます。 これらのオブジェクトは、非同期操作が発生していることを示し、出力メッセージをそれぞれ表示するために使用されます。
  • コードファイルには、があり、Windows.Services.Store 名前空間の ステートメントを使用しています。
  • アプリは、アプリを起動したユーザーのコンテキストでのみ実行されるシングル ユーザー アプリです。 詳細については、「アプリ内購入と試用版の」を参照してください。

完全なサンプル アプリケーションについては、ストアのサンプルを参照してください。

デスクトップ ブリッジを使用するデスクトップ アプリケーションがある場合は、これらの例に示されていないコードを追加して、StoreContext オブジェクトを構成する必要がある場合があります。 詳細については、「デスクトップ ブリッジを使用するデスクトップ アプリケーションでの StoreContext クラスの使用」を参照してください。

消耗品アドオンを完了として報告する

ユーザー アプリからアドオン を購入し、アドオンを使用した後、アプリは、StoreContext クラスの ReportConsumableFulfillmentAsync メソッドを呼び出して、アドオンをフルフィルメント済みとして報告する必要があります。 このメソッドには、次の情報を渡す必要があります。

  • 報告する対象のアドオンのストアID は、、フルフィルメント済みとして。
  • 完了として報告するアドオンの単位。
    • 開発者が管理する消耗品アイテムの場合は、数量 パラメーターに 1 を指定します。 これにより、消費型アイテムが満たされたことがストアに通知され、その後、顧客は消耗品アイテムを再度購入できます。 ユーザーは、アプリがストアにフルフィルメントされたことを通知するまで、消費型アイテムを再度購入することはできません。
    • ストアで管理される消耗品アイテムの場合は、消費されたユニットの実際の数を指定します。 ストアでは、消費型アイテムの残高が更新されます。
  • フルフィルメントの追跡 ID。 これは、追跡目的でフルフィルメント操作が関連付けられている特定のトランザクションを識別する、開発者が提供する GUID です。 詳細については、ReportConsumableFulfillmentAsyncの「解説」を参照してください。

この例では、ストアで管理される消耗品アイテムをフルフィルメント済みとして報告する方法を示します。

private StoreContext context = null;

public async void ConsumeAddOn(string addOnStoreId)
{
    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;
    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;
    }
}

ストアで管理される消耗品アイテムの残りの残高を取得する

この例では、StoreContext クラスの GetConsumableBalanceRemainingAsync メソッドを使用して、ストアで管理される消費型アドオンの残りの残高を取得する方法を示します。

private StoreContext context = null;

public async void GetRemainingBalance(string addOnStoreId)
{
    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.
    }

    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;
    }
}