---
title: "Migrate Adapty Android SDK lên phiên bản 4.0"
description: "Migrate lên Adapty Android SDK v4.0 (beta) bằng cách thay thế các API paywall bằng API flow, tương thích với cả Flow Builder và Paywall Builder."
---

Adapty Android SDK 4.0 (beta) giới thiệu flows và đổi tên các API paywall tương ứng. Các API mới hoạt động với cả Flow Builder mới và Paywall Builder hiện có — không cần thay đổi cấu hình nào trên Adapty Dashboard.
## Tham chiếu nhanh \{#quick-reference\}
| v3 | v4 |
|---|---|
| `Adapty.getPaywall(placementId, locale)` | `Adapty.getFlow(placementId)` |
| `Adapty.getPaywallForDefaultAudience(placementId, locale)` | `Adapty.getFlowForDefaultAudience(placementId)` |
| `AdaptyUI.getViewConfiguration(paywall)` | `AdaptyUI.getFlowConfiguration(flow, locale)` |
| `AdaptyUI.LocalizedViewConfiguration` | `AdaptyUI.FlowConfiguration` |
| `Adapty.getPaywallProducts(paywall)` | `Adapty.getPaywallProducts(flow)` |
| `Adapty.logShowPaywall(paywall)` | `Adapty.logShowFlow(flow)` |
| `AdaptyPaywall` | `AdaptyFlow` |
| `AdaptyUI.getPaywallView(...)` | `AdaptyUI.getFlowView(...)` |
| `AdaptyPaywallView` | `AdaptyFlowView` |
| `AdaptyPaywallScreen` (Compose) | `AdaptyFlowScreen` |
| `showPaywall(...)` | `showFlow(...)` |
| `AdaptyPaywallInsets` | `AdaptyFlowInsets` |
| `AdaptyUiEventListener` | `AdaptyFlowEventListener` |
| `AdaptyUiDefaultEventListener` | `AdaptyFlowDefaultEventListener` |
| `onPaywallShown` / `onPaywallClosed` | `onFlowShown` / `onFlowClosed` |
| `onRenderingError` | `onError` |
| `Adapty.updateAttribution(attribution, source)` (`source: String`) | `Adapty.updateAttribution(attribution, source)` (`source: AdaptyAttributionSource`) |
| `Adapty.setIntegrationIdentifier(key, value)` | `Adapty.setIntegrationIdentifier(AdaptyIntegrationIdentifier)` |
`AdaptyPaywallProduct` giữ nguyên tên — các sản phẩm vẫn thuộc về một flow, và `getPaywallProducts` giờ nhận vào một `AdaptyFlow`. Các phương thức khác của `AdaptyFlowEventListener` (`onProductSelected`, `onPurchaseStarted`, `onPurchaseFinished`, `onPurchaseFailure`, `onRestoreSuccess`, `onRestoreFailure`, `onActionPerformed`, `onAwaitingPurchaseParams`, `onLoadingProductsFailure`, v.v.) giữ nguyên tên và chữ ký.
## Cài đặt \{#installation\}

Adapty Android SDK 4.0 là phiên bản pre-release, vì vậy bạn phải chỉ định chính xác phiên bản thay vì dùng dải phiên bản động — đặt phiên bản `adapty-bom` thành `4.0.0-beta.1` và đồng bộ dự án. BOM sẽ tự động xác định phiên bản `android-sdk` và `android-ui` tương ứng cho bạn. Xem [Cài đặt Adapty SDK](sdk-installation-android) để biết cách khai báo dependency.
## Các API đã bị xóa và không còn được hỗ trợ \{#removed-and-deprecated-apis\}

- **`Adapty.makePurchase(activity, product, subscriptionUpdateParams, isOfferPersonalized, callback)`** — đã bị xóa. Overload này đã bị deprecated từ v3. Thay vào đó, hãy truyền các tùy chọn tương tự thông qua `AdaptyPurchaseParameters`:
```diff showLineNumbers
- Adapty.makePurchase(activity, product, subscriptionUpdateParams, isOfferPersonalized) { result -> /* ... */ }
+ val params = AdaptyPurchaseParameters.Builder()
+     .withSubscriptionUpdateParams(subscriptionUpdateParams)
+     .withOfferPersonalized(isOfferPersonalized)
+     .build()
+ Adapty.makePurchase(activity, product, params) { result -> /* ... */ }
```

- **Onboardings đã bị deprecated.** `AdaptyUI.getOnboardingView` và `AdaptyUI.getOnboardingConfiguration` được đánh dấu `@Deprecated` trong 4.0 — hãy migrate các onboarding sang flow được xây dựng trong [Flow Builder](adapty-flow-builder).
## Tải flows \{#fetching-flows\}
### getPaywall + getViewConfiguration → getFlow + getFlowConfiguration

Kiểu trả về của lệnh fetch thay đổi từ `AdaptyPaywall` sang `AdaptyFlow`, và trình tải cấu hình được đổi tên từ `AdaptyUI.getViewConfiguration` thành `AdaptyUI.getFlowConfiguration` (trả về `AdaptyUI.FlowConfiguration` thay vì `AdaptyUI.LocalizedViewConfiguration`). Tham số `locale` được chuyển ra khỏi lệnh fetch và đưa vào `getFlowConfiguration`:
```diff showLineNumbers
- Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") { result ->
+ Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
      if (result is AdaptyResult.Success) {
-         val paywall = result.value
-         if (!paywall.hasViewConfiguration) return@getPaywall
-         AdaptyUI.getViewConfiguration(paywall) { configResult ->
+         val flow = result.value
+         if (!flow.hasViewConfiguration) return@getFlow
+         AdaptyUI.getFlowConfiguration(flow, locale = "en") { configResult ->
              if (configResult is AdaptyResult.Success) {
                  val flowConfiguration = configResult.value
              }
          }
      }
  }
```

### getPaywallProducts(paywall) → getPaywallProducts(flow)

`getPaywallProducts` hiện nhận một `AdaptyFlow` được trả về bởi `Adapty.getFlow`:

```diff showLineNumbers
- Adapty.getPaywallProducts(paywall) { result -> /* products */ }
+ Adapty.getPaywallProducts(flow) { result -> /* products */ }
```
## Theo dõi lượt xem flow \{#tracking-flow-views\}
### logShowPaywall → logShowFlow

`logShowPaywall` được đổi tên thành `logShowFlow` và bây giờ nhận vào một `AdaptyFlow` thay vì `AdaptyPaywall`. Sự kiện vẫn được ghi lại dựa trên cùng một biến thể, vì vậy các chỉ số funnel và A/B test hiện tại vẫn hoạt động bình thường mà không cần thay đổi gì trên dashboard.

```diff showLineNumbers
- Adapty.logShowPaywall(paywall)
+ 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 dựng bởi [Flow Builder](adapty-flow-builder) hoặc [Paywall Builder](adapty-paywall-builder) — Adapty tự động theo dõi những lượt xem đó.
## Hiển thị flow \{#displaying-flows\}
### getPaywallView / AdaptyPaywallView → getFlowView / AdaptyFlowView \{#getpaywallview--adaptypayallview--getflowview--adaptyflowview\}

Đổi tên phương thức factory và kiểu view, đồng thời truyền vào `AdaptyUI.FlowConfiguration`:

```diff showLineNumbers
- val paywallView = AdaptyUI.getPaywallView(
-     activity,
-     viewConfiguration,
-     products,
-     eventListener,
- )
+ val flowView = AdaptyUI.getFlowView(
+     activity,
+     flowConfiguration,
+     products,
+     eventListener,
+ )
```

Nếu bạn tạo view trực tiếp, phương thức show cũng được đổi tên:
```diff showLineNumbers
- val paywallView = AdaptyPaywallView(activity)
- paywallView.showPaywall(viewConfiguration, products, eventListener)
+ val flowView = AdaptyFlowView(activity)
+ flowView.showFlow(flowConfiguration, products, eventListener)
```

Trong XML layouts, cập nhật thẻ view:

```diff showLineNumbers
- <com.adapty.ui.AdaptyPaywallView ... />
+ <com.adapty.ui.AdaptyFlowView ... />
```
Tham số tùy chọn `personalizedOfferResolver` đã bị xóa khỏi `getFlowView` / `showFlow` / `AdaptyFlowScreen`. Để chỉ định giá cá nhân hóa, hãy thiết lập theo từng sản phẩm thông qua `onAwaitingPurchaseParams` (`AdaptyPurchaseParameters.Builder().withOfferPersonalized(true)`). Một tham số tùy chọn mới `customAssets` cho phép bạn ghi đè hình ảnh và video tại runtime — xem [Tùy chỉnh assets](android-get-pb-paywalls#customize-assets).
### AdaptyPaywallScreen → AdaptyFlowScreen

Trong Jetpack Compose, đổi tên composable và cập nhật tham số cấu hình:

```diff showLineNumbers
- AdaptyPaywallScreen(
-     viewConfiguration,
+ AdaptyFlowScreen(
+     flowConfiguration,
      products,
      eventListener,
  )
```
## Xử lý sự kiện \{#handling-events\}

Event listener được đổi tên từ `AdaptyUiEventListener` thành `AdaptyFlowEventListener` (và `AdaptyUiDefaultEventListener` thành `AdaptyFlowDefaultEventListener`). Hầu hết các tên phương thức không thay đổi; các callback vòng đời và rendering được đổi tên:
```diff showLineNumbers
- class YourListener : AdaptyUiDefaultEventListener() {
+ class YourListener : AdaptyFlowDefaultEventListener() {

-     override fun onPaywallShown(context: Context) {}
-     override fun onPaywallClosed() {}
+     override fun onFlowShown(context: Context) {}
+     override fun onFlowClosed() {}

-     override fun onRenderingError(error: AdaptyError, context: Context) {}
+     override fun onError(error: AdaptyError, context: Context) {}
  }
```

Phần thân handler hiện có không cần thay đổi code — chỉ cần đổi tên kiểu và các override. `onError` sẽ kích hoạt cho cùng các lỗi render như `onRenderingError` đã làm, cộng thêm các lỗi runtime không liên quan đến mua hàng. Xem [Xử lý sự kiện flow & paywall](android-handling-events) để biết danh sách đầy đủ các callback.
## Mã định danh attribution và tích hợp \{#attribution-and-integration-identifiers\}
### updateAttribution

Tham số `source` thay đổi từ `String` sang kiểu `AdaptyAttributionSource` mới, và `attribution` hiện là `Map<String, Any>` (cũng có thể dùng overload `String` dạng JSON). Sử dụng một trong các nguồn được định nghĩa sẵn:

```diff showLineNumbers
- Adapty.updateAttribution(attribution, "appsflyer") { error -> /* handle the error */ }
+ Adapty.updateAttribution(attribution, AdaptyAttributionSource.APPSFLYER) { error -> /* handle the error */ }
```
Các nguồn được định sẵn: `AdaptyAttributionSource.APPLE_ADS`, `.ADJUST`, `.APPSFLYER`, `.BRANCH`, `.TENJIN`. Với bất kỳ nguồn nào khác, hãy tạo từ một chuỗi: `AdaptyAttributionSource("your_source")`.
### setIntegrationIdentifier

`setIntegrationIdentifier(key, value)` được thay thế bằng một phương thức nhận một hoặc nhiều giá trị `AdaptyIntegrationIdentifier`. Hãy dùng các hằng số `Key` được định nghĩa sẵn thay vì chuỗi key thô:

```diff showLineNumbers
- Adapty.setIntegrationIdentifier("appsflyer_id", appsFlyerId) { error -> /* handle the error */ }
+ Adapty.setIntegrationIdentifier(
+     AdaptyIntegrationIdentifier(AdaptyIntegrationIdentifier.Key.APPSFLYER_ID, appsFlyerId)
+ ) { error -> /* handle the error */ }
```

Bạn có thể đặt nhiều identifier trong một lần gọi:
```kotlin showLineNumbers
Adapty.setIntegrationIdentifier(
    listOf(
        AdaptyIntegrationIdentifier(AdaptyIntegrationIdentifier.Key.APPSFLYER_ID, appsFlyerId),
        AdaptyIntegrationIdentifier(AdaptyIntegrationIdentifier.Key.ADJUST_DEVICE_ID, adjustDeviceId),
    )
) { error -> /* handle the error */ }
```

Thay mỗi chuỗi key cũ bằng hằng số `Key` tương ứng:
| v3 key | v4 `AdaptyIntegrationIdentifier.Key` |
|---|---|
| `"adjust_device_id"` | `ADJUST_DEVICE_ID` |
| `"airbridge_device_id"` | `AIRBRIDGE_DEVICE_ID` |
| `"amplitude_user_id"` | `AMPLITUDE_USER_ID` |
| `"amplitude_device_id"` | `AMPLITUDE_DEVICE_ID` |
| `"appmetrica_device_id"` | `APPMETRICA_DEVICE_ID` |
| `"appmetrica_profile_id"` | `APPMETRICA_PROFILE_ID` |
| `"appsflyer_id"` | `APPSFLYER_ID` |
| `"branch_id"` | `BRANCH_ID` |
| `"facebook_anonymous_id"` | `FACEBOOK_ANONYMOUS_ID` |
| `"firebase_app_instance_id"` | `FIREBASE_APP_INSTANCE_ID` |
| `"mixpanel_user_id"` | `MIXPANEL_USER_ID` |
| `"one_signal_subscription_id"` | `ONE_SIGNAL_SUBSCRIPTION_ID` |
| `"one_signal_player_id"` | `ONE_SIGNAL_PLAYER_ID` |
| `"posthog_distinct_user_id"` | `POSTHOG_DISTINCT_USER_ID` |
| `"pushwoosh_hwid"` | `PUSHWOOSH_HWID` |
| `"tenjin_analytics_installation_id"` | `TENJIN_ANALYTICS_INSTALLATION_ID` |