为应用启用订阅加载项Enable subscription add-ons for your app

通用 Windows 平台 (UWP) 应用可以向客户提供订阅加载项的应用内购买。Your Universal Windows Platform (UWP) app can offer in-app purchases of subscription add-ons to your customers. 你可以按照自动定期帐单期间间使用订阅在你的应用中销售数字产品(如应用功能或数字内容)。You can use subscriptions to sell digital products in your app (such as app features or digital content) with automated recurring billing periods.

备注

若要支持应用内的订阅加载项购买,你的应用必须在 Visual Studio 中面向 Windows 10 周年纪念版(10.0;版本 14393) 或更高版本(这对应于 Windows 10 版本 1607),并且必须使用 Windows.Services.Store 命名空间(而不是 Windows.ApplicationModel.Store 命名空间)中的 API 来实现应用内购买体验。To enable the purchase of subscription add-ons in your app, your project must target Windows 10 Anniversary Edition (10.0; Build 14393) or a later release in Visual Studio (this corresponds to Windows 10, version 1607), and it must use the APIs in the Windows.Services.Store namespace to implement the in-app purchase experience instead of the Windows.ApplicationModel.Store namespace. 有关这些命名空间之间的差异的详细信息,请参阅应用内购买和试用For more information about the differences between these namespaces, see In-app purchases and trials.

功能要点Feature highlights

UWP 应用的订阅加载项支持以下功能:Subscription add-ons for UWP apps support the following features:

  • 你可以选择订阅期为 1 个月、3 个月、6 个月、1 年或 2 年。You can choose from subscription periods of 1 month, 3 months, 6 months, 1 year, or 2 years.
  • 你可以在你的订阅中添加 1 周或 1 个月的免费试用期间。You can add free trial periods of 1 week or 1 month to your subscription.
  • Windows SDK 提供了一些 API,可用于在应用中获取有关应用的可用订阅加载项的信息并支持购买订阅加载项。The Windows SDK provides APIs you can use in your app to get info about available subscription add-ons for the app and enable the purchase of a subscription add-on. 我们还提供你可以从你的服务调用的 REST API 来管理用户订阅We also provide REST APIs you can call from your services to manage subscriptions for a user.
  • 你可以查看分析报告,其中提供了订阅购置、活动订户以及在指定的时间段内取消的订阅的数量。You can view analytic reports that provide the number of subscription acquisitions, active subscribers, and canceled subscriptions in a given time period.
  • 客户可以在他们的 Microsoft 帐户的 http://account.microsoft.com/services 页面管理他们的订阅。Customers can manage their subscription on the http://account.microsoft.com/services page for their Microsoft account. 客户可以使用此页面查看他们购买的所有订阅、取消订阅,以及更改与其订阅关联的付款方式。Customers can use this page to view all of the subscriptions they have acquired, cancel a subscription, and change the form of payment that is associated with their subscription.

为你的应用启用订阅加载项的步骤Steps to enable a subscription add-on for your app

若要在你的应用中支持购买订阅加载项,请执行以下步骤。To enable the purchase of subscription add-ons in your app, follow these steps.

  1. 在开发人员中心仪表板中为你的订阅创建加载项提交,并发布此提交。Create an add-on submission for your subscription in the Dev Center dashboard and publish the submission. 在你执行加载项提交流程时,请密切注意以下属性:As you follow the add-on submission process, pay close attention to the following properties:

    • 产品类型:确保选择订阅Product type: Make sure you select Subscription.

    • 订阅期:为你的订阅选择定期帐单期间。Subscription period: Choose the recurring billing period for your subscription. 在发布加载项之后,你将不能更改订阅期。You cannot change the subscription period after you publish your add-on.

      每个订阅加载项都支持单个订阅期和试用期。Each subscription add-on supports a single subscription period and trial period. 你必须在应用中为你想要提供的每种订阅创建不同的订阅加载项。You must create a different subscription add-on for each type of subscription you want to offer in your app. 例如,如果你想要提供按月订阅无试用、按月订阅送一个月试用、按年订阅无试用以及按年订阅送一个月试用,则需要创建四个订阅加载项。For example, if you wanted to offer a monthly subscription with no trial, a monthly subscription with a one-month trial, an annual subscription with no trial, and an annual subscription with a one-month trial, you would need to create four subscription add-ons.

    • 试用期间:考虑为你的订阅选择 1 周或 1 个月的试用期,让用户可以在购买之前先试用。Trial period: Consider choosing a 1 week or 1 month trial period for your subscription to enable users to try your subscription content before they buy it. 在发布订阅加载项之后,你将不能更改或删除试用期。You cannot change or remove the trial period after you publish your subscription add-on.

      要免费试用你的订阅,用户必须通过标准的应用内购买流程(包括有效的付款方式)购买你的订阅。To acquire a free trial of your subscription, a user must purchase your subscription through the standard in-app purchase process, including a valid form of payment. 在试用期内不收取任何费用。They are not charged any money during the trial period. 在试用期结束时,订阅自动将转换为完全订阅,并将按用户的支付方式收取第一期的付费订阅费用。At the end of the trial period, the subscription automatically converts to the full subscription and the user's payment instrument will be charged for the first period of the paid subscription. 如果用户在试用期内选择取消订阅,则订阅在试用期结束之前仍然会保持有效。If the user chooses to cancel their subscription during the trial period, the subscription remains active until the end of the trial period. 一些试用期并非对所有订阅期都可用。Some trial periods are not available for all subscription periods.

      备注

      每位客户一次只能获取一个订阅加载项的免费试用版。Each customer can acquire a free trial for a subscription add-on only one time. 客户获得某项订阅的免费试用版后,Microsoft Store 将阻止该客户再次获取相同的免费试用订阅。After a customer acquires a free trial for a subscription, the Store prevents the same customer from ever acquiring the same free trial subscription again.

    • 可见性:如果要创建测试加载项并且仅用它来测试订阅的应用内购买体验,建议你选择一个在 Microsoft Store 中隐藏选项。Visibility: If you are creating a test add-on that you will only use to test the in-app purchase experience for your subscription, we recommend that you select one of the Hidden in the Store options. 否则,你可以选择最适合你的情形的可见性选项。Otherwise, you can select the best visibility option for your scenario.

    • 定价:在此部分中选择你的订阅的价格。Pricing: Choose the price of your subscription in this section. 在发布加载项之后,你将不能提高订阅价格。You cannot raise the price of the subscription after you publish the add-on. 不过,可以在以后降价。However, you can lower the price later.

      重要

      默认情况下,当你创建任何加载项时,价格最初都设置为免费By default, when you create any add-on the price is initially set to Free. 因为你在完成加载项提交之后不能提高订阅加载项的价格,请确保在此处选择你的订阅的价格。Because you cannot raise the price of a subscription add-on after you complete the add-on submission, be sure to choose the price of your subscription here.

  2. 在你的应用中,使用 Windows.Services.Store 命名空间中的 API 来确定当前用户是否已获取你的订阅加载项,然后以应用内购买的形式将它提供给用户。In your app, use APIs in the Windows.Services.Store namespace to determine whether the current user has already acquired your subscription add-on and then offer it for sale to the user as an in-app purchase. 请参阅本文中的代码示例以了解更多详细信息。See the code examples in this article for more details.

  3. 测试你的应用中订阅的应用内购买实现情况。Test the in-app purchase implementation of your subscription in your app. 你需要将你的应用从应用商店下载到你的开发设备,才能使用其许可证进行测试。You'll need to download your app once from the Store to your development device to use its license for testing. 有关详细信息,请参阅我们的应用内购买测试指南For more information, see our testing guidance for in-app purchases.

  4. 创建并发布应用提交,并使之包含你已更新的应用包(包括你已测试的代码)。Create and publish an app submission that includes your updated app package, including your tested code. 有关详细信息,请参阅应用提交For more information, see App submissions.

代码示例Code examples

此部分中的代码示例介绍如何使用 Windows.Services.Store 命名空间中的 API 来获取有关当前应用的订阅加载项的信息,以及代表当前用户请求购买订阅加载项。The code examples in this section demonstrate how to use the APIs in the Windows.Services.Store namespace to get info about subscription add-ons for the current app and request the purchase a subscription add-on on behalf of the current user.

这些示例有以下先决条件:These examples have the following prerequisites:

  • 适用于面向 Windows 10 周年纪念版(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. 在测试应用期间,你可以选择将应用配置为在应用商店中隐藏。You can optionally configure the app so it is not discoverable in the Store while you test it. 有关详细信息,请参阅测试指南For more information, see the testing guidance.
  • 你已经在开发人员中心仪表板中为该应用创建了一个订阅加载项You have created a subscription add-on for the app in the Dev Center dashboard.

这些示例中的代码假设:The code in these examples assumes:

  • 此代码文件包含对 Windows.Services.StoreSystem.Threading.Tasks 命名空间的 using 语句。The code file has using statements for the Windows.Services.Store and System.Threading.Tasks namespaces.
  • 该应用是单用户应用,仅在启动该应用的用户上下文中运行。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.

备注

如果你有使用桌面桥的桌面应用程序,可能需要添加未在这些示例中显示的额外代码来配置 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.

购买订阅加载项Purchase a subscription add-on

此示例演示如何代表当前客户请求购买已知订阅加载项。This example demonstrates how to request the purchase of a known subscription add-on for your app on behalf of the current customer. 此示例还显示如何处理订阅有试用期的情况。This example also shows how to handle the case where the subscription has a trial period.

  1. 这段代码首先确定客户是否已经拥有一个活动订阅许可证。The code first determines whether the customer already has an active license for the subscription. 如果客户已经有活动的许可证,则你的代码应根据需要解锁订阅功能(因为它专用于你的应用,这在示例中已用注释指明)。If the customer already has an active license, your code should unlock the subscription features as necessary (because this is proprietary to your app, this is identified with a comment in the example).
  2. 接下来,这段代码获取表示你想要代表客户购买的订阅的 StoreProduct 对象。Next, the code gets the StoreProduct object that represents the subscription you want to purchase on behalf of the customer. 代码假定你已知道你想要购买的订阅的 Store ID,并且你已对 subscriptionStoreId 变量指定此值。The code assumes that you already know the Store ID of the subscription add-on you want to purchase, and that you have assigned this value to the subscriptionStoreId variable.
  3. 然后代码确定该订阅是否有试用版。The code then determines whether a trial is available for the subscription. (可选)你的应用可以使用此信息向客户显示详情,说明存在可用的试用版或完整订阅。Optionally, your app can use this information to display details about the available trial or full subscription to the customer.
  4. 最后,代码调用 RequestPurchaseAsync 方法来请求购买订阅。Finally, the code calls RequestPurchaseAsync method to request the purchase of the subscription. 如果该订阅有试用版,则会向客户提供试用版以便购买。If a trial is available for the subscription, the trial will be offered to the customer for purchase. 否则,将提供完整订阅以便其购买。Otherwise, the full subscription will be offered for purchase.
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;
    }
}

获取有关当前应用的订阅加载项的信息Get info about subscription add-ons for the current app

此代码示例介绍如何获取有关可用于你的应用的所有订阅加载项的信息。This code example demonstrates how to get info for all the subscription add-ons that are available in your app. 要获取此信息,请先使用 GetAssociatedStoreProductsAsync 方法来获取表示应用提供的每个可用加载项的 StoreProduct 对象的集合。To get this info, first use the GetAssociatedStoreProductsAsync method to get the collection of StoreProduct objects that represent each of the available add-ons for the app. 然后,获取每个产品的 StoreSku,并使用 IsSubscriptionSubscriptionInfo 属性访问订阅信息。Then, get the StoreSku for each product and use the IsSubscription and SubscriptionInfo properties to access the subscription info.

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

从你的服务管理订阅Manage subscriptions from your services

在你更新过的应用在应用商店中发布且客户可以购买你的订阅加载项之后,你可能会遇到需要管理某个客户的订阅的情况。After your updated app is in the Store and customers can buy your subscription add-on, you may have scenarios where you need to manage the subscription for a customer. 我们提供了你可以从你的服务中调用的 REST API 来执行以下订阅管理任务:We provide REST APIs you can call from your services to perform the following subscription management tasks:

  • 获取用户有权使用的订阅Get the subscriptions that a user has an entitlement to use. 如果你的订阅是跨平台服务的一部分,则可以调用此 API 来确定指定的用户对于你的订阅是否拥有授权以及他们的订阅在你的 UWP 应用的上下文中的状态。If your subscription is part of a cross-platform service, you can call this API to determine whether the specified user has an entitlement for your subscription and the status of their subscription in the context of your UWP app. 然后,你可以使用此信息来更新你的服务支持的其他平台上的订阅状态。You can then use this information to update the status of the subscription on other platforms that your service supports.

  • 更改给定用户订阅的计费状态.Change the billing state of a subscription for a given user. 使用此 API 可取消、延长或禁用订阅的自动续订。Use this API to cancel, extend, or disable automatic renewal for a subscription.

取消Cancellations

客户可以使用其 Microsoft 帐户的 http://account.microsoft.com/services 页面查看他们购买的所有订阅、取消订阅,以及更改与其订阅关联的付款方式。Customers can use the http://account.microsoft.com/services page for their Microsoft account to view all of the subscriptions they have acquired, cancel a subscription, and change the form of payment that is associated with their subscription. 当客户使用此页面取消订阅时,他们在当前帐单期间内将仍然拥有对该订阅的访问权限。When a customer cancels a subscription using this page, they continue to have access to the subscription for the duration of the current billing period. 他们不能获得当前帐单周期任何部分的退款。They do not get a refund for any part of the current billing period. 在当前帐单周期结束时,他们的订阅会停止。At the end of the current billing period, their subscription is deactivated.

你还可以使用我们的 REST API 更改给定用户的订阅的帐单状态,以代表用户取消订阅。You can also cancel a subscription on behalf of a user by using our REST API to change the billing state of a subscription for a given user.

订阅续订和宽限期Subscription renewals and grace periods

在每个计费周期内的某个时间点,我们将尝试向客户的信用卡收取下一个计费周期的费用。At some point during each billing period, we will attempt to charge the customer's credit card for the next billing period. 如果收费失败,客户的订阅将进入催缴状态。If the charge fails, the customer's subscription enters the dunning state. 这意味着他们的订阅在当前计费周期剩余时间内仍然保持活动状态,但是我们将定期尝试向其信用卡收费以便自动续订订阅。This means that their subscription is still active for the remainder of the current billing period, but we will periodically try to charge their credit card to automatically renew the subscription. 这种状态最多可以持续两周,直到当前计费周期结束和下一个帐单期间的续订日期。This state can last up to two weeks, until the end of the current billing period and the renew date for the next billing period.

对于订阅帐单,我们不提供宽限期。We do not offer grace periods for subscription billing. 如果在当前计费周期结束时我们都无法对客户的信用卡收费,订阅将取消,在当前计费周期结束后,客户将不再能够访问订阅。If we are unable to successfully charge the customer's credit card by the end of the current billing period, the subscription will be canceled and the customer will no longer have access to the subscription after the current billing period.

不受支持的情形Unsupported scenarios

目前订阅加载项不支持以下情形。The following scenarios are not currently supported for subscription add-ons.

  • 目前不支持直接通过应用商店向客户销售订阅。Selling subscriptions to customers directly via the Store is not supported at this time. 订阅只能通过数字产品的应用内购买提供。Subscriptions are available for in-app purchases of digital products only.
  • 客户不能使用他们的 Microsoft 帐户的 http://account.microsoft.com/services 页面切换到不同订阅期。Customers cannot switch subscription periods using the http://account.microsoft.com/services page for their Microsoft account. 若要切换到不同订阅期,客户必须取消其当前的订阅,然后从你的应用中购买具有订阅期不同的订阅。To switch to a different subscription period, customers much cancel their current subscription and then purchase a subscription with a different subscription period from your app.
  • 订阅加载项目前不支持分级订阅(例如,将客户从基本订阅切换到包含更多功能的高级订阅)。Tier switching is currently not supported for subscription add-ons (for example, switching a customer from a basic subscription to a premium subscription with more features).
  • 目前订阅加载项不支持销售促销代码Sales and promotional codes are currently not supported for subscription add-ons.