Управление сообщениями App Store в iOS SDK

App Store иногда должен показывать пользователям сообщения о подписке: запросить согласие на повышение цены, сообщить о проблемах с оплатой или представить win-back offer. По умолчанию StoreKit показывает эти сообщения самостоятельно, пока открыто приложение — даже поверх пейвола, онбординга или оформления заказа.

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

Warning

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

Перед началом

Вам потребуется:

  • Adapty iOS SDK версии 4.2 или выше: в более ранних версиях отсутствует API сообщений стора.
  • iOS 16 или Mac Catalyst 16 или выше: StoreKit не доставляет сообщения приложениям на более ранних версиях, поэтому API сообщений стора помечен как доступный начиная с iOS 16. На macOS этот API недоступен.

SDK Adapty поддерживает iOS 15. Если ваше приложение тоже поддерживает iOS 15, оберните каждый вызов store messages в if #available(iOS 16.0, *) или пометьте тип, делающий этот вызов, аннотацией @available(iOS 16.0, *). Без одной из этих проверок приложение не скомпилируется. Примеры в этой статье включают такие проверки. Если ваш deployment target — iOS 16 или выше, их можно опустить.

Включение ручной обработки

Чтобы перехватывать сообщения App Store, установите значение storeMessagesHandling равным .manual при активации SDK:

let configurationBuilder = AdaptyConfiguration
    .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY")
    .with(storeMessagesHandling: .manual) // .auto is the default

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

Получение типов ожидающих сообщений

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

if #available(iOS 16.0, *) {
    let pendingTypes = await Adapty.getPendingStoreMessageTypes()

    if pendingTypes.contains(.billingIssue) {
        // For example, skip the upsell and show the billing message first
    }
}

Каждое сообщение относится к одному из следующих типов:

ТипСообщение
.genericОбщее сообщение App Store.
.priceIncreaseConsentЗапрос на согласие с повышением цены подписки.
.billingIssueУведомление о проблеме с оплатой подписки. Доступно на iOS 16.4 и выше.
.winBackOfferПодходящий win-back offer. Доступно на iOS 18 и выше.

Тип сообщения, который SDK не распознаёт, имеет значение storekit_<number>.

Показ ожидающих сообщений

Когда ваше приложение достигает точки, в которой системное окно не прервёт пользователя — например, после того как пользователь закрыл флоу или завершил онбординг — вызовите showStoreMessages:

SDK показывает сообщения одно за другим. После того как StoreKit отображает сообщение, SDK удаляет его из списка ожидания. Если StoreKit не может показать сообщение, SDK записывает ошибку в лог Adapty, сохраняет сообщение для следующего вызова и продолжает обработку остальных сообщений.

Показывать только определённые типы сообщений

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

try await Adapty.showStoreMessages(
    for: [.billingIssue, .priceIncreaseConsent],
    using: displayStoreKitMessage
)

Без for SDK показывает все ожидающие сообщения, включая типы, которые он не распознаёт.

Ошибки

showStoreMessages выбрасывает AdaptyError с одним из следующих кодов:

КодНазваниеПричина
3201operationInProgressДругой вызов showStoreMessages всё ещё отображает сообщения. Дождитесь его завершения и повторите попытку.
3202resolverFailureТолько UIKit: вы не передали сцену, и SDK не нашёл ни одной активной сцены на переднем плане. Вызовите метод снова, когда приложение находится на переднем плане, или передайте сцену явно.
9000operationInterruptedЗадача, вызвавшая метод, была отменена.