Включение надстроек с подпиской для приложения

Ваше приложение универсальной платформы Windows (UWP) может предлагать покупки из приложения для надстроек с подпиской своим пользователям. Подписки можно использовать для продажи цифровых продуктов в приложении (например, функций приложения или цифрового содержимого) с автоматическим периодическим выставлением счетов.

Примечание

Чтобы включить покупку надстроек с подпиской в приложении, ваш проект должен иметь в качестве целевой версии Windows 10 Anniversary Edition (10.0; сборка 14393) или более поздний выпуска в Visual Studio (это соответствует Windows 10 версии 1607), и он должен использовать API-интерфейсы в пространстве имен Windows.Services.Store для реализации возможности покупки из приложения вместо пространства имен Windows.ApplicationModel.Store. Дополнительные сведения о различиях между этими пространствами имен см. в разделе Покупки из приложения и пробные версии.

Краткие сведения о возможностях

Надстройки с подпиской для приложений UWP поддерживают следующие возможности.

  • Вы можете выбрать следующие варианты длительности подписки: 1 месяц, 3 месяца, 6 месяцев, 1 год или 2 года.
  • Можно добавить в подписку бесплатные пробные периоды длительностью 1 неделя или 1 месяц.
  • Windows SDK предоставляет API-интерфейсы, которые можно использовать в приложении, чтобы получить сведения о доступных надстройках с подпиской для приложения и включить покупку надстроек с подпиской. Мы также предоставляем API-интерфейсы REST, которые можно вызывать из своих служб для управления подписками пользователя.
  • Можно просмотреть аналитические отчеты, содержащие количество покупок подписки, активных подписчиков и отмененных подписок за определенный период времени.
  • Пользователи могут управлять своей подпиской на странице https://account.microsoft.com/services своей учетной записи Майкрософт. Пользователи могут использовать эту страницу для просмотра всех приобретенных подписок, отмены подписки и изменения способа оплаты, связанного с подпиской.

Действия для включения надстроек с подпиской для приложения

Чтобы обеспечить возможность покупки надстройки с подпиской в приложении, выполните следующие действия.

  1. Создайте отправку надстройки для подписки в Центре партнеров и опубликуйте отправку. При выполнении процесса отправки надстройки обратите особое внимание на следующие свойства.

    • Тип продукта: обязательно выберите Подписка.

    • Период подписки: выберите периодичность выставления счетов по вашей подписке. Изменить периодичность подписки после публикации надстройки невозможно.

      Каждая надстройка с подпиской поддерживает один вариант периода подписки и пробного периода. Необходимо создать различные надстройки с подпиской для каждого типа подписки, который вы собираетесь предлагать в своем приложении. Например, если вы хотите предложить месячную подписку без пробного периода, месячную подписку с пробным периодом в один месяц, годовую подписку без пробного периода и годовую подписку с пробным периодом в один месяц, вам потребуется создать четыре разных надстройки с подпиской.

    • Пробный период: выберите длительность пробного периода подписки в 1 неделю или 1 месяц, чтобы пользователи могли попробовать предлагаемое по подписке содержимое, прежде чем приобрести его. Изменить или удалить пробный период после публикации надстройки с подпиской невозможно.

      Чтобы получить бесплатную пробную версию подписки, пользователю необходимо приобрести вашу подписку путем стандартной процедуры покупки из приложения, также указав допустимый способ оплаты. В течение пробного периода денежные средства с пользователей не взымаются. По окончании пробного периода подписка автоматически преобразуется в полную подписку, и указанное пользователем платежное средство используется для оплаты за первый период платной подписки. Если пользователь решит отменить подписку в течение пробного периода, подписка останется активной до окончания пробного периода. Некоторые варианты пробного периода недоступны для всех периодов подписки.

      Примечание

      Каждый клиент может получить бесплатную пробную подписку на надстройку только один раз. Если клиент получает бесплатную пробную подписку, Store запрещает тому же пользователю снова приобрести такую же бесплатную пробную подписку.

    • Видимость: если вы создаете тестовую надстройку, которую будете использовать только для тестирования функции покупки из приложения, рекомендуется выбрать один из вариантов Скрыто в Store. В противном случае можно выбрать оптимальную для вашего сценария видимость.

    • Цена: выберите стоимость вашей подписки в этом разделе. Повысить стоимость подписки после публикации надстройки невозможно. Однако можно в дальнейшем снизить стоимость.

      Важно!

      По умолчанию при создании любой надстройки цене изначально устанавливается значение Бесплатно. Поскольку повысить цену надстройки с подпиской после завершения отправки надстройки невозможно, не забудьте выбрать здесь стоимость вашей подписки.

  2. В приложении используйте API-интерфейсы в пространстве имен Windows.Services.Store, чтобы определить, приобрел ли текущий пользователь вашу надстройку с подпиской, и затем предложить ее пользователю в качестве покупки из приложения. В разделе примеры кода этой статьи приводятся дополнительные сведения.

  3. Протестируйте реализацию покупок из приложения для подписки в приложении. Вам потребуется один раз скачать свое приложение из Магазина на свое устройство разработки, чтобы использовать его лицензию для тестирования. Дополнительные сведения по покупкам из приложения см. в руководстве по тестированию.

  4. Создайте и опубликуйте отправку приложения, которая включает в себя обновленный пакет приложения, включая тестируемый код. Более подробные сведения см. в разделе Отправки приложений.

Примеры кода

В примерах кода в этом разделе показано, как использовать API-интерфейсы в пространстве имен Windows.Services.Store для получения сведений о надстройках с подпиской для текущего приложения и запроса покупки надстройки с подпиской от имени текущего пользователя.

Для этих примеров необходимо выполнение следующих предварительных условий.

В коде из этих примеров предполагается следующее.

  • В файле кода используются операторы using для пространств имен Windows.Services.Store и System.Threading.Tasks.
  • Приложение — однопользовательское и выполняется только в контексте пользователя, запустившего его. Подробнее см. в разделе Покупки из приложения и пробные версии.

Примечание

Если у вас есть классическое приложение, которое использует мост для классических приложений, вам может потребоваться добавить дополнительный код, не показанный в этих примерах, для настройки объекта StoreContext. Дополнительные сведения см. в разделе Использование класса StoreContext в классическом приложении, в котором применяется мост для классических приложений.

Покупка надстройки с подпиской

В этом примере показано, как запросить приобретение известной подписки на надстройку для вашего приложения от имени текущего пользователя. В этом примере также показано, как обрабатывать ситуации, в которых у подписки есть пробный период.

  1. Код сначала определяет, есть ли у клиента уже активная лицензия для подписки. Если у клиента уже есть активная лицензия, ваш код должен разблокировать возможности подписки согласно необходимости (так как это уникально в каждом приложении, этот фрагмент обозначен в примере комментарием).
  2. Затем код получает объект StoreProduct, представляющий подписку, которую требуется приобрести от имени пользователя. Предполагается, что вы уже знаете код продукта в Store для подписки на надстройку, которую требуется приобрести, и уже присвоили это значение переменной subscriptionStoreId.
  3. Затем код определяет, доступна ли пробная версия подписки. Кроме того ваше приложение может использовать эти сведения для отображения информации о доступной пробной версии или полной подписке для пользователя.
  4. Наконец, код вызывает метод 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;
            }
        }
    }
}

Управление подписками из ваших служб

После того как ваше обновленное приложение появится в Магазине и пользователи смогут покупать надстройку с подпиской, возможно, возникнут ситуации, в которых вам потребуется управлять подпиской пользователя. Мы предоставляем API-интерфейсы REST, которые можно вызывать из ваших служб для выполнения следующих задач по управления подпиской.

Отмены

Пользователи могут использовать страницу https://account.microsoft.com/services в учетной записи Майкрософт для просмотра всех приобретенных подписок, отмены подписки и изменения способа оплаты, связанного с подпиской. Если пользователь отменяет подписку с помощью этой страницы, он по-прежнему имеет доступ к этой подписке в течение текущего периода выставления счетов. Он не получает возврат денежных средств за какую-либо часть текущего периода выставления счетов. В конце текущего периода выставления счетов подписка будет отключена.

Также можно отменить подписку от имени пользователя с помощью нашего API-интерфейса REST для изменения состояния выставления счетов для данного пользователя.

Обновление подписки и периоды отсрочки

В определенный момент в каждом периоде выставления счетов мы попытаемся снять с кредитной карты клиента сумму за следующий период выставления счетов. В случае отказа подписка клиента переходит в состояние dunning. Это означает, что подписка по-прежнему активна в течение оставшейся части текущего периода выставления счетов, но мы будем периодически пытаться снять с кредитной карты соответствующую сумму для автоматического продления подписки. Это состояние может длиться до двух недель, пока не истечет текущий период выставления счетов и не наступит дата продления для следующего периода выставления счетов.

Мы не предлагаем периоды отсрочки при выставлении счетов по подпискам. Если нам не удается получить оплату с кредитной карты пользователя к окончанию текущего периода выставления счетов, подписка отменяется, и пользователь больше не имеет доступа к подписке после окончания текущего периода выставления счетов.

Неподдерживаемые сценарии

Следующие сценарии не поддерживаются для надстроек с подпиской.

  • В настоящее время не поддерживается продажа подписок пользователям напрямую в Магазине. Подписки доступны только для покупок цифровых продуктов из приложения.
  • Пользователи не могут менять периоды подписки на странице https://account.microsoft.com/services своей учетной записи Майкрософт. Чтобы переключиться на другой период подписки, клиенты должны отменить свою текущую подписку, а затем приобрести подписку с другим периодом подписки из вашего приложения.
  • Переключение уровней для надстроек с подпиской в настоящее время не поддерживается (например, переход с базовой подписки на подписку уровня Премиум с увеличенным числом функций).
  • Продажи и рекламные коды для надстроек с подпиской в настоящее время не поддерживаются.
  • Продление существующих подписок после настройки видимости надстройки подписки в значение Остановить приобретение. Дополнительные сведения см. в статье Настройка цен и доступности надстроек .