共用方式為


使用 Store 服務管理針對性供應項目

如果您在合作夥伴中心的 [參與] > [針對性供應項目] 頁面為應用程式建立了針對性供應項目,請使用應用程式的程式碼 Microsoft Store 針對性供應項目 API來擷取有助於您為針對性供應項目可實作於應用程式內體驗的資訊。 如需針對性供應項目以及如何在儀表板中建立這些項目的詳細資訊,請參閱使用針對性供應項目將參與度和轉換率最大化。

針對性供應項目 API 是簡單的 REST API,您可以根據使用者是否屬於針對性供應項目的客戶區分,用來取得目前使用者可用的針對型供應項目。 若要在應用程式的程式碼中使用此 API,請遵循下列步驟:

  1. 取得您應用程式目前登入使用者的 Microsoft 帳戶權杖
  2. 取得目前使用者的針對性供應項目
  3. 針對與其中一個針對性供應項目相關聯的附加元件,實作於應用程式內購買體驗。 如需實作應用程式內購買的詳細資訊,請參閱這篇文章

如需示範所有這些步驟的完整程式碼範例,請參閱本文結尾的程式碼範例。 下列各節提供每個步驟的詳細資料。

取得目前使用者的 Microsoft 帳戶權杖

在應用程式的程式碼中,取得目前登入使用者的 Microsoft 帳戶 (MSA) 權杖。 您必須在 Microsoft Store 針對性供應項目 API 的 Authorization 要求標頭中傳遞此權杖。 Store 會使用此權杖來擷取目前使用者可用的針對性供應項目。

若要取得 MSA 權杖,請使用 WebAuthenticationCoreManager 類別來要求使用範圍 devcenter_implicit.basic,wl.basic 的權杖。 下列範例示範如何進行這項操作。 此範例是完整範例的摘錄,它需要使用完整範例中提供的陳述式。

private async Task<string> GetMicrosoftAccountTokenAsync()
{
    var msaProvider = await WebAuthenticationCoreManager.FindAccountProviderAsync(
        "https://login.microsoft.com", "consumers");

    WebTokenRequest request = new WebTokenRequest(msaProvider, "devcenter_implicit.basic,wl.basic");
    WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);

    if (result.ResponseStatus == WebTokenRequestStatus.Success)
    {
        return result.ResponseData[0].Token;
    }
    else
    {
        return string.Empty;
    }
}

如需取得 MSA 權杖的詳細資訊,請參閱 Web 帳戶管理員

取得目前使用者的針對性供應項目

取得目前使用者的 MSA 權杖之後,請呼叫 https://manage.devcenter.microsoft.com/v2.0/my/storeoffers/user URI 的 GET 方法,以取得目前使用者可用的針對性供應項目。 如需此 REST 方法的詳細資訊,請參閱取得針對性供應項目

這個方法會傳回與目前使用者可用之針對性供應項目相關聯的附加元件產品識別碼。 透過這項資訊,您可以將一或多個針對性供應項目作為應用程式內購買提供給使用者。

下列範例示範如何取得目前使用者可用的針對性供應項目。 此範例是完整範例的摘錄。 它需要 Newtonsoft 和其他類別的 Json.NET 程式庫,以及使用完整範例中提供的陳述式。

private async Task<List<TargetedOfferData>> GetTargetedOffersForUserAsync(string msaToken)
{
    if (string.IsNullOrEmpty(msaToken))
    {
        System.Diagnostics.Debug.WriteLine("Microsoft Account token is null or empty.");
        return null;
    }

    HttpClient httpClientGetOffers = new HttpClient();
    httpClientGetOffers.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", msaToken);
    List<TargetedOfferData> availableOfferData = null;

    try
    {
        string getOffersResponse = await httpClientGetOffers.GetStringAsync(new Uri(storeOffersUri));
        availableOfferData = 
            Newtonsoft.Json.JsonConvert.DeserializeObject<List<TargetedOfferData>>(getOffersResponse);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.Message);
    }

    return availableOfferData;
}

完整程式碼範例

下列程式碼範例會示範下列工作:

  • 取得目前使用者的 MSA 權杖。
  • 使用取得針對性供應項目方法,取得目前使用者的所有針對性供應項目。
  • 購買與針對性供應項目相關聯的附加元件。

此範例需要 Newtonsoft 的 Json.NET 程式庫。 此範例會使用此程式庫來序列化及還原序列化 JSON 格式化的資料。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Windows.Services.Store;
using Windows.Security.Authentication.Web.Core;

namespace DocumenationExamples
{
    public class TargetedOffersExample
    {
        private const string storeOffersUri = "https://manage.devcenter.microsoft.com/v2.0/my/storeoffers/user";
        private const string jsonMediaType = "application/json";
        private static string[] productKinds = { "Durable", "Consumable", "UnmanagedConsumable" };
        private static StoreContext storeContext = StoreContext.GetDefault();

        public async void DemonstrateTargetedOffers()
        {
            // Get the Microsoft Account token for the current user.
            string msaToken = await GetMicrosoftAccountTokenAsync();

            if (string.IsNullOrEmpty(msaToken))
            {
                System.Diagnostics.Debug.WriteLine("Microsoft Account token could not be retrieved.");
                return;
            }

            // Get the targeted Store offers for the current user.
            List<TargetedOfferData> availableOfferData =
                await GetTargetedOffersForUserAsync(msaToken);

            if (availableOfferData == null || availableOfferData.Count == 0)
            {
                System.Diagnostics.Debug.WriteLine("There was an error retrieving targeted offers," +
                    "or there are no targeted offers available for the current user.");
                return;
            }

            // Get the product ID of the add-on that is associated with the first available offer
            // in the response data.
            TargetedOfferData offerData = availableOfferData[0];
            string productId = offerData.Offers[0];

            // Get the Store ID of the add-on that has the matching product ID, and then purchase the add-on.
            List<String> filterList = new List<string>(productKinds);
            StoreProductQueryResult queryResult = await storeContext.GetAssociatedStoreProductsAsync(filterList);
            foreach (KeyValuePair<string, StoreProduct> result in queryResult.Products)
            {
                if (result.Value.InAppOfferToken == productId)
                {
                    await PurchaseOfferAsync(result.Value.StoreId);
                    return;
                }
            }

            System.Diagnostics.Debug.WriteLine("No add-on with the specified product ID could be found " +
                "for the current app.");
            return;
        }

        private async Task<string> GetMicrosoftAccountTokenAsync()
        {
            var msaProvider = await WebAuthenticationCoreManager.FindAccountProviderAsync(
                "https://login.microsoft.com", "consumers");

            WebTokenRequest request = new WebTokenRequest(msaProvider, "devcenter_implicit.basic,wl.basic");
            WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);

            if (result.ResponseStatus == WebTokenRequestStatus.Success)
            {
                return result.ResponseData[0].Token;
            }
            else
            {
                return string.Empty;
            }
        }

        private async Task<List<TargetedOfferData>> GetTargetedOffersForUserAsync(string msaToken)
        {
            if (string.IsNullOrEmpty(msaToken))
            {
                System.Diagnostics.Debug.WriteLine("Microsoft Account token is null or empty.");
                return null;
            }

            HttpClient httpClientGetOffers = new HttpClient();
            httpClientGetOffers.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", msaToken);
            List<TargetedOfferData> availableOfferData = null;

            try
            {
                string getOffersResponse = await httpClientGetOffers.GetStringAsync(new Uri(storeOffersUri));
                availableOfferData = 
                    Newtonsoft.Json.JsonConvert.DeserializeObject<List<TargetedOfferData>>(getOffersResponse);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }

            return availableOfferData;
        }

        private async Task PurchaseOfferAsync(string storeId)
        {
            if (string.IsNullOrEmpty(storeId))
            {
                System.Diagnostics.Debug.WriteLine("storeId is null or empty.");
                return;
            }

            // Purchase the add-on for the current user. Typically, a game or app would first show
            // a UI that prompts the user to buy the add-on; for simplicity, this example
            // simply purchases the add-on.
            StorePurchaseResult result = await storeContext.RequestPurchaseAsync(storeId);

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

            switch (result.Status)
            {
                case StorePurchaseStatus.AlreadyPurchased:
                    System.Diagnostics.Debug.WriteLine("The user has already purchased the product.");
                    break;

                case StorePurchaseStatus.Succeeded:
                    System.Diagnostics.Debug.WriteLine("The purchase was successful.");
                    break;

                case StorePurchaseStatus.NotPurchased:
                    System.Diagnostics.Debug.WriteLine("The purchase did not complete. " +
                        "The user may have cancelled the purchase. ExtendedError: " + extendedError);
                    break;

                case StorePurchaseStatus.NetworkError:
                    System.Diagnostics.Debug.WriteLine("The purchase was unsuccessful due to a network error. " +
                        "ExtendedError: " + extendedError);
                    break;

                case StorePurchaseStatus.ServerError:
                    System.Diagnostics.Debug.WriteLine("The purchase was unsuccessful due to a server error. " +
                        "ExtendedError: " + extendedError);
                    break;

                default:
                    System.Diagnostics.Debug.WriteLine("The purchase was unsuccessful due to an unknown error. " +
                        "ExtendedError: " + extendedError);
                    break;
            }
        }
    }

    public class TargetedOfferData
    {
        [JsonProperty(PropertyName = "offers")]
        public IList<string> Offers { get; } = new List<string>();

        [JsonProperty(PropertyName = "trackingId")]
        public string TrackingId { get; set; }
    }
}