アプリのサブスクリプション アドオンの有効化
ユニバーサル Windows プラットフォーム (UWP) アプリでは、ユーザーにサブスクリプション アドオンのアプリ内購入を提供できます。 サブスクリプションを使用すると、自動の定期的な課金期間を設定してアプリ内でデジタル製品 (アプリの機能やデジタル コンテンツなど) を販売できます。
注意
アプリ内でサブスクリプション アドオンの購入を有効にするには、Visual Studio でプロジェクトが Windows 10 Anniversary Edition (10.0、ビルド 14393) またはそれ以降のリリース (これは、Windows 10 バージョン 1607 に対応) をターゲットにしている必要があります。また、Windows.ApplicationModel.Store 名前空間の代わりに、Windows.Services.Store 名前空間の API を使用して、アプリ内購入エクスペリエンスを実装している必要があります。 これらの名前空間の違いについて詳しくは、「アプリ内購入と試用版」をご覧ください。
機能概要
UWP アプリのサブスクリプション アドオンでは、次の機能をサポートします。
- サブスクリプション期間を 1 か月、3 か月、6 か月、1 年、または 2 年から選択できます。
- サブスクリプションに 1 週間または 1 か月の無料試用期間を追加できます。
- Windows SDK では、アプリで利用可能なサブスクリプション アドオンに関する情報を入手したり、サブスクリプション アドオンを購入できるようにしたりするためにアプリで利用できる API を提供しています。 また、サービスから呼び出してユーザーのサブスクリプションを管理できる REST API も提供しています。
- サブスクリプションの取得数、アクティブなサブスクリプション会員数、および特定の期間中に取り消されたサブスクリプション数を表示する分析レポートを確認できます。
- ユーザーは、自分の Microsoft アカウントの https://account.microsoft.com/services ページでサブスクリプションを管理できます。 ユーザーはこのページを使用して、取得したサブスクリプションすべての表示、サブスクリプションの取り消し、およびサブスクリプションに関連付けられた支払方法の変更ができます。
アプリのサブスクリプション アドオンを有効化する手順
アプリでサブスクリプション アドオンを購入できるようにするには、次の手順に従います。
パートナー センターでサブスクリプションのアドオンの申請を作成し、申請を発行します。 アドオンの申請プロセスに従い、次のプロパティをよく確認します。
製品の種類: [サブスクリプション]を選択していることを確認します。
サブスクリプション期間: サブスクリプションの定期的な課金期間を選択します。 アドオンの公開後にサブスクリプション期間を変更することはできません。
各サブスクリプション アドオンがサポートするのは、単一のサブスクリプション期間と試用期間だけです。 アプリで提供するサブスクリプションの種類ごとに異なるサブスクリプション アドオンを作成する必要があります。 たとえば、試用期間のない月間サブスクリプション、1 か月の試用期間のある月間サブスクリプション、試用期間のない年間サブスクリプション、1 か月の試用期間のある年間サブスクリプションを提供する場合、サブスクリプション アドオンを 4 つ作成する必要があります。
試用期間: ユーザーがサブスクリプション コンテンツを購入する前に試すことのできる期間を 1 週間にするか、1 か月にするかを選択することを検討します。 サブスクリプション アドオンの公開後に試用期間を変更または削除することはできません。
サブスクリプションの無料試用版を取得するには、ユーザーは有効な支払方法の設定も含めて標準のアプリ内購入プロセスに従って、サブスクリプションを購入する必要があります。 試用期間中に料金を請求されることはありません。 試用期間の終わりに、サブスクリプションは自動的に完全なサブスクリプションに変わり、有料サブスクリプションの最初の期間の料金がユーザーの支払方法に請求されます。 ユーザーが試用期間中にサブスクリプションを取り消した場合、試用期間が終わるまでサブスクリプションは有効のままです。 一部の試用期間は、すべてのサブスクリプション期間では利用できません。
注意
各ユーザーは、サブスクリプション アドオンの無料試用版を 1 回だけ取得できます。 ユーザーがサブスクリプションの無料試用版を取得したら、Microsoft Store では、同じユーザーが今後同じ無料試用版のサブスクリプションを取得しないようにします。
可視性: サブスクリプションのアプリ内購入エクスペリエンスのテストだけに使用するテスト用アドオンを作成している場合は、[ストアに表示しない] オプションのいずれかを選択することをお勧めします。 それ以外の場合は、シナリオに最適な可視化オプションを選択します。
価格: このセクションでサブスクリプションの価格を選択します。 アドオンの公開後にサブスクリプションの価格を上げることはできません。 ただし、後で価格を下げることはできます。
重要
アドオンの作成時、既定では、価格は最初 [無料] に設定されています。 サブスクリプション アドオンの申請の完了後にアドオンの価格を上げることはできないため、ここで必ずサブスクリプションの価格を選択してください。
アプリで Windows.Services.Store 名前空間の API を使用して、現在のユーザーが既にサブスクリプション アドオンを取得しているかどうかを確認し、そのユーザーにアドオンをアプリ内購入として販売するかどうかを決定します。 詳細については、この記事のコード サンプルを参照してください。
アプリで、サブスクリプションのアプリ内購入の実装をテストします。 ストアからアプリを開発用デバイスに 1 回ダウンロードして、そのライセンスをテストに使用する必要があります。 詳細については、アプリ内購入のテスト ガイダンスをご覧ください。
テストしたコードを含む更新したアプリ パッケージを含めたアプリの申請を作成して公開します。 詳しくは、「アプリの申請」をご覧ください。
コード例
このセクションのコード例では、Windows.Services.Store 名前空間の API を使用して現在のアプリのサブスクリプション アドオンに関する情報を取得する方法および現在のユーザーの代わりにサブスクリプション アドオンの購入を要求する方法を説明します。
これらの例には、次の前提条件があります。
- Windows 10 Anniversary Edition (10.0、ビルド 14393) 以降のリリースをターゲットとするユニバーサル Windows プラットフォーム (UWP) アプリの Visual Studio プロジェクト。
- パートナー センターでアプリの申請を作成し、このアプリが Microsoft Store で公開されている。 必要に応じで、テスト中にストアでアプリを検索できないようにアプリを構成することも可能です。 詳しくは、テスト ガイダンスをご覧ください。
- パートナー センターでこのアプリのサブスクリプション アドオンを作成してある。
これらの例のコードは、次の点を前提としています。
- コード ファイルに Windows.Services.Store 名前空間と System.Threading.Tasks 名前空間を使うための using ステートメントがある。
- アプリは、アプリを起動したユーザーのコンテキストでのみ動作するシングル ユーザー アプリです。 詳しくは、「アプリ内購入と試用版」をご覧ください。
注意
デスクトップ ブリッジを使用するデスクトップ アプリケーションがある場合、これらの例には示されていないコードを追加して StoreContext オブジェクトを構成することが必要になることがあります。 詳しくは、「デスクトップ ブリッジを使用するデスクトップ アプリケーションでの StoreContext クラスの使用」をご覧ください。
サブスクリプション アドオンの購入
この例では、現在のユーザーに代わって、アプリの既知のサブスクリプション アドオンの購入を要求する方法を示します。 この例は、サブスクリプションに試用期間がある場合の処理方法も示しています。
- コードではまず、ユーザーがサブスクリプションのアクティブなライセンスを既に持っているかどうかを確認します。 ユーザーがアクティブなラインセンスを既に持っている場合は、必要に応じてコードでサブスクリプション機能のロックを解除する必要があります (これはアプリに固有の処理なので、例ではコメントで示されています)。
- 次に、ユーザーに代わって購入するサブスクリプションを表す StoreProduct オブジェクトを取得します。 コードでは、購入するサブスクリプション アドオンの Store ID が既にわかっていて、その値が subscriptionStoreId 変数に割り当てられていると想定しています。
- コードは次に、サブスクリプションに試用期間があるかどうかを確認します。 アプリでは、必要に応じてこの情報を使って、利用可能な試用版サブスクリプションまたは製品版サブスクリプションの詳細をユーザーに表示することができます。
- 最後に、コードで RequestPurchaseAsync メソッドを呼び出して、サブスクリプションの購入を要求します。 サブスクリプションに試用版がある場合は、試用版がユーザーに提供されます。 それ以外の場合は、製品版のサブスクリプションが購入用に提供されます。
private StoreContext context = null;
StoreProduct subscriptionStoreProduct;
// Assign this variable to the Store ID of your subscription add-on.
private string subscriptionStoreId = "";
// This is the entry point method for the example.
public async Task SetupSubscriptionInfoAsync()
{
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.
}
bool userOwnsSubscription = await CheckIfUserHasSubscriptionAsync();
if (userOwnsSubscription)
{
// Unlock all the subscription add-on features here.
return;
}
// Get the StoreProduct that represents the subscription add-on.
subscriptionStoreProduct = await GetSubscriptionProductAsync();
if (subscriptionStoreProduct == null)
{
return;
}
// Check if the first SKU is a trial and notify the customer that a trial is available.
// If a trial is available, the Skus array will always have 2 purchasable SKUs and the
// first one is the trial. Otherwise, this array will only have one SKU.
StoreSku sku = subscriptionStoreProduct.Skus[0];
if (sku.SubscriptionInfo.HasTrialPeriod)
{
// You can display the subscription trial info to the customer here. You can use
// sku.SubscriptionInfo.TrialPeriod and sku.SubscriptionInfo.TrialPeriodUnit
// to get the trial details.
}
else
{
// You can display the subscription purchase info to the customer here. You can use
// sku.SubscriptionInfo.BillingPeriod and sku.SubscriptionInfo.BillingPeriodUnit
// to provide the renewal details.
}
// Prompt the customer to purchase the subscription.
await PromptUserToPurchaseAsync();
}
private async Task<bool> CheckIfUserHasSubscriptionAsync()
{
StoreAppLicense appLicense = await context.GetAppLicenseAsync();
// Check if the customer has the rights to the subscription.
foreach (var addOnLicense in appLicense.AddOnLicenses)
{
StoreLicense license = addOnLicense.Value;
if (license.SkuStoreId.StartsWith(subscriptionStoreId))
{
if (license.IsActive)
{
// The expiration date is available in the license.ExpirationDate property.
return true;
}
}
}
// The customer does not have a license to the subscription.
return false;
}
private async Task<StoreProduct> GetSubscriptionProductAsync()
{
// Load the sellable add-ons for this app and check if the trial is still
// available for this customer. If they previously acquired a trial they won't
// be able to get a trial again, and the StoreProduct.Skus property will
// only contain one SKU.
StoreProductQueryResult result =
await context.GetAssociatedStoreProductsAsync(new string[] { "Durable" });
if (result.ExtendedError != null)
{
System.Diagnostics.Debug.WriteLine("Something went wrong while getting the add-ons. " +
"ExtendedError:" + result.ExtendedError);
return null;
}
// Look for the product that represents the subscription.
foreach (var item in result.Products)
{
StoreProduct product = item.Value;
if (product.StoreId == subscriptionStoreId)
{
return product;
}
}
System.Diagnostics.Debug.WriteLine("The subscription was not found.");
return null;
}
private async Task PromptUserToPurchaseAsync()
{
// Request a purchase of the subscription product. If a trial is available it will be offered
// to the customer. Otherwise, the non-trial SKU will be offered.
StorePurchaseResult result = await subscriptionStoreProduct.RequestPurchaseAsync();
// 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 StorePurchaseStatus.Succeeded:
// Show a UI to acknowledge that the customer has purchased your subscription
// and unlock the features of the subscription.
break;
case StorePurchaseStatus.NotPurchased:
System.Diagnostics.Debug.WriteLine("The purchase did not complete. " +
"The customer may have cancelled the purchase. ExtendedError: " + extendedError);
break;
case StorePurchaseStatus.ServerError:
case StorePurchaseStatus.NetworkError:
System.Diagnostics.Debug.WriteLine("The purchase was unsuccessful due to a server or network error. " +
"ExtendedError: " + extendedError);
break;
case StorePurchaseStatus.AlreadyPurchased:
System.Diagnostics.Debug.WriteLine("The customer already owns this subscription." +
"ExtendedError: " + extendedError);
break;
}
}
現在のアプリのサブスクリプション アドオンの情報の取得
このコード例では、アプリで利用可能なすべてのサブスクリプション アドオンの情報を取得する方法を示しています。 この情報を取得するには、まず GetAssociatedStoreProductsAsync メソッドを使用して、アプリで利用可能なアドオンそれぞれを表す StoreProduct オブジェクトのコレクションを取得します。 次に、各製品の StoreSku を取得し、IsSubscription プロパティと SubscriptionInfo プロパティを使用してサブスクリプション情報にアクセスします。
private StoreContext context = null;
public async Task GetSubscriptionsInfo()
{
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.
}
// Subscription add-ons are Durable products.
string[] productKinds = { "Durable" };
List<String> filterList = new List<string>(productKinds);
StoreProductQueryResult queryResult =
await context.GetAssociatedStoreProductsAsync(productKinds);
if (queryResult.ExtendedError != null)
{
// The user may be offline or there might be some other server failure.
System.Diagnostics.Debug.WriteLine($"ExtendedError: {queryResult.ExtendedError.Message}");
return;
}
foreach (KeyValuePair<string, StoreProduct> item in queryResult.Products)
{
// Access the Store product info for the add-on.
StoreProduct product = item.Value;
// For each add-on, the subscription info is available in the SKU objects in the add-on.
foreach (StoreSku sku in product.Skus)
{
if (sku.IsSubscription)
{
// Use the sku.SubscriptionInfo property to get info about the subscription.
// For example, the following code gets the units and duration of the
// subscription billing period.
StoreDurationUnit billingPeriodUnit = sku.SubscriptionInfo.BillingPeriodUnit;
uint billingPeriod = sku.SubscriptionInfo.BillingPeriod;
}
}
}
}
サービスからのサブスクリプションの管理
更新したアプリがストアで公開され、ユーザーがサブスクリプション アドオンを購入できるようになったら、ユーザーのサブスクリプションの管理が必要になる可能性があります。 サービスから呼び出して次のサブスクリプション管理タスクを実行できる REST API が用意されています。
ユーザーが使う権利を持っているサブスクリプションを取得する。 サブスクリプションがクロスプラットフォーム サービスの一部である場合は、この API を呼び出して、指定のユーザーにサブスクリプションの権利があるかどうかや、UWP アプリのコンテキストにおけるサブスクリプションの状態を判断することができます。 その後、この情報を使用して、サービスでサポートしている他のプラットフォームにおけるサブスクリプションの状態を更新できます。
特定のユーザーのサブスクリプションに関する請求の状態を変更する。 この API を使用して、サブスクリプションの取り消し、延長、または自動更新の無効化を行えます。
取り消し
ユーザーは、Microsoft アカウントの https://account.microsoft.com/services ページを使って、取得したすべてのサブスクリプションの表示、サブスクリプションの取り消し、サブスクリプションに関連付けられている支払い方法の変更ができます。 ユーザーがこのページを使ってサブスクリプションを取り消した場合でも、現在の請求期間中はサブスクリプションを引き続き利用できます。 現在の請求期間に対する払い戻しは一切行われません。 現在の請求期間の終了時に、サブスクリプションが無効になります。
REST API を使用して、ユーザーの代わりにサブスクリプションを取り消して、特定のユーザーのサブスクリプションに関する請求の状態を変更することもできます。
サブスクリプションの更新と猶予期間
請求期間中のある時点で、ユーザーのクレジット カードに対して次の請求期間分の請求が試みられます。 この請求に失敗すると、ユーザーのサブスクリプションは催促中の状態になります。 つまり、現在の請求期間が終わるまでの間、サブスクリプションはアクティブですが、サブスクリプションを自動更新するためにクレジット カードへの請求が定期的に試みられます。 この状態は、現在の請求期間が終了して次の請求期間が更新される日まで、最大で 2 週間続く可能性があります。
サブスクリプションの請求に対する猶予期間は用意されていません。 現在の請求期間が終了するまでにユーザーのクレジット カードに請求できなかった場合、サブスクリプションは取り消され、現在の請求期間後にユーザーがサブスクリプションにアクセスすることはできなくなります。
サポートされていないシナリオ
次のシナリオは、サブスクリプション アドオンで現在サポートされていません。
- 現時点では、ストアを通じたユーザーへのサブスクリプションの直接販売はサポートされていません。 サブスクリプションはデジタル製品のアプリ内購入でのみ利用可能です。
- ユーザーが Microsoft アカウントの https://account.microsoft.com/services ページを使ってサブスクリプション期間を切り替えることはできません。 異なるサブスクリプション期間に切り替えるには、ユーザーは現在のサブスクリプションを取り消して、アプリで別のサブスクリプション期間のサブスクリプションを購入する必要があります。
- サブスクリプション アドオンでは現在、サブスクリプション レベルの切り替えはサポートされていません (たとえば、ユーザーをベーシック サブスクリプションから機能の多いプレミアム サブスクリプションに切り替えるなど)。
- サブスクリプション アドオンでは現在、セールとプロモーション コードはサポートされていません。
- サブスクリプション アドオンの可視性を [購入の停止] に設定した後の、既存のサブスクリプションの更新。 詳細については、「アドオンの価格と使用可能状況の設定」を参照してください。