Совершение покупок в мобильном приложении с помощью Kotlin Multiplatform SDK

Отображение пейволов в мобильном приложении — важный шаг для предоставления пользователям доступа к премиум-контенту или сервисам. Однако просто показать пейвол достаточно для проведения покупок лишь в том случае, если вы используете Paywall Builder для его настройки.

Если вы не используете Paywall Builder, для завершения покупки и открытия нужного контента необходимо вызвать отдельный метод .makePurchase(). Именно через него пользователи взаимодействуют с пейволами и совершают нужные транзакции.

Если для продукта, который пользователь пытается купить, настроен активный promotional offer, Adapty автоматически применит его в момент покупки.

Обратите внимание: introductory offer применяется автоматически только при использовании пейволов, настроенных через Paywall Builder.

В остальных случаях нужно проверить право пользователя на introductory offer на iOS. Пропуск этого шага может привести к отклонению приложения при релизе, а также к списанию полной цены с пользователей, которым доступен introductory offer.

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

Совершение покупки

Используете Paywall Builder? Покупки обрабатываются автоматически — этот шаг можно пропустить.

Нужны пошаговые инструкции? Смотрите гайд по быстрому старту с полным описанием реализации.


Adapty.makePurchase(product = product).onSuccess { purchaseResult ->
    when (purchaseResult) {
        is AdaptyPurchaseResult.Success -> {
            val profile = purchaseResult.profile
            if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) {
                // Grant access to the paid features
            }
        }
        is AdaptyPurchaseResult.UserCanceled -> {
            // Handle the case where the user canceled the purchase
        }
        is AdaptyPurchaseResult.Pending -> {
            // Handle deferred purchases (e.g., the user will pay offline with cash)
        }
    }
}.onError { error ->
    // Handle the error
}

Параметры запроса:

ПараметрОбязательностьОписание
ProductобязательныйОбъект AdaptyPaywallProduct, полученный из пейвола.

Параметры ответа:

ПараметрОписание
Profile

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

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

Примечание: если вы всё ещё используете StoreKit версии ниже 2.0 и Adapty SDK версии ниже 2.9.0, вам нужно указать общий секрет Apple App Store. Этот метод в настоящее время признан устаревшим компанией Apple.

Смена подписки при совершении покупки

Когда пользователь выбирает новую подписку вместо продления текущей, поведение зависит от магазина приложений. В Google Play подписка не обновляется автоматически — переключение нужно реализовать в коде мобильного приложения, как описано ниже.

Чтобы заменить подписку на другую в Android, вызовите метод .makePurchase() с дополнительным параметром:


val subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters(
    oldSubVendorProductId = "old_subscription_product_id",
    replacementMode = AdaptyAndroidSubscriptionUpdateReplacementMode.CHARGE_FULL_PRICE
)

val purchaseParams = AdaptyPurchaseParameters.Builder()
    .setSubscriptionUpdateParams(subscriptionUpdateParams)
    .build()

Adapty.makePurchase(
    product = product,
    parameters = purchaseParams
).onSuccess { purchaseResult ->
    when (purchaseResult) {
        is AdaptyPurchaseResult.Success -> {
            val profile = purchaseResult.profile
            // successful cross-grade
        }
        is AdaptyPurchaseResult.UserCanceled -> {
            // user canceled the purchase flow
        }
        is AdaptyPurchaseResult.Pending -> {
            // the purchase has not been finished yet, e.g. user will pay offline by cash
        }
    }
}.onError { error ->
    // Handle the error
}

Дополнительный параметр запроса:

ПараметрОбязательностьОписание
parametersнеобязательныйОбъект AdaptyAndroidSubscriptionUpdateParameters, передаваемый через AdaptyPurchaseParameters.

Подробнее о подписках и режимах замены можно прочитать в документации Google для разработчиков:

Погашение промокодов в iOS

Об офферных кодах

Офферные коды позволяют предоставлять скидки или бесплатные пробные периоды конкретным пользователям. В отличие от обычных офферов, которые применяются автоматически, офферные коды распространяются за пределами приложения — через email-рассылки, социальные сети или печатные материалы. Пользователи активируют их, вводя код в App Store, переходя по ссылке для активации или через диалог внутри приложения.

Чтобы настроить офферные коды, откройте подписку в App Store Connect и перейдите в раздел Offer Codes. Вы можете создать три вида офферных кодов:

  • Free — подписка бесплатна на заданный период, следующее продление — по полной цене.
  • Pay as you go — пользователь платит сниженную цену в каждом расчётном периоде на протяжении заданного срока, после чего подписка продлевается по полной цене.
  • Pay up front — пользователь единовременно платит сниженную цену за весь срок оффера, после чего подписка продлевается по полной цене.

Добавлять офферные коды в Adapty не нужно. Apple помечает каждую транзакцию в период действия оффера категорией офферного кода. Это касается как первоначальной активации, так и всех последующих продлений со скидкой. Adapty обнаруживает метку и записывает каждую транзакцию с категорией оффера offer_code. Как только период оффера заканчивается и подписка продлевается по полной цене, метка исчезает. Вы можете фильтровать аналитику по типу оффера Offer Code в дашборде Adapty.

Устранение расхождений в выручке

Если транзакция по офферному коду отображается в Adapty по полной цене продукта вместо сниженной цены оффера, проверьте следующее в App Store Connect:

  • Для офферного кода настроены корректные цены для всех регионов, где пользователи могут его активировать.
  • Цена оффера задана для конкретной страны или региона пользователя. Apple передаёт региональную цену в транзакции. Если для оффера не настроена региональная цена, Apple может передать полную цену продукта.

Вы можете фильтровать и проверять транзакции по офферным кодам в дашборде Adapty по фильтрам типа оффера Offer Code и Offer Discount Type.

Устаревшие промокоды (deprecated)

Apple прекратила поддержку промокодов для встроенных покупок в марте 2026 года. Офферные коды заменяют их с расширенными возможностями: настраиваемые условия применения, сроки действия и до 1 миллиона кодов в квартал. Если вы ранее использовали промокоды для встроенных покупок, перейдите на офферные коды в App Store Connect.

Устаревшие промокоды (не более 100 на приложение на версию) предоставляли бесплатный доступ к подписке. В отличие от офферных кодов, Apple не включала информацию о скидке в транзакции по промокодам — в чеке указывалась полная цена продукта. В результате Adapty записывал эти транзакции по полной цене, что приводило к расхождениям в выручке между аналитикой Adapty и App Store Connect.

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

Чтобы отобразить в приложении экран погашения кода:

Adapty.presentCodeRedemptionSheet()
    .onSuccess {
        // code redemption sheet presented successfully
    }
    .onError { error ->
        // handle the error
    }

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

Для этого откройте URL следующего формата: https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}

Управление предоплаченными планами (Android)

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


Adapty.activate(
    AdaptyConfig.Builder("PUBLIC_SDK_KEY")
        .withGoogleEnablePendingPrepaidPlans(true)
        .build()
).onSuccess {
    // successful activation
}.onError { error ->
    // handle the error
}