---
title: "Cài đặt & cấu hình Flutter SDK"
description: "Hướng dẫn từng bước cài đặt Adapty SDK trên Flutter cho các ứng dụng dựa trên gói đăng ký."
---

Adapty SDK gồm hai module chính để tích hợp liền mạch vào ứng dụng Flutter của bạn:

- **Core Adapty**: SDK cốt lõi, bắt buộc phải có để Adapty hoạt động đúng trong ứng dụng.
- **AdaptyUI**: Module này cần thiết nếu bạn sử dụng [Adapty Paywall Builder](adapty-paywall-builder) — công cụ no-code thân thiện để tạo paywall đa nền tảng một cách dễ dàng.

:::tip
Muốn xem ví dụ thực tế về cách tích hợp Adapty SDK vào ứng dụng di động? Hãy xem [ứng dụng mẫu](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example) của chúng tôi, minh họa toàn bộ quá trình cài đặt, bao gồm hiển thị paywall, thực hiện mua hàng và các chức năng cơ bản khác.
:::

## Yêu cầu \{#requirements\}

Adapty SDK hỗ trợ iOS 13.0+, nhưng cần iOS 15.0+ để hoạt động đúng với các paywall được tạo trong Paywall Builder.

:::info
Adapty tương thích với Google Play Billing Library đến phiên bản 8.x. Mặc định, Adapty hoạt động với Google Play Billing Library v7.0.0, nhưng nếu bạn muốn sử dụng phiên bản mới hơn, bạn có thể thêm thủ công [dependency](https://developer.android.com/google/play/billing/integrate#dependency).
:::

---
no_index: true
---
import Callout from '../../../components/Callout.astro';

<Callout type="info">
Cài đặt SDK là bước 5 trong quá trình thiết lập Adapty. Trước khi các giao dịch mua hàng hoạt động trong ứng dụng, bạn cần kết nối ứng dụng với các cửa hàng, sau đó tạo sản phẩm, paywall và placement trong Adapty Dashboard. [Hướng dẫn quickstart](quickstart) sẽ hướng dẫn bạn qua tất cả các bước cần thiết.
</Callout>

## Cài đặt Adapty SDK \{#install-adapty-sdk\}

[![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Flutter.svg?style=flat&logo=flutter)](https://github.com/adaptyteam/AdaptySDK-Flutter/releases)

1. Thêm Adapty vào file `pubspec.yaml` của bạn:

   ```yaml showLineNumbers title="pubspec.yaml"
   dependencies: 
     adapty_flutter: ^<the latest SDK version>
   ```

2. Chạy lệnh sau để cài đặt các dependency:

   ```bash showLineNumbers title="Terminal"
   flutter pub get
   ```

3. Import Adapty SDK vào ứng dụng của bạn:

   ```dart showLineNumbers title="main.dart"
   import 'package:adapty_flutter/adapty_flutter.dart';
   ```

## Kích hoạt module Adapty của Adapty SDK \{#activate-adapty-module-of-adapty-sdk\}

Kích hoạt Adapty SDK trong code ứng dụng của bạn.

:::note
Adapty SDK chỉ cần được kích hoạt một lần trong ứng dụng.
:::

Để lấy **Public SDK Key**:

1. Truy cập Adapty Dashboard và điều hướng đến [**App settings → General**](https://app.adapty.io/settings/general).
2. Trong phần **Api keys**, sao chép **Public SDK Key** (KHÔNG phải Secret Key).
3. Thay thế `"YOUR_PUBLIC_SDK_KEY"` trong code.

Hoặc lấy theo cách lập trình, sử dụng [Adapty CLI](developer-cli):

```
npm install -g adapty
adapty auth login
adapty apps list
```

Hoặc, trực tiếp:

```
npx adapty auth login
adapty apps list
```

- Đảm bảo bạn sử dụng **Public SDK key** để khởi tạo Adapty, **Secret key** chỉ nên dùng cho [server-side API](getting-started-with-server-side-api).
- **SDK keys** là duy nhất cho mỗi ứng dụng, vì vậy nếu bạn có nhiều ứng dụng, hãy đảm bảo chọn đúng key.

```dart showLineNumbers title="main.dart"

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    _initializeAdapty();

    super.initState();
  }

  Future<void> _initializeAdapty() async {
    try {
      await Adapty().activate(
        configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY'),
      );
    } catch (e) {
      // handle the error
    }
  }

  Widget build(BuildContext context) {
    return Text("Hello");
  }
}
```

:::important
Hãy đợi `activate` hoàn tất trước khi gọi bất kỳ phương thức nào khác của Adapty SDK. Xem [Thứ tự gọi trong Flutter SDK](flutter-sdk-call-order) để biết toàn bộ trình tự.
:::

Bây giờ hãy thiết lập paywall trong ứng dụng của bạn:

- Nếu bạn dùng [Adapty Paywall Builder](adapty-paywall-builder), trước tiên hãy [kích hoạt module AdaptyUI](#activate-adaptyui-module-of-adapty-sdk) bên dưới, sau đó làm theo [hướng dẫn nhanh Paywall Builder](flutter-quickstart-paywalls).
- Nếu bạn tự xây dựng giao diện paywall, hãy xem [hướng dẫn nhanh cho paywall tùy chỉnh](flutter-quickstart-manual).

## Kích hoạt module AdaptyUI của Adapty SDK \{#activate-adaptyui-module-of-adapty-sdk\}

Nếu bạn dự định sử dụng [Paywall Builder](adapty-paywall-builder) và đã [cài đặt module AdaptyUI](sdk-installation-flutter#install-adapty-sdk), bạn cũng cần kích hoạt AdaptyUI:

:::note
Các dependency liên quan đến AdaptyUI được liên kết vào ứng dụng bất kể AdaptyUI có được kích hoạt hay không.
:::

:::important
Trong code của bạn, phải kích hoạt module Adapty cốt lõi trước khi kích hoạt AdaptyUI.
:::

```dart showLineNumbers title="main.dart"
await Adapty().activate(
  configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
    ..withActivateUI(true), // This automatically activates AdaptyUI
);
```

## Thiết lập tùy chọn \{#optional-setup\}

### Ghi log \{#logging\}

#### Thiết lập hệ thống ghi log \{#set-up-the-logging-system\}

Adapty ghi lại các lỗi và thông tin quan trọng để giúp bạn hiểu những gì đang xảy ra. Các mức log có sẵn như sau:

| Mức                      | Mô tả                                                                                                                     |
| :----------------------- | :------------------------------------------------------------------------------------------------------------------------ |
| `AdaptyLogLevel.none`    | Không ghi log gì cả. Giá trị mặc định                                                                                    |
| `AdaptyLogLevel.error`   | Chỉ ghi log các lỗi                                                                                                       |
| `AdaptyLogLevel.warn`    | Ghi log các lỗi và thông báo từ SDK không gây ra lỗi nghiêm trọng nhưng đáng chú ý.                                      |
| `AdaptyLogLevel.info`    | Ghi log các lỗi, cảnh báo và các thông báo thông tin khác nhau.                                                           |
| `AdaptyLogLevel.verbose` | Ghi log mọi thông tin bổ sung có thể hữu ích trong quá trình debug, như lời gọi hàm, truy vấn API, v.v.                  |

Bạn có thể đặt mức log trong ứng dụng trước khi cấu hình Adapty:

```dart showLineNumbers title="main.dart"
// Set log level before activation. 
// 'verbose' is recommended for development and the first production release
await Adapty().setLogLevel(AdaptyLogLevel.verbose);

// Or set it during configuration
await Adapty().activate(
  configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
    ..withLogLevel(AdaptyLogLevel.verbose),
);
```

### Chính sách dữ liệu \{#data-policies\}

Adapty không lưu trữ dữ liệu cá nhân của người dùng trừ khi bạn gửi dữ liệu đó một cách tường minh, nhưng bạn có thể áp dụng thêm các chính sách bảo mật dữ liệu để tuân thủ quy định của cửa hàng hoặc quốc gia.

#### Tắt thu thập và chia sẻ địa chỉ IP \{#disable-ip-address-collection-and-sharing\}

Khi kích hoạt module Adapty, đặt `ipAddressCollectionDisabled` thành `true` để tắt việc thu thập và chia sẻ địa chỉ IP của người dùng. Giá trị mặc định là `false`.

Sử dụng tham số này để tăng cường quyền riêng tư người dùng, tuân thủ các quy định bảo vệ dữ liệu theo khu vực (như GDPR hoặc CCPA), hoặc giảm việc thu thập dữ liệu không cần thiết khi các tính năng dựa trên IP không được yêu cầu cho ứng dụng của bạn.

```dart showLineNumbers title="main.dart"
await Adapty().activate(
  configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
    ..withIpAddressCollectionDisabled(true),
);
```

#### Tắt thu thập và chia sẻ ID quảng cáo \{#disable-advertising-id-collection-and-sharing\}

Khi kích hoạt module Adapty, đặt `appleIdfaCollectionDisabled` (iOS) hoặc `googleAdvertisingIdCollectionDisabled` (Android) thành `true` để tắt việc thu thập các identifier quảng cáo. Giá trị mặc định là `false`.

Sử dụng tham số này để tuân thủ chính sách App Store/Play Store, tránh kích hoạt lời nhắc App Tracking Transparency, hoặc khi ứng dụng của bạn không cần attribution quảng cáo hay analytics dựa trên ID quảng cáo.

```dart showLineNumbers title="main.dart"
await Adapty().activate(
  configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
    ..withAppleIdfaCollectionDisabled(true)      // iOS
    ..withGoogleAdvertisingIdCollectionDisabled(true), // Android
);
```

#### Thiết lập cấu hình cache media cho AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\}

Module được kích hoạt tự động cùng với Adapty SDK. Nếu bạn không sử dụng Paywall Builder và muốn tắt module AdaptyUI, hãy truyền `withActivateUI(false)` trong quá trình kích hoạt.

Mặc định, AdaptyUI lưu cache media (như hình ảnh và video) để cải thiện hiệu suất và giảm sử dụng mạng. Bạn có thể tùy chỉnh cài đặt cache bằng cách cung cấp cấu hình riêng.

Sử dụng `withMediaCacheConfiguration` để ghi đè kích thước cache và thời gian hiệu lực mặc định. Đây là tùy chọn — nếu bạn không gọi phương thức này, các giá trị mặc định sẽ được dùng (100MB dung lượng đĩa, không giới hạn số lượng trong bộ nhớ). Tuy nhiên, nếu bạn sử dụng cấu hình, tất cả các tham số phải được bao gồm.

```dart showLineNumbers title="main.dart"

final mediaCacheConfig = AdaptyUIMediaCacheConfiguration(
  memoryStorageTotalCostLimit: 200 * 1024 * 1024, // 200 MB
  memoryStorageCountLimit: 2147483647, // max int value
  diskStorageSizeLimit: 200 * 1024 * 1024, // 200 MB
);

await Adapty().activate(
  configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
    ..withMediaCacheConfiguration(mediaCacheConfig),
);
```

**Tham số:**

| Tham số                  | Bắt buộc | Mô tả                                                                       |
|-------------------------|----------|-----------------------------------------------------------------------------|
| memoryStorageTotalCostLimit | tùy chọn | Tổng kích thước cache trong bộ nhớ tính bằng byte. Mặc định là 100 MB.      |
| memoryStorageCountLimit     | tùy chọn | Giới hạn số lượng item trong bộ nhớ. Mặc định là giá trị int tối đa.        |
| diskStorageSizeLimit        | tùy chọn | Giới hạn kích thước file trên đĩa tính bằng byte. Mặc định là 100 MB.       |

### Bật mức độ truy cập cục bộ (Android) \{#enable-local-access-levels-android\}

Mặc định, [mức độ truy cập cục bộ](local-access-levels) được bật trên iOS và tắt trên Android. Để bật trên Android, đặt `withGoogleLocalAccessLevelAllowed` thành `true`:

```dart showLineNumbers title="main.dart"
await Adapty().activate(
  configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
    ..withGoogleLocalAccessLevelAllowed(true),
);
```

### Xóa dữ liệu khi khôi phục backup \{#clear-data-on-backup-restore\}

Khi `clearDataOnBackup` được đặt thành `true`, SDK sẽ phát hiện khi ứng dụng được khôi phục từ backup iCloud và xóa toàn bộ dữ liệu SDK được lưu cục bộ, bao gồm thông tin hồ sơ người dùng được cache, chi tiết sản phẩm và paywall. SDK sau đó sẽ khởi tạo lại với trạng thái sạch. Giá trị mặc định là `false`.

:::note
Chỉ có cache SDK cục bộ bị xóa. Lịch sử giao dịch với Apple và dữ liệu người dùng trên máy chủ Adapty vẫn không thay đổi.
:::

```dart showLineNumbers title="main.dart"
await Adapty().activate(
  configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
    ..withClearDataOnBackup(true) // default – false 
);
```

## Xử lý sự cố \{#troubleshooting\}

#### Quy tắc backup Android (cấu hình Auto Backup) \{#android-backup-rules-auto-backup-configuration\}

Một số SDK (bao gồm Adapty) đi kèm với cấu hình Android Auto Backup riêng. Nếu bạn sử dụng nhiều SDK có định nghĩa backup rules, quá trình merge Android manifest có thể thất bại với lỗi liên quan đến `android:fullBackupContent`, `android:dataExtractionRules`, hoặc `android:allowBackup`.

Triệu chứng lỗi thường gặp: `Manifest merger failed: Attribute application@dataExtractionRules value=(@xml/your_data_extraction_rules)
is also present at [com.other.sdk:library:1.0.0] value=(@xml/other_sdk_data_extraction_rules)`

:::note
Những thay đổi này cần được thực hiện trong thư mục platform Android của bạn (thường nằm trong thư mục `android/` của dự án).
:::

Để khắc phục, bạn cần:

- Yêu cầu manifest merger sử dụng các giá trị của ứng dụng cho các thuộc tính liên quan đến backup.

- Tạo các file backup rule kết hợp rules của Adapty với rules từ các SDK khác.

#### 1. Thêm namespace `tools` vào manifest \{#1-add-the-tools-namespace-to-your-manifest\}

Trong file `AndroidManifest.xml`, hãy đảm bảo thẻ gốc `<manifest>` có chứa tools:

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.app">

    ...
</manifest>
```

#### 2. Ghi đè các thuộc tính backup trong `<application>` \{#2-override-backup-attributes-in-application\}

Trong cùng file `AndroidManifest.xml`, cập nhật thẻ `<application>` để ứng dụng của bạn cung cấp các giá trị cuối cùng và yêu cầu manifest merger thay thế các giá trị từ thư viện:

```xml
<application
android:name=".App"
android:allowBackup="true"
android:fullBackupContent="@xml/sample_backup_rules"           
android:dataExtractionRules="@xml/sample_data_extraction_rules"
tools:replace="android:fullBackupContent,android:dataExtractionRules">

    ...
</application>
```

Nếu có SDK nào cũng đặt `android:allowBackup`, hãy thêm nó vào `tools:replace`:

```xml
tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules"
```

#### 3. Tạo các file backup rules đã merge \{#3-create-merged-backup-rules-files\}

Tạo các file XML trong thư mục `res/xml/` của dự án Android, kết hợp rules của Adapty với rules từ các SDK khác. Android sử dụng các định dạng backup rule khác nhau tùy theo phiên bản OS, vì vậy việc tạo cả hai file đảm bảo tương thích với tất cả các phiên bản Android mà ứng dụng hỗ trợ.

:::note
Các ví dụ dưới đây sử dụng AppsFlyer làm SDK bên thứ ba mẫu. Hãy thay thế hoặc bổ sung rules cho các SDK khác mà bạn đang dùng trong ứng dụng.
:::

**Dành cho Android 12 trở lên** (sử dụng định dạng data extraction rules mới):

```xml title="sample_data_extraction_rules.xml"
<?xml version="1.0" encoding="utf-8"?>
<data-extraction-rules>
    <cloud-backup>
        
        <exclude domain="sharedpref" path="appsflyer-data"/>
        <exclude domain="sharedpref" path="appsflyer-purchase-data"/>
        <exclude domain="database" path="afpurchases.db"/>
        
        <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/>
    </cloud-backup>

    <device-transfer>
        
        <exclude domain="sharedpref" path="appsflyer-data"/>
        <exclude domain="sharedpref" path="appsflyer-purchase-data"/>
        <exclude domain="database" path="afpurchases.db"/>
        <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/>
    </device-transfer>
</data-extraction-rules>
```

**Dành cho Android 11 trở xuống** (sử dụng định dạng full backup content cũ):

```xml title="sample_backup_rules.xml"
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
    
    <exclude domain="sharedpref" path="appsflyer-data"/>

    
    <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/>

#### Mua hàng thất bại sau khi quay lại từ ứng dụng khác trên Android \{#purchases-fail-after-returning-from-another-app-in-android\}

Nếu Activity khởi động flow mua hàng sử dụng `launchMode` không phải mặc định, Android có thể tạo lại hoặc tái sử dụng Activity đó không đúng cách khi người dùng quay lại từ Google Play, ứng dụng ngân hàng hoặc trình duyệt. Điều này có thể khiến kết quả mua hàng bị mất hoặc bị coi là đã hủy.

Để đảm bảo mua hàng hoạt động đúng, chỉ sử dụng launch mode `standard` hoặc `singleTop` cho Activity khởi động flow mua hàng, và tránh các mode khác.

Trong `AndroidManifest.xml`, hãy đảm bảo Activity khởi động flow mua hàng được đặt thành `standard` hoặc `singleTop`:

```xml
<activity
    android:name=".MainActivity"
    android:launchMode="standard" />
```

#### Lỗi build Swift 6 do Podfile ghi đè SWIFT_VERSION \{#swift-6-build-errors-caused-by-podfile-swift_version-override\}

Khi build ứng dụng Flutter cho iOS, bạn có thể thấy lỗi biên dịch Swift 6 trên các pod target của Adapty. Các triệu chứng thường gặp bao gồm lỗi `@Sendable` trong `AdaptyUIBuilderLogic`, thiếu conformance `Sendable` trên các kiểu Adapty, hoặc lỗi actor isolation.

Các pod Adapty khai báo `s.swift_version = '6.0'` và yêu cầu Swift 6 để build. Code ứng dụng của bạn có thể tiếp tục dùng Swift 5 — chỉ các pod target của Adapty (`Adapty`, `AdaptyUI`, `AdaptyUIBuilder`, `AdaptyLogger`, `AdaptyPlugin`) cần được build với Swift 6.

Nguyên nhân phổ biến nhất là hook `post_install` trong `ios/Podfile` ghi đè `SWIFT_VERSION` cho mọi pod target:

```ruby showLineNumbers title="ios/Podfile"
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['SWIFT_VERSION'] = '5.9'
    end
  end
end
```

**Cách khắc phục**: Loại trừ các pod target của Adapty khỏi việc ghi đè:

```ruby showLineNumbers title="ios/Podfile"
post_install do |installer|
  installer.pods_project.targets.each do |target|
    next if %w[Adapty AdaptyUI AdaptyUIBuilder AdaptyLogger AdaptyPlugin].include?(target.name)
    target.build_configurations.each do |config|
      config.build_settings['SWIFT_VERSION'] = '5.9'
    end
  end
end
```

Sau đó chạy `pod install` từ thư mục `ios/` và build lại.

Để kiểm tra, mở `ios/Pods/Pods.xcodeproj`, chọn pod target `Adapty` → **Build Settings** → **Swift Language Version**. Giá trị phải là **Swift 6**.