Миграция Adapty iOS SDK на v. 4.0
Adapty iOS SDK 4.0 (beta) вводит флоу и переименовывает paywall API соответствующим образом. Новые API работают как с новым Flow Builder, так и с существующим Paywall Builder — никаких изменений на стороне дашборда Adapty не требуется.
Краткий справочник
| v3 | v4 |
|---|---|
Adapty.getPaywall(placementId:locale:) | Adapty.getFlow(placementId:) |
AdaptyUI.getPaywallConfiguration(forPaywall:) | AdaptyUI.getFlowConfiguration(forFlow:locale:) |
Adapty.getPaywallProducts(paywall:) | Adapty.getPaywallProducts(flow:) |
Adapty.logShowPaywall(_:) | Adapty.logShowFlow(_:) |
AdaptyPaywallController | AdaptyFlowController |
AdaptyPaywallControllerDelegate | AdaptyFlowControllerDelegate |
AdaptyUI.paywallController(with:delegate:) | AdaptyUI.flowController(with:delegate:) |
.paywall() (SwiftUI modifier) | .flow() |
AdaptyPaywallView | AdaptyFlowView |
didFailRenderingWith: / didFailRendering: | didReceiveError: |
Adapty.updateAttribution(_:source:) (source: String) | Adapty.updateAttribution(_:source:) (source: AdaptyAttributionSource) |
Adapty.setIntegrationIdentifier(key:value:) | Adapty.setIntegrationIdentifier(_:) (AdaptyIntegrationIdentifier) |
Установка: CocoaPods больше не поддерживается
Adapty iOS SDK 4.0 отказывается от поддержки CocoaPods. Устанавливайте SDK через Swift Package Manager.
Если ваш проект всё ещё использует CocoaPods, удалите поды Adapty и AdaptyUI из Podfile, выполните pod install, чтобы убрать их, а затем добавьте пакет в Xcode через File → Add Package Dependency, указав https://github.com/adaptyteam/AdaptySDK-iOS.git.
Удалённые API
Adapty.getPaywallProductsWithoutDeterminingOffer(paywall:)— удалён. Все продукты теперь включают информацию об офере, поэтому отдельный проход для определения доступности больше не нужен.AdaptyPaywallProductWithoutDeterminingOffer— удалён. Коллбэки, которые раньше передавали этот тип (например,didSelectProduct), теперь передаютAdaptyPaywallProduct.
Получение пейволов
getPaywall + getPaywallConfiguration → getFlow + getFlowConfiguration
Возвращаемые типы меняются с AdaptyPaywall / AdaptyUI.PaywallConfiguration на AdaptyFlow / AdaptyUI.FlowConfiguration. Параметр locale переносится из вызова получения данных в getFlowConfiguration:
- let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en")
- let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall)
+ let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID")
+ let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow, locale: "en")
getPaywallProducts(paywall:) → getPaywallProducts(flow:)
getPaywallProducts теперь принимает AdaptyFlow, возвращаемый Adapty.getFlow:
- let products = try await Adapty.getPaywallProducts(paywall: paywall)
+ let products = try await Adapty.getPaywallProducts(flow: flow)
Отслеживание просмотров пейвола
logShowPaywall(:) → logShowFlow(:)
logShowPaywall переименован в logShowFlow и теперь принимает AdaptyFlow вместо AdaptyPaywall. Событие по-прежнему записывается к тому же варианту, поэтому существующие метрики воронки и A/B-тестов продолжают работать без изменений в дашборде.
- try await Adapty.logShowPaywall(paywall)
+ try await Adapty.logShowFlow(flow)
Как и в v3, вам не нужно вызывать этот метод при отображении флоу или пейволов, отрисованных с помощью Flow Builder или Paywall Builder — Adapty отслеживает эти просмотры автоматически.
UIKit
AdaptyPaywallController → AdaptyFlowController
Переименуйте тип контроллера и фабричный метод:
- let controller = try AdaptyUI.paywallController(
- with: paywallConfiguration,
- delegate: self
- )
+ let controller = try AdaptyUI.flowController(
+ with: flowConfiguration,
+ delegate: self
+ )
AdaptyPaywallControllerDelegate → AdaptyFlowControllerDelegate
Переименуйте протокол и обновите каждую сигнатуру метода. Обратите внимание, что didSelectProduct теперь принимает AdaptyPaywallProduct вместо удалённого AdaptyPaywallProductWithoutDeterminingOffer.
- class YourClass: AdaptyPaywallControllerDelegate {
+ class YourClass: AdaptyFlowControllerDelegate {
- func paywallControllerDidAppear(_ controller: AdaptyPaywallController) { }
+ func flowControllerDidAppear(_ controller: AdaptyFlowController) { }
- func paywallControllerDidDisappear(_ controller: AdaptyPaywallController) { }
+ func flowControllerDidDisappear(_ controller: AdaptyFlowController) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didPerform action: AdaptyUI.Action) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didPerform action: AdaptyUI.Action) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didSelectProduct product: AdaptyPaywallProduct) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didStartPurchase product: AdaptyPaywallProduct) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didStartPurchase product: AdaptyPaywallProduct) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFinishPurchase product: AdaptyPaywallProduct,
- purchaseResult: AdaptyPurchaseResult) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFinishPurchase product: AdaptyPaywallProduct,
+ purchaseResult: AdaptyPurchaseResult) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailPurchase product: AdaptyPaywallProduct,
- error: AdaptyError) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFailPurchase product: AdaptyPaywallProduct,
+ error: AdaptyError) { }
- func paywallControllerDidStartRestore(_ controller: AdaptyPaywallController) { }
+ func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFinishRestoreWith profile: AdaptyProfile) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFinishRestoreWith profile: AdaptyProfile) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailRestoreWith error: AdaptyError) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFailRestoreWith error: AdaptyError) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailRenderingWith error: AdaptyUIError) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didReceiveError error: AdaptyUIError) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailLoadingProductsWith error: AdaptyError) -> Bool { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFailLoadingProductsWith error: AdaptyError) -> Bool { }
- func paywallController(_ controller: AdaptyPaywallController,
- didPartiallyLoadProducts failedIds: [String]) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didPartiallyLoadProducts failedIds: [String]) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFinishWebPaymentNavigation product: AdaptyPaywallProduct?,
- error: AdaptyError?) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFinishWebPaymentNavigation product: AdaptyPaywallProduct?,
+ error: AdaptyError?) { }
}
SwiftUI
Модификатор .paywall() → .flow()
Переименуйте модификатор и обновите имя параметра конфигурации:
@State var flowPresented = false // переименуйте как угодно — имя переменной на ваш выбор
var body: some View {
Text("Hello, AdaptyUI!")
- .paywall(
+ .flow(
isPresented: $flowPresented,
- paywallConfiguration: paywallConfiguration,
+ flowConfiguration: flowConfiguration,
didFailPurchase: { product, error in /* обработать ошибку */ },
didFinishRestore: { profile in /* проверить уровень доступа и закрыть */ },
didFailRestore: { error in /* обработать ошибку */ },
- didFailRendering: { error in flowPresented = false }
+ didReceiveError: { error in flowPresented = false }
)
}
Переименованный колбэк срабатывает при тех же ошибках рендеринга, что и didFailRendering, плюс при новых ошибках выполнения из скрипта флоу (JavaScript-исключения с кодом AdaptyUIError 4105 — .jsException). Менять код в теле обработчика не нужно — достаточно переименовать параметр.
AdaptyPaywallView → AdaptyFlowView
Переименуйте вью, обновите параметр конфигурации и обновите замыкание didSelectProduct — теперь оно получает AdaptyPaywallProduct вместо удалённого AdaptyPaywallProductWithoutDeterminingOffer:
- AdaptyPaywallView(
- paywallConfiguration: paywallConfiguration,
- didSelectProduct: { product: AdaptyPaywallProductWithoutDeterminingOffer in /* handle */ },
+ AdaptyFlowView(
+ flowConfiguration: flowConfiguration,
+ didSelectProduct: { product: AdaptyPaywallProduct in /* handle */ },
didFailPurchase: { product, error in /* handle the error */ },
didFinishRestore: { profile in /* check access level and dismiss */ },
didFailRestore: { error in /* handle the error */ },
- didFailRendering: { error in /* handle the error */ }
+ didReceiveError: { error in /* handle the error */ }
)
Пользовательские ресурсы AdaptyUI
AdaptyUICustomVideoAsset
Два изменения затрагивают все существующие места вызова:
.playerтеперь принимаетAVPlayerвместоAVQueuePlayer.- В каждый case добавлен завершающий параметр
resolution: CGSize?. Передайтеnil, чтобы сохранить текущее поведение, или передайте фактический размер в пикселях, чтобы плеер мог зарезервировать место в лэйауте (соотношение сторон =width / height) до загрузки видео.
- case file(url: URL, preview: AdaptyUICustomImageAsset?)
- case remote(url: URL, preview: AdaptyUICustomImageAsset?)
- case player(item: AVPlayerItem, player: AVQueuePlayer, preview: AdaptyUICustomImageAsset?)
+ case file(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?)
+ case remote(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?)
+ case player(item: AVPlayerItem, player: AVPlayer, preview: AdaptyUICustomImageAsset?, resolution: CGSize?)
Идентификаторы атрибуции и интеграций
updateAttribution(_:source:)
Параметр source изменился с типа String на новый тип AdaptyAttributionSource, а вложенный ранее AdaptyProfile.AttributionSource переименован в AdaptyAttributionSource на верхнем уровне. Используйте один из предопределённых источников или передайте строковый литерал для любого другого источника — AdaptyAttributionSource поддерживает ExpressibleByStringLiteral, поэтому существующие вызовы со строковыми литералами продолжат компилироваться.
- try await Adapty.updateAttribution(attribution, source: "adjust")
+ try await Adapty.updateAttribution(attribution, source: .adjust)
Предопределённые источники: .appleAds, .adjust, .appsflyer, .branch, .tenjin. Если источник хранится в переменной типа String, оберните его: AdaptyAttributionSource(rawValue: yourSource).
setIntegrationIdentifier(_:)
setIntegrationIdentifier(key:value:) заменён вариативным методом, который принимает одно или несколько значений AdaptyIntegrationIdentifier. Используйте предопределённые фабричные методы вместо строковых ключей:
- try await Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid)
+ try await Adapty.setIntegrationIdentifier(.appsflyerId(uid))
Можно задать сразу несколько идентификаторов в одном вызове:
try await Adapty.setIntegrationIdentifier(
.appsflyerId(uid),
.adjustDeviceId(adid)
)
Замените каждую старую строку ключа соответствующим фабричным методом:
| ключ v3 | фабрика v4 |
|---|---|
"adjust_device_id" | .adjustDeviceId(_:) |
"airbridge_device_id" | .airbridgeDeviceId(_:) |
"amplitude_user_id" | .amplitudeUserId(_:) |
"amplitude_device_id" | .amplitudeDeviceId(_:) |
"appmetrica_device_id" | .appmetricaDeviceId(_:) |
"appmetrica_profile_id" | .appmetricaProfileId(_:) |
"appsflyer_id" | .appsflyerId(_:) |
"branch_id" | .branchId(_:) |
"facebook_anonymous_id" | .facebookAnonymousId(_:) |
"firebase_app_instance_id" | .firebaseAppInstanceId(_:) |
"mixpanel_user_id" | .mixpanelUserId(_:) |
"one_signal_subscription_id" | .oneSignalSubscriptionId(_:) |
"one_signal_player_id" | .oneSignalPlayerId(_:) |
"posthog_distinct_user_id" | .posthogDistinctUserId(_:) |
"pushwoosh_hwid" | .pushwooshHWID(_:) |
"tenjin_analytics_installation_id" | .tenjinAnalyticsInstallationId(_:) |