Поддержка покупки продуктов из приложения

Предоставьте пользователям возможность покупки из приложения потребляемых внутренних продуктов приложения (товаров, которые можно покупать, использовать и покупать снова) через Магазин. Покупка из приложения — удобный и надежный способ приобрести товар. Это особенно удобно при покупке виртуальной валюты для игр (золота, монет и др.), которую можно потом использовать в процессе игры.

Важно!

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

Предварительные требования

  • В этом разделе рассказывается о покупках потребляемых внутренних продуктов приложения и отчетах об исполнении сделок в ваших приложениях. Чтобы ознакомиться с продуктами из приложения, см. статью Поддержка покупок продуктов из приложения, из которой вы узнаете о лицензировании и о том, как правильно вносить продукты из приложения в список Магазина.
  • Когда вы создадите код для продаж внутренних продуктов приложения и будете проверять его в первый раз, используйте объект CurrentAppSimulator вместо объекта CurrentApp. В этом случае вы сможете проверить логику лицензирования путем имитации обращения к серверу лицензирования вместо вызова реального сервера. Для этого необходимо настроить файл с именем WindowsStoreProxy.xml в папке %userprofile%\AppData\local\packages\<package name>\LocalState\Microsoft\Windows Store\ApiData. Имитатор Microsoft Visual Studio создает этот файл при первом запуске приложения. Также можно загрузить собственный его вариант во время выполнения. Дополнительные сведения см. в разделе Использование файла WindowsStoreProxy.xml с CurrentAppSimulator.
  • В этом разделе также приведены ссылки на примеры кода из статьи Пример для Магазина. Этот пример дает отличную возможность поэкспериментировать с разными способами оплаты, доступными для приложений универсальной платформы Windows (UWP).

Шаг 1. Отправка запроса на покупку

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

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

PurchaseResults purchaseResults = await CurrentAppSimulator.RequestProductPurchaseAsync("product1");
switch (purchaseResults.Status)
{
    case ProductPurchaseStatus.Succeeded:
        product1TempTransactionId = purchaseResults.TransactionId;

        // Grant the user their purchase here, and then pass the product ID and transaction ID to
        // CurrentAppSimulator.ReportConsumableFulfillment to indicate local fulfillment to the
        // Windows Store.
        break;

    case ProductPurchaseStatus.NotFulfilled:
        product1TempTransactionId = purchaseResults.TransactionId;

        // First check for unfulfilled purchases and grant any unfulfilled purchases from an
        // earlier transaction. Once products are fulfilled pass the product ID and transaction ID
        // to CurrentAppSimulator.ReportConsumableFulfillment to indicate local fulfillment to the
        // Windows Store.
        break;
}

Шаг 2. Отслеживание выполнения покупки приложением

Предоставляя клиентам доступ к потребляемым внутренним продуктам приложения, важно отслеживать, какой товар поставляется (productId) и с какой транзакцией связывается эта поставка (transactionId).

Важно!

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

Пример ниже демонстрирует, как использовать свойства PurchaseResults вызова RequestProductPurchaseAsync из предыдущего этапа, чтобы указать, что покупка товара выполнена. Для сохранения сведений о товаре в месте, на которое впоследствии можно будет сослаться, чтобы подтвердить, что приложение выполнило свою часть сделки, используется коллекция.

private void GrantFeatureLocally(string productId, Guid transactionId)
{
    if (!grantedConsumableTransactionIds.ContainsKey(productId))
    {
        grantedConsumableTransactionIds.Add(productId, new List<Guid>());
    }
    grantedConsumableTransactionIds[productId].Add(transactionId);

    // Grant the user their content. You will likely increase some kind of gold/coins/some other asset count.
}

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

Важно!

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

private Boolean IsLocallyFulfilled(string productId, Guid transactionId)
{
    return grantedConsumableTransactionIds.ContainsKey(productId) &&
        grantedConsumableTransactionIds[productId].Contains(transactionId);
}

Шаг 3. Отправка в Магазин отчета об исполнении сделки

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

Важно!

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

FulfillmentResult result = await CurrentAppSimulator.ReportConsumableFulfillmentAsync(
    "product2", product2TempTransactionId);

Шаг 4. Идентификация невыполненных сделок

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

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

private async void GetUnfulfilledConsumables()
{
    products = await CurrentApp.GetUnfulfilledConsumablesAsync();

    foreach (UnfulfilledConsumable product in products)
    {
        logMessage += "\nProduct Id: " + product.ProductId + " Transaction Id: " + product.TransactionId;
        // This is where you would pass the product ID and transaction ID to
        // currentAppSimulator.reportConsumableFulfillment to indicate local fulfillment to the Windows Store.
    }
}