Миграция Adapty Kotlin Multiplatform SDK на v4.1
Adapty Kotlin Multiplatform SDK 4.1 — это первый стабильный релиз ветки 4.x: версия 4.0 вышла только в бета, поэтому если вы используете 3.x, переходите сразу на 4.1. Это руководство охватывает всю миграцию: флоу, введённые в 4.0, и изменения версии 4.1.
Версия 4.x вводит флоу и соответствующим образом переименовывает API пейволов. Новые API работают как с Flow & Paywall Builder, так и со старым Paywall Builder — никаких изменений в настройках на стороне дашборда Adapty не требуется. Помимо этого, версия 4.1 переводит Adapty Attribution в режим opt-in, переименовывает API внешней атрибуции и тип подписки на продукт, а также добавляет поддержку продвигаемых встроенных покупок App Store.
Переходите с бета-версии 4.0? Обновите версию, и вам нужно ознакомиться только с пятью разделами: Атрибуция Adapty отключена по умолчанию, переименованные API внешней атрибуции, AdaptyPaywallProductSubscription → AdaptyProductSubscription, встроенные покупки, продвигаемые в App Store, и выбор конкретного лейаута. hasViewConfiguration также возвращён в модель флоу.
Краткий справочник
| v3 | v4.1 |
|---|---|
| Атрибуция Adapty включена автоматически | отключена по умолчанию — включите с помощью .withAdaptyAttributionEnabled(true) |
Adapty.getPaywall(placementId, locale) | Adapty.getFlow(placementId) |
Adapty.getPaywallForDefaultAudience(placementId, locale) | Adapty.getFlowForDefaultAudience(placementId) |
Adapty.getPaywallProducts(paywall) | Adapty.getPaywallProducts(flow) |
Adapty.logShowPaywall(paywall) | Adapty.logShowFlow(flow) |
AdaptyPaywall | AdaptyFlow |
AdaptyUI.createPaywallView(paywall, ...) | AdaptyUI.createFlowView(flow, ...) |
AdaptyUI.createNativePaywallView(...) → AdaptyNativePaywallView | AdaptyUI.createNativeFlowView(...) → AdaptyNativeFlowView |
AdaptyUIPaywallView | AdaptyUIFlowView |
AdaptyUI.presentPaywallView(view) / dismissPaywallView(view) | AdaptyUI.presentFlowView(view) / dismissFlowView(view) |
AdaptyUI.setPaywallsEventsObserver(observer) | AdaptyUI.setFlowsEventsObserver(observer) |
AdaptyUI.registerPaywallEventsListener / unregisterPaywallEventsListener | AdaptyUI.registerFlowEventsListener / unregisterFlowEventsListener |
AdaptyUIPaywallsEventsObserver | AdaptyUIFlowsEventsObserver |
AdaptyUIPaywallPlatformView(paywall, ...) | AdaptyUIFlowPlatformView(flow, ...) |
paywallViewDidPerformAction, paywallViewDidAppear и другие колбэки paywallView... | flowViewDidPerformAction, flowViewDidAppear и другие колбэки flowView... |
paywallViewDidFailRendering | flowViewDidReceiveError |
Adapty.updateAttribution(attribution, source) со строковым параметром source | Adapty.updateExternalAttribution(attribution, provider) с AdaptyExternalAttributionProvider |
провайдер передаётся как строка, например "adjust" | AdaptyExternalAttributionProvider, например AdaptyExternalAttributionProvider.ADJUST |
AdaptyProfile.appliedAttributionSources: List<String> | AdaptyProfile.appliedExternalAttributionProviders: List<AdaptyExternalAttributionProvider> |
AdaptyPaywallProductSubscription | AdaptyProductSubscription |
| Promoted in-app purchases завершаются автоматически, без возможности перехватить их | OnPromotedPurchaseListener и Adapty.makePromotedPurchase(product) передают завершение покупки вашему приложению |
AdaptyPaywallProduct сохраняет своё название — продукты по-прежнему принадлежат флоу, и getPaywallProducts тоже сохраняет название, теперь принимая AdaptyFlow. Методы getFlow и getFlowForDefaultAudience больше не принимают параметр locale — передавайте его в createFlowView. API покупок и профилей (makePurchase, restorePurchases, getProfile, identify, updateProfile) и setFallback сохраняют те же сигнатуры, однако файл резервного пейвола необходимо скачать заново — см. Резервные файлы. Методы онбординга по-прежнему работают, но считаются устаревшими — см. Устаревание API онбординга. Некоторые поведения по умолчанию изменились — см. Изменения поведения по умолчанию.
Установка
Обновите версию и синхронизируйте проект:
[versions]
adapty-kmp = "<the latest SDK version>"
[libraries]
adapty-kmp = { module = "io.adapty:adapty-kmp", version.ref = "adapty-kmp" }
adapty-kmp-ui = { module = "io.adapty:adapty-kmp-ui", version.ref = "adapty-kmp" }
Модуль adapty-kmp-ui нужен только если вы отображаете флоу и пейволы через слой Compose Multiplatform (view.present()). Подробнее об установке см. в разделе Установка Adapty SDK.
Нативные SDK Adapty для обеих платформ обновлены до версии 4.x и подтягиваются автоматически — никаких изменений в сборке не требуется. Минимальная версия iOS остаётся 15.0, это изменение её не затрагивает.
⚠️ Атрибуция Adapty отключена по умолчанию
Если вы используете Атрибуцию Adapty и обновляетесь до SDK 4.1 без явного подключения, всё сломается без каких-либо предупреждений — установки перестанут фиксироваться, и никаких уведомлений не будет.
В более ранних версиях SDK автоматически регистрировал установки для Атрибуции Adapty. Начиная с версии SDK 4.1, это отключено по умолчанию: SDK не регистрирует установки, слушатель, заданный через setOnInstallationDetailsListener, никогда не срабатывает, а getCurrentInstallationStatus возвращает AdaptyInstallationStatus.Determined.NotAvailable.
Если вы используете Атрибуцию Adapty, включите её при активации SDK:
val config = AdaptyConfig
.Builder("PUBLIC_SDK_KEY")
+ .withAdaptyAttributionEnabled(true)
.build()
Adapty.activate(configuration = config)
Если вы не используете Adapty Attribution, никаких изменений не требуется.
Получение флоу
getPaywall → getFlow
Возвращаемый тип меняется с AdaptyPaywall на AdaptyFlow, параметр locale переносится из вызова fetch в createFlowView; для кастомных пейволов все локали возвращаются в flow.remoteConfigs:
- Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en")
- .onSuccess { paywall ->
- // use the paywall
+ Adapty.getFlow("YOUR_PLACEMENT_ID")
+ .onSuccess { flow ->
+ AdaptyUI.createFlowView(flow = flow, locale = "en")
}
.onError { error ->
// handle the error
}
locale остаётся необязательным параметром в createFlowView: если его не указать, вид отобразится на en или на языке по умолчанию флоу, если в нём нет en. См. Локализации и коды языков.
getPaywallForDefaultAudience переименован аналогичным образом:
- Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en")
+ Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID")
getPaywallProducts(paywall) → getPaywallProducts(flow)
getPaywallProducts сохраняет своё название, но теперь принимает AdaptyFlow:
- Adapty.getPaywallProducts(paywall)
+ Adapty.getPaywallProducts(flow)
.onSuccess { products ->
// use the products
}
Резервные файлы
Формат резервного файла изменился в SDK v4. Скачайте новый файл в разделе Placements > Fallbacks и добавьте его в приложение.
Модель данных
getFlow возвращает AdaptyFlow вместо AdaptyPaywall, и структура объекта изменилась:
Свойство AdaptyPaywall в v3 | Свойство AdaptyFlow в v4 | Действие |
|---|---|---|
remoteConfig: AdaptyRemoteConfig? (одиночный) | remoteConfigs: List<AdaptyRemoteConfig> | Флоу содержит один Remote Config на каждый настроенный язык. Читайте тот, который соответствует пользователю: flow.remoteConfigs.firstOrNull { it.locale == "en" }. |
| (новое) | paywalls: List<AdaptyFlowPaywall> | Каждый элемент — один вариант пейвола во флоу, со своими name, variationId и productIdentifiers. Методы web paywall принимают AdaptyFlowPaywall — см. Методы web paywall. |
productIdentifiers | перемещено | Идентификаторы продуктов теперь находятся в каждом варианте: flow.paywalls[i].productIdentifiers. Для получения продуктов по-прежнему вызывайте getPaywallProducts(flow). |
hasViewConfiguration | сохранено | Указывает, содержит ли флоу макет, который AdaptyUI может отобразить. Это свойство отсутствовало в бета-версии 4.0 и вернулось в 4.1 — если вы убрали проверки для беты, можете снова его использовать. Значение false означает, что флоу не содержит макета, поэтому обрабатывайте его только как Remote Config. Также можно вызвать createFlowView и обработать ошибку (см. Отображение флоу). |
hasViewConfiguration также присутствует в AdaptyOnboarding и не изменился.
Методы веб-пейвола
openWebPaywall и createWebPaywallUrl сохраняют свои названия, но параметр paywall заменяется параметром flowPaywall, принимающим AdaptyFlowPaywall — одним из вариантов в flow.paywalls. Вместо него по-прежнему можно передать AdaptyPaywallProduct:
- Adapty.openWebPaywall(paywall = paywall)
+ flow.paywalls.firstOrNull()?.let { flowPaywall ->
+ Adapty.openWebPaywall(flowPaywall = flowPaywall)
+ }
Отслеживание просмотров флоу
logShowPaywall → logShowFlow
logShowPaywall переименован в logShowFlow и теперь принимает AdaptyFlow. Событие по-прежнему регистрируется для того же варианта, поэтому существующие метрики воронки и A/B-тестов продолжают работать без изменений в дашборде.
- Adapty.logShowPaywall(paywall)
+ Adapty.logShowFlow(flow)
Как и в v3, вызывать этот метод при отображении флоу или пейволов, отрисованных самим Adapty, не нужно — Adapty отслеживает такие просмотры автоматически.
Отображение флоу
createPaywallView → createFlowView
Переименуйте фабричный метод и передайте AdaptyFlow. Тип возвращаемого значения переименован с AdaptyUIPaywallView на AdaptyUIFlowView, но его методы (present, dismiss) и необязательные параметры (loadTimeout, preloadProducts, customTags, customTimers, customAssets, productPurchaseParams) остались прежними. Добавлен один новый необязательный параметр: locale — он заменяет locale, который раньше передавался в getPaywall. Подробнее см. в разделе Получение флоу.
customTimers по-прежнему существует, но влияет только на пейволы, созданные с помощью устаревшего Paywall Builder. Таймер обратного отсчёта countdown timer во флоу работает по настройкам, заданным во Flow & Paywall Builder, поэтому флоу игнорирует всё, что вы передаёте здесь.
- AdaptyUI.createPaywallView(paywall)
+ AdaptyUI.createFlowView(flow)
.onSuccess { view ->
view.present()
}
.onError { error ->
// handle the error
}
Если вы не используете Compose Multiplatform, нативный фабричный метод переименован так же:
- AdaptyUI.createNativePaywallView(paywall)
+ AdaptyUI.createNativeFlowView(flow)
createFlowView возвращает AdaptyResult.Error, если для флоу не настроен вид, поэтому вы можете убрать проверку hasViewConfiguration из v3 и обработать ошибку вместо неё:
- if (paywall.hasViewConfiguration) {
- AdaptyUI.createPaywallView(paywall)
- .onSuccess { view -> view.present() }
- }
+ AdaptyUI.createFlowView(flow)
+ .onSuccess { view -> view.present() }
+ .onError { error ->
+ // the flow has no view configured, or view creation failed
+ }
Представление флоу одноразовое: после вызова dismiss() оно уничтожается, поэтому для повторного показа флоу вызовите createFlowView ещё раз.
Обработка событий
Наблюдатель событий переименован с AdaptyUIPaywallsEventsObserver на AdaptyUIFlowsEventsObserver, а его колбэки меняют префикс paywallView на flowView. Тела существующих обработчиков менять не нужно — достаточно переименовать тип и переопределения:
- AdaptyUI.setPaywallsEventsObserver(object : AdaptyUIPaywallsEventsObserver {
- override fun paywallViewDidFinishPurchase(
- view: AdaptyUIPaywallView,
+ AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver {
+ override fun flowViewDidFinishPurchase(
+ view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
// custom logic after purchase
}
})
Один колбэк также переименован: paywallViewDidFailRendering становится flowViewDidReceiveError. Он срабатывает для тех же ошибок рендеринга, что и раньше, плюс других runtime-ошибок, не связанных с покупкой:
- override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) {}
+ override fun flowViewDidReceiveError(view: AdaptyUIFlowView, error: AdaptyError) {}
См. Обработка событий флоу и пейвола — полный список колбэков.
Compose platform view
Если вы встраиваете представления через Compose Multiplatform composable, AdaptyUIPaywallPlatformView(paywall, ...) переименовывается в AdaptyUIFlowPlatformView(flow, ...). Колбэки событий сохраняют свои имена onDid..., за исключением onDidFailRendering, который становится onDidReceiveError:
- AdaptyUIPaywallPlatformView(
- paywall = paywall,
+ AdaptyUIFlowPlatformView(
+ flow = flow,
onDidFinishPurchase = { view, product, result -> /* ... */ },
)
Как и в v3, коллбэки, которые вы передаёте здесь (и любой наблюдатель, зарегистрированный через registerFlowEventsListener), выполняются в дополнение к глобальному наблюдателю, а не вместо него — ваш коллбэк наблюдает за событием, но не заменяет глобальное поведение по умолчанию. Учитывайте изменения поведения по умолчанию: например, глобальное поведение по умолчанию больше не закрывает экран после покупки.
Новые API
AdaptyUI.setObserverModeResolver(...)сAdaptyUIObserverModeResolver— управляет покупками и восстановлениями, инициированными из флоу, когда SDK работает в режиме Observer. Ранее это было доступно только в нативных iOS- и Android-SDK. См. Отображение флоу в режиме Observer.AdaptyUI.setSystemRequestsHandler(...)сAdaptyUISystemRequestsHandler— зарезервирован для системных запросов из флоу (запросы разрешений ОС и запросы на оценку приложения). Флоу пока не инициируют такие запросы, поэтому регистрировать обработчик не нужно.- Новый опциональный колбэк
flowViewDidReceiveAnalyticEventпередаёт аналитические события из флоу, начиная с события просмотра экрана для каждого экрана, который открывает пользователь. См. Отслеживание просмотров экранов флоу. AdaptyUI.openWebUrl(url, openIn)иAdaptyUI.requestAppReview()— обеспечивают стандартную обработкуOpenUrlActionиhandleAppReviewRequestпо умолчанию, так что URL и запросы на оценку приложения обрабатываются нативно из коробки. Вызывайте их напрямую только если переопределяете эти значения по умолчанию.AdaptyUIFlowView.locale— возвращает локализацию, с которой было построено представление, чтобы вы могли узнать, какую именно видит пользователь.AdaptyConfig.ServerCluster.CN— новый вариант серверного кластера наряду сDEFAULTиEU, для подключения вашего приложения к серверам Adapty в Китае.
Переименованные API для внешней атрибуции
Начиная с версии SDK 4.1, API для передачи данных атрибуции от внешнего провайдера (Adjust, AppsFlyer, Branch, Tenjin, Apple Ads или кастомного) переименованы в соответствии с нативными SDK, а провайдер изменён со строки на тип. Устаревших псевдонимов нет, поэтому существующие места вызова перестанут компилироваться до тех пор, пока вы их не обновите.
updateAttribution → updateExternalAttribution
Метод переименован, параметр source заменён на provider, и теперь принимает AdaptyExternalAttributionProvider вместо String:
- Adapty.updateAttribution(attribution, "adjust")
+ Adapty.updateExternalAttribution(attribution, AdaptyExternalAttributionProvider.ADJUST)
Данные атрибуции по-прежнему передаются как Map<String, Any>.
Вызов завершается, как только бэкенд принимает данные для асинхронной обработки. Успешный результат не означает, что данные уже применены к профилю.
AdaptyExternalAttributionProvider
Теперь это тип с предопределёнными значениями: APPLE_ADS, ADJUST, APPSFLYER, BRANCH, TENJIN и CUSTOM. Для любого другого провайдера создайте экземпляр из его идентификатора:
AdaptyExternalAttributionProvider("your_provider")
Прямое создание экземпляра также охватывает провайдеров, которые Adapty добавит после выхода этой версии SDK — идентификатор передаётся на бэкенд без изменений, а не схлопывается в неизвестное значение. Пробельные символы по краям обрезаются.
Каждое предопределённое значение оборачивает тот же идентификатор, который вы передавали в updateAttribution ранее: AdaptyExternalAttributionProvider.APPLE_ADS.value — это apple_search_ads, остальные используют собственные имена в нижнем регистре.
AdaptyProfile.appliedAttributionSources → appliedExternalAttributionProviders
Свойство профиля, в котором перечислены провайдеры атрибуции, применённые к профилю, переименовано, и тип его элементов изменился соответственно:
- if (profile.appliedAttributionSources.contains("apple_search_ads")) {
+ if (profile.appliedExternalAttributionProviders.contains(AdaptyExternalAttributionProvider.APPLE_ADS)) {
// Apple Ads attribution has been applied
}
AdaptyPaywallProductSubscription → AdaptyProductSubscription
Тип с деталями подписки переименован, так как продвигаемые продукты теперь используют тот же тип. Изменилось только имя — все свойства сохранили свои имена и типы:
- val subscription: AdaptyPaywallProductSubscription? = product.subscription
+ val subscription: AdaptyProductSubscription? = product.subscription
Продвигаемые встроенные покупки в App Store
SDK 4.1 доставляет встроенные покупки, продвигаемые на странице вашего продукта в App Store, в ваше приложение на iOS. В более ранних версиях такая покупка завершалась автоматически, и приложение не могло её перехватить. Начиная с версии 4.1 покупка ожидает вашего кода, поэтому это требует действий, даже если вы никогда не работали с продвигаемыми покупками.
Чтобы поддержать продвигаемые покупки, зарегистрируйте OnPromotedPurchaseListener и завершите покупку, передав продукт в Adapty.makePromotedPurchase. Без зарегистрированного слушателя покупка будет приостановлена, а не завершена: пользователь нажимает Buy на странице App Store, и в вашем приложении ничего не происходит. Зарегистрируйте слушатель как можно раньше — подробнее о тайминге и полном примере см. в разделе Встроенные покупки из App Store.
Выбор конкретного макета
createFlowView, createNativeFlowView и AdaptyUIFlowPlatformView принимают новый необязательный параметр customLayoutId. Передайте его, чтобы отобразить конкретный макет из конфигурации макетов флоу вместо того, который SDK выбирает автоматически в зависимости от типа устройства и размера экрана. Flow & Paywall Builder пока не поддерживает назначение пользовательских идентификаторов макетов, поэтому оставьте этот параметр неустановленным:
AdaptyUI.createFlowView(flow, customLayoutId = "tablet_landscape")
Если ни один макет не соответствует ID, флоу загружается без конфигурации отображения. Параметр необязателен и по умолчанию равен null, поэтому существующие вызовы не затрагиваются.
Изменения поведения по умолчанию
Эти изменения не вызывают ошибок компиляции, поэтому проверяйте их в runtime:
- Завершение покупки: В v3 дефолтный
paywallViewDidFinishPurchaseзакрывал вью после любого результата покупки, кромеAdaptyPurchaseResult.UserCanceled. В v4 дефолтныйflowViewDidFinishPurchaseничего не делает, поэтому флоу остаётся открытым после покупки, пока вы его не закроете — аналогично поведению на iOS. Если вы рассчитывали на автоматическое закрытие, вызовитеview.dismiss()самостоятельно после завершения покупки. - Системная кнопка «Назад» на Android: В v3 дефолтный
paywallViewDidPerformActionзакрывал вью как поCloseAction, так и поAndroidSystemBackAction. В v4 дефолтный обработчик реагирует только наCloseAction— системная кнопка «Назад» больше не закрывает флоу автоматически, что соответствует поведению iOS, где флоу нельзя закрыть системным жестом. Дайте пользователям явный способ выйти (кнопка Close или действиеon_device_back) или закройте вью самостоятельно вflowViewDidPerformAction. - Ошибки вью: В v3 дефолтный
paywallViewDidFailRenderingничего не делал. В v4 дефолтныйflowViewDidReceiveErrorзакрывает вью — переопределите его, если хотите оставить вью открытым или обработать ошибку иначе. - Вью одноразовые: После вызова
dismiss()вью уничтожается. Чтобы показать флоу повторно, вызовитеcreateFlowViewзаново.
Устаревший API онбординга
Устаревший API онбординга в v4 заменён Flow & Paywall Builder. Он по-прежнему работает, но будет удалён в одном из будущих релизов, поэтому планируйте миграцию своих онбордингов на Flow & Paywall Builder.
Устаревшие символы: getOnboarding, getOnboardingForDefaultAudience, AdaptyUI.createOnboardingView, AdaptyUI.createNativeOnboardingView и AdaptyUIOnboardingsEventsObserver.