Migrate Adapty Capacitor SDK sang v4.1.1
Adapty Capacitor SDK 4.1.1 là bản phát hành ổn định hiện tại của dòng 4.x — phiên bản 4.0 chỉ được phát hành dưới dạng beta, vì vậy nếu bạn đang dùng 3.x, hãy migrate thẳng lên 4.1.1. Hướng dẫn này bao gồm toàn bộ quá trình migration: các flow được giới thiệu trong 4.0 và các thay đổi của 4.1.1 bổ sung thêm.
Dòng 4.x giới thiệu các flow và đổi tên các API paywall tương ứng. Các API mới hoạt động với flow, và chúng vẫn hoạt động với các paywall từ builder cũ — không cần thay đổi cấu hình nào trên Adapty Dashboard. Ngoài ra, phiên bản 4.1.1 làm cho Adapty Attribution trở thành opt-in, đổi tên phương thức attribution bên ngoài, thay đổi định dạng file dự phòng, và bổ sung tính năng App Store promoted in-app purchase.
Bạn đang chuyển từ bản beta 4.0? Hãy thay phiên bản beta đã ghim bằng phiên bản mới nhất, sau đó chỉ cần xem bốn phần sau: Adapty Attribution bị tắt theo mặc định, các API attribution ngoài đã được đổi tên, tệp dự phòng, và sản phẩm được quảng bá trên App Store.
Tham khảo nhanh
| v3 | v4.1.1 |
|---|---|
| Adapty Attribution được bật tự động | mặc định bị tắt — bật bằng adaptyAttributionEnabled: true |
adapty.getPaywall({ placementId, locale?, params? }) | adapty.getFlow({ placementId, params? }) |
adapty.getPaywallForDefaultAudience({ placementId, locale?, params? }) | adapty.getFlowForDefaultAudience({ placementId, params? }) |
adapty.getPaywallProducts({ paywall }) | adapty.getPaywallProducts({ flow }) |
adapty.logShowPaywall({ paywall }) | adapty.logShowFlow({ flow }) |
AdaptyPaywall (type) | AdaptyFlow + AdaptyFlowPaywall |
createPaywallView(paywall, params?) | createFlowView(flow, params?) |
PaywallViewController | FlowViewController |
EventHandlers (type) | FlowEventHandlers |
CreatePaywallViewParamsInput | CreateFlowViewParamsInput |
onRenderingFailed | onError |
adapty.updateAttribution({ attribution, source }) | adapty.updateExternalAttribution({ attribution, provider }) |
AdaptyProfile.appliedAttributionSources | AdaptyProfile.appliedExternalAttributionProviders |
AttributionSource | AdaptyExternalAttributionProvider |
| File fallback đã tải xuống cho bản 3.x | định dạng file fallback mới — tải lại file |
| In-app purchase được quảng cáo hoàn tất tự động, không có cách nào để chặn lại | sự kiện 'onPromotedPurchaseReceived' và adapty.makePromotedPurchase({ product }) chuyển quyền hoàn tất về phía app của bạn |
AdaptyPaywallProduct giữ nguyên tên — các sản phẩm vẫn thuộc về một flow, và getPaywallProducts cũng giữ nguyên tên, nhưng giờ nhận vào một AdaptyFlow. Các phương thức getFlow và getFlowForDefaultAudience không còn nhận tham số locale nữa — thay vào đó hãy truyền nó vào createFlowView. Các API mua hàng và hồ sơ người dùng (makePurchase, restorePurchases, getProfile, identify, updateProfile) và setFallback giữ nguyên signature, nhưng file fallback cần được tải lại — xem Fallback files. Các phương thức của view gồm present, dismiss, setEventHandlers, clearEventHandlers, showDialog, và các event handler onCloseButtonPress, onUrlPress, onCustomAction, onProductSelected, onPurchaseStarted, onPurchaseCompleted, onPurchaseFailed, onRestoreStarted, onRestoreCompleted, onRestoreFailed, onLoadingProductsFailed, onWebPaymentNavigationFinished, và onAndroidSystemBack vẫn giữ nguyên tên như trong v3. Các phương thức onboarding vẫn hoạt động nhưng đã bị deprecated — xem Onboarding API deprecation. Một số hành vi mặc định đã thay đổi — xem Default behavior changes.
Phiên bản tối thiểu
Yêu cầu runtime không thay đổi so với v3.16+: iOS 15.0, Android minSdk 24 và Capacitor 8. Không cần thay đổi deployment target.
Có thêm một yêu cầu build mới: Xcode 26 trở lên — SDK Adapty iOS native đi kèm với bản phát hành này sử dụng Swift tools 6.2.
Cài đặt
Cập nhật package
npm install @adapty/capacitor@latest
Sau đó đồng bộ các native project:
npx cap sync
iOS: Chỉ dùng Swift Package Manager
Repo spec của CocoaPods sẽ chuyển sang chế độ chỉ đọc vào tháng 12 năm 2026, vì vậy kể từ v4, AdaptyCapacitor.podspec đã bị xóa và SDK chỉ cài đặt trên iOS thông qua Swift Package Manager (SPM). Dự án iOS của ứng dụng bạn phải sử dụng tích hợp SPM của Capacitor:
- Ứng dụng mới: thêm platform iOS với package manager SPM:
npx cap add ios --packagemanager SPM
- Ứng dụng đang dùng CocoaPods: migrate dự án iOS theo hướng dẫn của Capacitor về việc dùng SPM trong dự án hiện có.
Xem Cài đặt Adapty SDK để biết toàn bộ các bước thiết lập.
⚠️ Adapty Attribution bị tắt theo mặc định
Nếu bạn đang dùng Adapty Attribution và cập nhật lên SDK 4.1.1 mà không bật tính năng này, mọi thứ sẽ âm thầm bị lỗi — lượt cài đặt ngừng được ghi nhận mà không có bất kỳ cảnh báo nào.
Trong các phiên bản trước, SDK tự động đăng ký lượt cài đặt cho Adapty Attribution. Bắt đầu từ SDK phiên bản 4.1.1, tính năng này bị tắt theo mặc định: SDK không đăng ký lượt cài đặt, các sự kiện 'onInstallationDetailsSuccess' và 'onInstallationDetailsFail' sẽ không bao giờ được kích hoạt, và getCurrentInstallationStatus trả về trạng thái not_available.
Nếu bạn sử dụng Adapty Attribution, hãy bật tính năng này khi kích hoạt SDK:
await adapty.activate({
apiKey: 'YOUR_PUBLIC_SDK_KEY',
params: {
+ adaptyAttributionEnabled: true,
},
});
Nếu bạn không sử dụng Adapty Attribution, không cần thay đổi gì.
Tải flow
getPaywall → getFlow
Kiểu trả về thay đổi từ AdaptyPaywall sang AdaptyFlow, và tùy chọn locale chuyển từ lệnh gọi fetch sang createFlowView; đối với paywall tùy chỉnh, tất cả các locale được trả về trong flow.remoteConfigs:
- const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' });
+ const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' });
+ const view = await createFlowView(flow, { locale: 'en' });
locale vẫn là tùy chọn trong createFlowView: bỏ qua nó thì view sẽ hiển thị bằng en, hoặc bằng ngôn ngữ mặc định của flow khi flow không có en. Do cơ chế dự phòng này, view có thể hiển thị bằng ngôn ngữ khác với ngôn ngữ bạn yêu cầu — thuộc tính FlowViewController.locale mới sẽ cho biết ngôn ngữ thực sự được sử dụng. Xem Localizations và mã locale.
getPaywallForDefaultAudience được đổi tên theo cách tương tự:
- const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' });
+ const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID' });
getPaywallProducts(paywall) → getPaywallProducts(flow)
getPaywallProducts giữ nguyên tên nhưng giờ nhận vào một AdaptyFlow:
- const products = await adapty.getPaywallProducts({ paywall });
+ const products = await adapty.getPaywallProducts({ flow });
Tệp dự phòng
Định dạng tệp dự phòng đã thay đổi trong phiên bản 4.0, và thay đổi lần nữa trong 4.1.1. Hãy tải lại tệp từ Placements > Fallbacks và đóng gói vào ứng dụng, kể cả khi bạn đã tải về cho bản beta 4.0.
Bước này không gây lỗi build. Nếu bỏ qua, setFallback sẽ từ chối tệp cũ và mọi placement đều mất fallback của mình.
Mô hình dữ liệu
getFlow trả về một AdaptyFlow thay vì AdaptyPaywall, và cấu trúc đối tượng đã thay đổi:
Trường AdaptyPaywall v3 | Trường AdaptyFlow v4 | Hành động |
|---|---|---|
remoteConfig? (đơn) | remoteConfigs?: AdaptyRemoteConfig[] (mảng) | Một flow chứa một remote config cho mỗi ngôn ngữ được cấu hình. Đọc cái phù hợp với người dùng: flow.remoteConfigs?.find((c) => c.lang === 'en'). |
productIdentifiers | flow.paywalls[i].productIdentifiers | Các identifier sản phẩm giờ nằm trên từng biến thể của flow, không phải trên flow. |
products (deprecated trong v3) | đã xóa | Dùng flow.paywalls[i].productIdentifiers, hoặc gọi getPaywallProducts(flow) để lấy đầy đủ sản phẩm. ProductReference đã bị xóa khỏi kiểu public. |
webPurchaseUrl? | flow.paywalls[i].webPurchaseUrl | Chuyển từ flow sang từng biến thể paywall. |
version?: number | flowVersionId?: string | Đổi tên, và kiểu dữ liệu thay đổi từ number sang string. |
requestLocale | đã xóa | Locale không còn là một phần của model nữa. |
| (mới) | paywalls: AdaptyFlowPaywall[] | Mỗi mục là một biến thể paywall trong flow. |
| (mới) | responseCreatedAt: number | Timestamp phản hồi từ server, tính bằng mili giây. |
requestLocale vẫn còn trên AdaptyOnboarding — chỉ có flow model là bỏ nó.
Identifier sản phẩm đã được chuyển từ flow sang từng variation:
- const ids = paywall.productIdentifiers;
+ const ids = flow.paywalls[0].productIdentifiers;
Nếu code của bạn vẫn đang đọc paywall.products — đã deprecated từ v3 và hiện đã bị xóa — hãy chuyển sang productIdentifiers, hoặc gọi getPaywallProducts(flow) khi bạn cần đầy đủ sản phẩm thay vì chỉ identifier.
Phương thức Web Paywall
openWebPaywall và createWebPaywallUrl giữ nguyên tên, nhưng tùy chọn paywallOrProduct giờ nhận một AdaptyFlowPaywall (biến thể flow) thay vì AdaptyPaywall. Bạn vẫn có thể truyền vào AdaptyPaywallProduct. Hãy kiểm tra flow.paywalls không rỗng trước khi đọc phần tử đầu tiên:
const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' });
- await adapty.openWebPaywall({ paywallOrProduct: paywall });
+ await adapty.openWebPaywall({ paywallOrProduct: flow.paywalls[0] });
Theo dõi lượt xem flow
logShowPaywall → logShowFlow
logShowPaywall được đổi tên thành logShowFlow và giờ nhận vào một AdaptyFlow. Sự kiện vẫn được ghi lại theo cùng một variation, vì vậy các chỉ số funnel và A/B test hiện có vẫn hoạt động bình thường mà không cần thay đổi trên dashboard.
- await adapty.logShowPaywall({ paywall });
+ await adapty.logShowFlow({ flow });
Giống như trong v3, bạn không cần gọi phương thức này khi hiển thị các flow hoặc paywall được render bởi Adapty — Adapty tự động theo dõi những lượt xem đó.
Hiển thị flows
createPaywallView → createFlowView
Đổi tên hàm factory và truyền vào AdaptyFlow. Controller trả về được đổi tên từ PaywallViewController thành FlowViewController, nhưng các phương thức của nó (present, dismiss, setEventHandlers, clearEventHandlers, và showDialog) vẫn giữ nguyên. Kiểu params được đổi tên từ CreatePaywallViewParamsInput thành CreateFlowViewParamsInput:
- import { createPaywallView } from '@adapty/capacitor';
+ import { createFlowView } from '@adapty/capacitor';
- const view = await createPaywallView(paywall);
+ const view = await createFlowView(flow);
await view.present();
Flow view chỉ dùng một lần: sau khi bạn gọi dismiss(), view sẽ bị hủy và các event handler của nó sẽ bị xóa, vì vậy hãy gọi lại createFlowView nếu muốn hiển thị flow thêm một lần nữa.
Các tham số mới
CreateFlowViewParamsInput giữ nguyên tất cả các tham số của v3 (prefetchProducts, loadTimeoutMs, customTags, customTimers, customAssets, productPurchaseParams) và bổ sung thêm ba tham số:
customTimers vẫn tồn tại, nhưng chỉ ảnh hưởng đến các paywall được xây dựng bằng Paywall Builder cũ. Bộ đếm thời gian (countdown timer) của một flow chạy dựa trên cài đặt hành vi được thiết lập trong Flow & Paywall Builder, vì vậy flow sẽ bỏ qua bất kỳ giá trị nào bạn truyền vào đây.
| Tham số | Mô tả |
|---|---|
locale | Ngôn ngữ bản địa hóa để hiển thị flow. Tham số này được chuyển từ getPaywall sang đây — xem getPaywall → getFlow. |
customLayoutId | ID tùy chỉnh của một layout trong cấu hình layout của flow. Truyền vào đây để hiển thị layout cụ thể đó thay vì layout mà SDK tự động chọn dựa trên loại thiết bị và kích thước màn hình. Nếu không có layout nào khớp với ID, lệnh gọi sẽ thất bại với lỗi no-view-configuration. Flow & Paywall Builder hiện chưa hỗ trợ gán custom layout ID, vì vậy hãy để trống tham số này. |
android.enableSafeArea | Kiểm soát padding safe-area trên Android ở runtime. Nằm trong khóa android, mặc định là true. |
const view = await createFlowView(flow, {
locale: 'en',
customLayoutId: 'tablet_landscape',
android: { enableSafeArea: true },
});
Xử lý sự kiện
Giao diện event-handler được đổi tên từ EventHandlers sang FlowEventHandlers, và một callback cũng được đổi tên. Phần thân handler hiện tại không cần thay đổi code — chỉ cần đổi tên:
- onRenderingFailed: (error) => { /* … */ },
+ onError: (error) => { /* … */ },
Tất cả các event handler khác vẫn giữ nguyên tên. Chỉ có một handler thay đổi chữ ký: onAppeared nay là (view) thay vì (), trong đó view là một FlowEventView mô tả view vừa xuất hiện — bao gồm cả bản ngôn ngữ mà view đó được xây dựng. Các handler hiện có vẫn hoạt động bình thường, vì chúng bỏ qua tham số mới. Xem Xử lý sự kiện flow & paywall để biết danh sách đầy đủ.
v4 cũng bổ sung một số tính năng bạn có thể tự chọn kích hoạt:
adapty.openWebUrl({ url, openIn })vàadapty.requestAppReview()— các phương thức này hỗ trợ các handler mặc địnhonUrlPressvàonRequestAppReview, giúp xử lý URL và yêu cầu đánh giá ứng dụng ngay từ đầu mà không cần cấu hình thêm. Chỉ gọi trực tiếp khi bạn override các handler đó.- Xử lý mua hàng ở Observer mode bên trong flow thông qua các handler mới
onObserverPurchaseInitiated/onObserverRestoreInitiated. Xem Hiển thị flow trong Observer mode. onAnalytics: (name, params)— các sự kiện analytics mà flow phát ra, bắt đầu với sự kiện xem màn hình cho mỗi màn hình người dùng mở. Xem Theo dõi lượt xem màn hình flow.onRequestPermission: (permission, customArgs)— dành riêng cho các yêu cầu cấp quyền hệ thống (như thông báo đẩy hoặc truy cập camera) từ một flow. Flow hiện chưa kích hoạt yêu cầu cấp quyền, nên bạn chưa cần triển khai phần này.
Riêng ở phiên bản 4.1.1, SDK bổ sung thêm một event cấp SDK (không phải flow handler): 'onPromotedPurchaseReceived', được gửi qua adapty.addListener. Nếu không có listener nào được đăng ký, SDK sẽ tự hoàn tất giao dịch mua được quảng bá; nếu có listener, quyền hoàn tất sẽ được chuyển về ứng dụng của bạn. Xem App Store promoted in-app purchases.
Đổi tên các API attribution bên ngoài
Từ phiên bản SDK 4.1.1, các API dùng để truyền dữ liệu attribution từ nhà cung cấp bên ngoài (Adjust, AppsFlyer, Branch, Tenjin hoặc nhà cung cấp tùy chỉnh) được đổi tên để phù hợp với các SDK gốc. Không có alias deprecated nào, vì vậy các lệnh gọi hiện tại sẽ ngừng hoạt động cho đến khi bạn đổi tên chúng:
| Trước 4.1.1 | 4.1.1 |
|---|---|
adapty.updateAttribution({ attribution, source }) | adapty.updateExternalAttribution({ attribution, provider }) |
AttributionSource | AdaptyExternalAttributionProvider |
AdaptyProfile.appliedAttributionSources | AdaptyProfile.appliedExternalAttributionProviders |
updateAttribution → updateExternalAttribution
Phương thức được đổi tên và tùy chọn source của nó được đổi thành provider. Dữ liệu attribution vẫn là một object thông thường:
- await adapty.updateAttribution({ attribution, source: 'adjust' });
+ await adapty.updateExternalAttribution({ attribution, provider: 'adjust' });
AttributionSource → AdaptyExternalAttributionProvider
Kiểu provider được đổi tên. Nó vẫn là một union mở — các giá trị được định nghĩa sẵn là 'apple_search_ads', 'adjust', 'appsflyer', 'branch', và 'tenjin', và bất kỳ chuỗi nào khác đều được chấp nhận, vì vậy một provider mà Adapty thêm sau này sẽ hoạt động mà không cần cập nhật SDK:
- import type { AttributionSource } from '@adapty/capacitor';
+ import type { AdaptyExternalAttributionProvider } from '@adapty/capacitor';
AdaptyProfile.appliedAttributionSources → appliedExternalAttributionProviders
Thuộc tính profile liệt kê các nhà cung cấp attribution đã áp dụng cho hồ sơ người dùng được đổi tên, và kiểu phần tử của nó cũng thay đổi theo:
- if (profile.appliedAttributionSources?.includes('apple_search_ads')) {
+ if (profile.appliedExternalAttributionProviders?.includes('apple_search_ads')) {
// Apple Ads attribution has been applied
}
Code đọc giá trị này cần được cập nhật — xem Hiển thị paywall được nhắm mục tiêu bởi Apple Ads.
In-app purchase được quảng bá trên App Store
Trước phiên bản 4.1.1, một in-app purchase được quảng bá trên trang sản phẩm App Store của bạn sẽ tự động hoàn tất và Adapty sẽ ghi lại giao dịch đó, nhưng ứng dụng của bạn không có cách nào để chặn nó. Phiên bản 4.1.1 bổ sung hook đó, vì vậy đây là một tính năng mới chứ không phải bước migration: nếu không có code của riêng bạn, SDK vẫn sẽ tự động hoàn tất các in-app purchase được quảng bá cho bạn.
Viết code để tự xử lý luồng mua hàng — ví dụ như hiển thị một màn hình trước. Đăng ký listener cho sự kiện 'onPromotedPurchaseReceived' mới, và hoàn tất giao dịch bằng adapty.makePromotedPurchase. Khi listener đó được đăng ký, SDK sẽ không tự động hoàn tất promoted purchase nữa.
Thay đổi hành vi mặc định
Những thay đổi này không gây ra lỗi biên dịch, vì vậy hãy kiểm tra chúng trong thời gian chạy:
onAndroidSystemBack: Mặc định đã thay đổi từ đóng view sang giữ nguyên. Để khôi phục hành vi cũ, hãy trả vềtruetừ handler.onPurchaseCompleted: Mặc định đã thay đổi từ đóng view (trừ khi người dùng hủy mua) sang luôn giữ nguyên. Để khôi phục hành vi cũ, hãy trả vềpurchaseResult.type !== 'user_cancelled'từ handler.onRestoreCompleted: Mặc định đã thay đổi từ đóng view sau khi khôi phục thành công sang giữ nguyên. Để khôi phục hành vi cũ, hãy trả vềtruetừ handler.onUrlPress: Mặc định hiện mở URL thông qua native layer, tuân theo cài đặt trình duyệt in-app hoặc bên ngoài từ dashboard. Ghi đè handler để tự mở URL.- View chỉ dùng một lần: Sau khi gọi
dismiss(), view sẽ bị hủy. Gọi lạicreateFlowViewđể hiển thị flow một lần nữa.
Các API đã bị xóa
Các export đã bị xóa
Các symbol này không còn được export từ @adapty/capacitor nữa. Hãy xóa các import tương ứng:
AdaptyPaywall: DùngAdaptyFlowvàAdaptyFlowPaywallthay thế.ProductReference: DùngAdaptyProductIdentifier, đọc từflow.paywalls[i].productIdentifiers.AdaptyPaywallBuilder: Đã bị xóa. Flow và paywall được render trực tiếp trên thiết bị.AdaptyAndroidSubscriptionUpdateParameters: Dùng cấu trúc tham số mua hàngandroidlồng nhau (xem bên dưới).
activate: lockMethodsUntilReady
lockMethodsUntilReady (đã bị deprecated và không hoạt động từ v3) đã được xóa. Hãy xóa nó khỏi lời gọi activate — giữ lại sẽ không thể biên dịch:
- await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY', params: { lockMethodsUntilReady: true } });
+ await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY' });
makePurchase: Tham số Android
Kiểu dữ liệu phẳng (flat) đã bị deprecated của MakePurchaseParamsInput dành cho Android đã bị xóa — chỉ còn dạng lồng nhau (nested). Hãy chuyển các tham số mua hàng Android vào params: { android: { ... } }. Xem Thực hiện mua hàng để xem ví dụ đầy đủ.
Onboarding API không còn được hỗ trợ
Onboarding API cũ đã bị deprecated trong v4, thay thế bằng Flow & Paywall Builder. API này vẫn hoạt động nhưng sẽ bị xóa trong phiên bản tương lai, vì vậy hãy lên kế hoạch migrate các onboarding của bạn sang Flow & Paywall Builder.
Các symbol đã bị deprecated: getOnboarding, getOnboardingForDefaultAudience, createOnboardingView và OnboardingViewController.