Store 서비스를 사용하여 대상 제품 관리하기
파트너 센터에서, 앱의 참여 > 대상 제품 페이지에서 대상 제품을 만들 때 앱 코드에서 Microsoft Store 대상 제품 API를 사용하여 대상 제품에 대한 앱 내 환경을 구현하는 데 도움이 되는 정보를 검색합니다. 대상 제품 및 대시보드에서 대상 제품을 만드는 방법에 대한 자세한 내용은 대상 제품을 사용하여 참여 및 변환 최대화를 참조하세요.
대상 제품 API는 사용자가 대상 제품의 고객 세그먼트에 포함되는지 여부에 따라 현재 사용자에게 제공되는 대상 제품을 가져오는 데 사용할 수 있는 간단한 REST API입니다. 이 API를 앱 코드에 사용하려면 다음 단계를 따릅니다.
- 현재 앱에 로그인한 사용자의 Microsoft 계정 토큰을 가져옵니다.
- 현재 사용자의 대상 제품을 가져옵니다.
- 대상 제품 중 하나와 연결된 추가 기능에 대한 앱에서 바로 구매 환경을 구현합니다. 앱에서 바로 구매를 구현하는 데 대한 자세한 내용은 이 문서를 참조하세요.
이러한 모든 단계를 보여 주는 완전한 코드 예제는 이 문서의 끝 부분에 있는 코드 예제를 참조합니다. 다음 섹션에서는 이러한 각 단계에 대한 자세한 내용을 제공합니다.
현재 사용자의 Microsoft 계정 토큰 가져오기
앱의 코드에서 현재 로그인한 사용자의 MSA(Microsoft 계정) 토큰을 가져옵니다. Microsoft Store 대상 제품 API의 Authorization
요청 헤더에 이 토큰을 전달해야 합니다. 이 토큰은 Microsoft Store에서 현재 사용자에게 제공되는 대상 제품을 검색하는 데 사용됩니다.
MSA 토큰을 가져오려면 WebAuthenticationCoreManager 클래스를 사용하여 devcenter_implicit.basic,wl.basic
범위를 사용하는 토큰을 요청합니다. 다음 예제에서는 이 작업을 수행하는 방법을 보여 줍니다. 완전한 예제에서 발췌한 예제입니다. 완전한 예제에서 제공되는 using 문이 필요합니다.
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 토큰을 가져오는 방법에 대한 자세한 내용은 웹 계정 관리자를 참조하세요.
현재 사용자의 대상 제품 가져오기
현재 사용자의 MSA 토큰을 확보한 후에는 https://manage.devcenter.microsoft.com/v2.0/my/storeoffers/user
URI의 GET 메서드를 호출하여 현재 사용자에게 제공되는 대상 제품을 가져옵니다. 이 REST 메서드에 대한 자세한 내용은 대상 제품 가져오기를 참조하세요.
이 메서드는 현재 사용자에게 제공되는 대상 제품과 연결된 추가 기능의 제품 ID를 반환합니다. 이 정보를 사용하여 사용자에게 하나 이상의 대상 제품을 앱에서 바로 구매로 제공할 수 있습니다.
다음 예제는 현재 사용자에게 대상 제품을 제시하는 방법을 보여 줍니다. 이 예제는 완전한 예제에서 발췌했습니다. Newtonsoft의 Json.NET 라이브러리와 추가 클래스, 완전한 예제에서 제공되는 using 문이 필요합니다.
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 토큰을 가져옵니다.
- Get targeted offers 메서드를 사용하여 현재 사용자에게 제공되는 대상 제품을 모두 가져옵니다.
- 대상 제품과 연결된 추가 기능을 구매합니다.
이 예제는 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; }
}
}