Совершение покупок в мобильном приложении с Flutter SDK

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

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

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

Warning

Имейте в виду, что introductory offer будет применён автоматически только в том случае, если Adapty отрисовывает экран.

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

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

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

Note

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

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

try {
  final purchaseResult = await Adapty().makePurchase(product: product);
    switch (purchaseResult) {
      case AdaptyPurchaseResultSuccess(profile: final profile):
        if (profile.accessLevels['premium']?.isActive ?? false) {
          // Grant access to the paid features
        }
        break;
      case AdaptyPurchaseResultPending():
        break;
      case AdaptyPurchaseResultUserCancelled():
        break;
      default:
        break;
    }
} on AdaptyError catch (adaptyError) {
    // Handle the error
} catch (e) {
    // Handle the error
}

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

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

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

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

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

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

Warning

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

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

Когда пользователь выбирает новую подписку вместо продления текущей, поведение зависит от стора:

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

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

try {
  final subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters(
    'OLD_PRODUCT_ID',
    AdaptyAndroidSubscriptionUpdateReplacementMode.immediateWithTimeProration,
  );

  final result = await Adapty().makePurchase(
    product: product,
    parameters: AdaptyPurchaseParameters(
      subscriptionUpdateParams: subscriptionUpdateParams,
    ),
  );
  
  // successful cross-grade
} on AdaptyError catch (adaptyError) {
  // Handle the error
} catch (e) {
  // Handle the error
}

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

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

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

Активация промокодов в iOS

Об offer-кодах

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

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

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

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

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

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

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

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

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

Warning

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

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

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

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

try {
  await Adapty().presentCodeRedemptionSheet();
} on AdaptyError catch (adaptyError) {
  // handle the error
} catch (e) {
  // handle the error
}
Danger

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

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

Warning

Продвигаемые встроенные покупки поступают в ваше приложение начиная с SDK версии 4.1, и ваше приложение завершает их обработку. В SDK 4.0 SDK завершал их самостоятельно. Начиная с версии 4.1, продвигаемая покупка, которую никто не слушает, отбрасывается — поэтому добавьте слушатель ниже при обновлении. См. Миграция на v4.1.

Когда пользователь начинает покупку со страницы вашего продукта в App Store и транзакция переходит в ваше приложение, SDK передаёт продукт в didReceivePromotedPurchaseStream. Подпишитесь на поток и передайте продукт в makePromotedPurchase:

Adapty().didReceivePromotedPurchaseStream.listen((product) async {
  try {
    final result = await Adapty().makePromotedPurchase(product: product);
    // process the purchase result
  } on AdaptyError catch (adaptyError) {
    // handle the error
  } catch (e) {
    // handle the error
  }
});

Подпишитесь на события сразу после activate при запуске приложения — это гарантирует, что слушатель будет зарегистрирован до того, как придёт уведомление об акционной покупке. didReceivePromotedPurchaseStream — это широковещательный поток без воспроизведения: продукт, доставленный в отсутствие слушателя, будет потерян.

makePromotedPurchase не принимает параметры покупки, поскольку акционный продукт поступает из App Store, а не с пейвола, и не несёт контекста пейвола. Метод возвращает тот же AdaptyPurchaseResult, что и makePurchase.

Если продвигаемый продукт содержит подписочное предложение, SDK применяет его при покупке автоматически. Предложение считывается из намерения покупки App Store, которое доступно начиная с iOS 18.0. На iOS 16.4–17.x покупка выполняется по базовой цене.

Info

Стрим построен на StoreKit 2 и требует iOS 16.4 или выше. На версиях ниже iOS 16.4 и на Android он никогда не эмитирует события.

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

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

await Adapty().activate(
  configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
    ..withGoogleEnablePendingPrepaidPlans(true),
);