---
title: "Migrate Adapty Flutter SDK sang v4.1"
description: "Migrate sang Adapty Flutter SDK v4.1: bật Adapty Attribution tường minh, sử dụng các API attribution bên ngoài đã được đổi tên, tải lại file fallback, và xử lý các sản phẩm được quảng bá trên App Store."
---

> **AI agents**: to search Adapty docs faster and with fewer tokens, install the Adapty skill. Claude Code (self-updating via plugin): `claude plugin marketplace add adaptyteam/adapty-skills && claude plugin install adapty-skills@adapty` — other tools: `npx skills add adaptyteam/adapty-skills --all`

Adapty Flutter SDK 4.1 thay đổi cách bật Adapty Attribution, đổi tên các API attribution bên ngoài, và thay đổi định dạng file fallback. Ngoài ra, SDK còn chuyển giao các in-app purchase được quảng bá trên App Store cho ứng dụng của bạn, đồng thời bổ sung cách giữ một flow view tồn tại sau khi đóng nó.

:::warning
Các API đã đổi tên là một thay đổi bất tương thích hoàn toàn. Tên cũ bị xóa hoàn toàn — không có alias deprecated nào để thay thế. Code biên dịch với 4.0.x sẽ lỗi trên 4.1 cho đến khi bạn đổi tên tất cả các call site được liệt kê bên dưới.
:::

Nếu bạn vẫn đang dùng 3.x, hãy bắt đầu với [Migrate sang v4.0](migration-to-flutter-sdk-v4) rồi làm theo hướng dẫn này.

## Tham khảo nhanh \{#quick-reference\}

| v4.0 | v4.1 |
|---|---|
| Adapty Attribution được bật tự động | Adapty Attribution bị tắt theo mặc định; bật bằng `withAdaptyAttributionEnabled(true)` |
| `Adapty().updateAttribution(attribution, source: source)` | `Adapty().updateExternalAttribution(attribution, provider: provider)` |
| `AdaptyAttributionSource` | `AdaptyExternalAttributionProvider`, với giá trị `custom` mới |
| `AdaptyProfile.appliedAttributionSources` | `AdaptyProfile.appliedExternalAttributionProviders` |
| File dự phòng đã tải cho 4.0 | Định dạng file dự phòng mới; tải lại file |
| In-app purchase được quảng bá tự hoàn tất | Ứng dụng của bạn hoàn tất chúng từ `didReceivePromotedPurchaseStream` |
| `dismissFlowView(view)` luôn giải phóng view | `destroy: false` giữ view còn sống để hiển thị lại |

Các API mua hàng, hồ sơ người dùng và trình bày flow vẫn không thay đổi.

## Cài đặt \{#installation\}

Cập nhật `adapty_flutter` lên v4.1 trong `pubspec.yaml` của bạn:

```yaml showLineNumbers title="pubspec.yaml"
dependencies:
  adapty_flutter: 4.1.0
```

Nếu ứng dụng của bạn sử dụng [Kids Mode](kids-mode-flutter), hãy dùng `adapty_flutter_kids` thay thế:

```yaml showLineNumbers title="pubspec.yaml"
dependencies:
  adapty_flutter_kids: 4.1.0
```

Yêu cầu không thay đổi so với 4.0: **Flutter 3.32.0** (Dart 3.8.0) và **iOS 15.0**. Xem [Cài đặt Adapty SDK](sdk-installation-flutter) để biết hướng dẫn cài đặt đầy đủ.

4.1 ghim native iOS SDK vào phiên bản 4.1.3 và native Android SDK vào phiên bản 4.1.1. Bản phát hành iOS cũng sửa lỗi các tham số số trong các sự kiện phân tích flow: trước đây, mọi giá trị `0` và `1` đều được truyền đến `flowViewDidReceiveAnalyticEvent` dưới dạng `false` và `true`.

## ⚠️ Adapty Attribution mặc định bị tắt \{#adapty-attribution-is-disabled-by-default\}

:::warning
Nếu bạn cập nhật lên SDK 4.1 mà không bật tùy chọn này, [Adapty Attribution](user-acquisition) sẽ ngừng hoạt động mà không có cảnh báo — các lượt cài đặt sẽ không được ghi nhận nữa.
:::

Trong phiên bản 4.0 và trước đó, SDK tự động đăng ký lượt cài đặt cho [Adapty Attribution](user-acquisition). Từ phiên bản 4.1 trở đi, tính năng này mặc định bị tắt: SDK không đăng ký lượt cài đặt, `onUpdateInstallationDetailsSuccessStream` và `onUpdateInstallationDetailsFailStream` sẽ không bao giờ phát ra sự kiện, và `getCurrentInstallationStatus` trả về `AdaptyInstallationStatusNotAvailable`.

Nếu bạn sử dụng Adapty Attribution, hãy bật tính năng này khi cấu hình SDK:

```diff showLineNumbers
  await Adapty().activate(
-   configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY'),
+   configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
+     ..withAdaptyAttributionEnabled(true),
  );
```

Nếu bạn không sử dụng Adapty Attribution, không cần thay đổi gì.

## Đổi tên các API attribution bên ngoài \{#renamed-external-attribution-apis\}

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 tùy chỉnh) đã được đổi tên để phù hợp với các SDK gốc.

### updateAttribution → updateExternalAttribution

Phương thức được đổi tên và tham số `source` của nó được đổi thành `provider`. Tham số này giờ nhận một `AdaptyExternalAttributionProvider` thay vì một chuỗi, và dữ liệu attribution vẫn là một map:

```diff showLineNumbers
- await Adapty().updateAttribution(attribution, source: 'adjust');
+ await Adapty().updateExternalAttribution(attribution, provider: AdaptyExternalAttributionProvider.adjust);
```

### AdaptyAttributionSource → AdaptyExternalAttributionProvider

Kiểu provider được đổi tên. Nó vẫn là một wrapper mở trên một chuỗi — các giá trị được định nghĩa sẵn là `appleAds`, `adjust`, `appsflyer`, `branch`, `tenjin`, và một giá trị mới là `custom` dành cho các provider mà Adapty không tích hợp trực tiếp. Bạn có thể khởi tạo từ bất kỳ chuỗi nào, vì vậy khi Adapty thêm provider mới, bạn không cần cập nhật SDK:

```dart showLineNumbers
final provider = AdaptyExternalAttributionProvider('my_provider');
```

### AdaptyProfile.appliedAttributionSources → appliedExternalAttributionProviders

Thuộc tính của hồ sơ người dùng liệt kê các nhà cung cấp attribution được áp dụng cho hồ sơ được đổi tên, và kiểu phần tử của nó cũng thay đổi theo:

```diff showLineNumbers
- if (profile.appliedAttributionSources.contains(AdaptyAttributionSource.appleAds)) {
+ if (profile.appliedExternalAttributionProviders.contains(AdaptyExternalAttributionProvider.appleAds)) {
      // Apple Ads attribution has been applied
  }
```

Trường profile được serialize vẫn giữ nguyên tên `applied_attribution_sources`, vì vậy backend đọc profile thô không cần thay đổi gì. Tuy nhiên, code đọc thuộc tính này thì cần cập nhật — xem [Hiển thị paywall được nhắm mục tiêu bằng Apple Ads](flutter-show-aa-targeted-paywall).

## Tệp dự phòng \{#fallback-files\}

Định dạng của [tệp dự phòng](fallback-flows) đã thay đổi trong SDK 4.1. Hãy tải lại tệp từ **[Placements](https://app.adapty.io/placements)** > **Fallbacks** và đóng gói vào app, dù bạn đã tải tệp cho phiên bản 4.0 trước đó.

:::warning
Bước này không gây lỗi build. Nếu bỏ qua, SDK sẽ từ chối tệp cũ và mọi placement sẽ mất paywall dự phòng.
:::

## ⚠️ In-app purchase được quảng bá giờ sẽ chờ ứng dụng của bạn xử lý \{#promoted-in-app-purchases-now-wait-for-your-app\}

:::warning
Đây là thay đổi hành vi, không phải tính năng mới để bạn tùy ý áp dụng. Ở phiên bản 4.0, một [in-app purchase được quảng bá trên trang sản phẩm App Store của bạn](flutter-making-purchases#promoted-in-app-purchases-from-the-app-store) sẽ tự hoàn tất. Ở phiên bản 4.1, nó chỉ hoàn tất nếu ứng dụng của bạn lắng nghe sự kiện đó. Nếu bạn phát hành 4.1 mà không có đoạn code bên dưới, các giao dịch mua đó sẽ không xảy ra — App Store chuyển sản phẩm cho ứng dụng của bạn, và không có gì xảy ra tiếp theo.
:::

Ở phiên bản 4.0, Adapty ghi nhận promoted purchase như bất kỳ giao dịch nào khác, và app của bạn không có cách nào để chặn nó lại. Phiên bản 4.1 cho phép app của bạn kiểm soát điều này, đồng thời cũng đặt ra trách nhiệm hoàn tất việc mua hàng.

Đăng ký `didReceivePromotedPurchaseStream` và truyền sản phẩm vào `makePromotedPurchase`:

```dart showLineNumbers
Adapty().didReceivePromotedPurchaseStream.listen((product) async {
  try {
    final result = await Adapty().makePromotedPurchase(product: product);
    // process the purchase result
  } on AdaptyError catch (e) {
    // handle the error
  }
});
```

Đăng ký trước khi một promoted purchase có thể đến — trong lúc khởi động ứng dụng, ngay sau `activate`. Stream này là broadcast stream không replay: nếu có sản phẩm được gửi đến mà không có gì đang lắng nghe, sản phẩm đó sẽ bị mất cùng với giao dịch mua.

`makePromotedPurchase` không nhận tham số mua hàng, vì sản phẩm được promote đến từ App Store chứ không phải từ paywall và không mang theo context của paywall. Hàm này trả về cùng kiểu `AdaptyPurchaseResult` như `makePurchase`.

:::warning
Stream này được xây dựng trên StoreKit 2 và yêu cầu **iOS 16.4** trở lên. Trên các phiên bản iOS thấp hơn 16.4 và trên Android, stream sẽ không bao giờ phát ra sự kiện.
:::

Nếu sản phẩm được quảng bá có kèm ưu đãi gói đăng ký, SDK sẽ tự động áp dụng ưu đãi đó khi mua. Ưu đãi được đọc từ App Store purchase intent, tính năng này chỉ khả dụng trên iOS 18.0 trở lên. Trên iOS 16.4–17.x, giao dịch mua sẽ được thực hiện theo giá gốc.

## Giữ flow view hoạt động sau khi đóng \{#keep-a-flow-view-alive-after-dismissing-it\}

`AdaptyUI().dismissFlowView` và `AdaptyUIFlowView.dismiss` chấp nhận cờ `destroy`:

```dart showLineNumbers
await AdaptyUI().dismissFlowView(view, destroy: false);
```

Mặc định là `true`, tức là giải phóng view như trước. Khi dùng `destroy: false`, view vẫn được giữ nguyên, cho phép bạn hiển thị lại và người dùng sẽ quay về đúng màn hình họ đã rời, với trạng thái mà flow đã tích lũy.

View được giữ theo cách này sẽ tồn tại cho đến khi bạn đóng nó với `destroy: true`. Nếu cố hiển thị một view đã bị giải phóng thì sẽ thất bại, vì vậy hãy gọi `createFlowView` lại để hiển thị flow đó thêm lần nữa.

## hasViewConfiguration

`AdaptyFlow.hasViewConfiguration` hiện cũng yêu cầu flow phải mang theo UI schema, vì vậy nó chỉ báo `true` cho flow mà AdaptyUI có thể render. Một flow đến ứng dụng của bạn mà không có schema sẽ báo `false` trong khi phiên bản 4.0 báo `true`. Xem [Lấy cấu hình view](flutter-get-pb-paywalls#fetch-the-view-configuration).