---
title: "Lấy paywall được thiết kế bằng Paywall Builder và cấu hình của nó trong Android SDK"
description: "Tìm hiểu cách lấy PB paywalls trong Adapty để kiểm soát gói đăng ký tốt hơn trong ứng dụng Android của bạn."
---

Sau khi [thiết kế phần giao diện cho paywall](adapty-paywall-builder) bằng Paywall Builder mới trong Adapty Dashboard, bạn có thể hiển thị nó trong ứng dụng mobile của mình. Bước đầu tiên trong quy trình này là lấy paywall gắn với placement cùng cấu hình view của nó như mô tả bên dưới.

:::warning
Paywall Builder mới hoạt động với Android SDK phiên bản 3.0 trở lên.
:::

Lưu ý rằng chủ đề này đề cập đến các paywall được tùy chỉnh bằng Paywall Builder. Nếu bạn đang triển khai paywall theo cách thủ công, vui lòng tham khảo chủ đề [Lấy paywalls và sản phẩm cho remote config paywalls trong ứng dụng mobile](fetch-paywalls-and-products-android).

:::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](sample-apps) của chúng tôi, nơi minh họa toàn bộ quá trình thiết lập, 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.

:::

<details>
   <summary>Trước khi bắt đầu hiển thị paywalls trong ứng dụng mobile của bạn (nhấn để mở rộng)</summary>

1. [Tạo sản phẩm](create-product) trong Adapty Dashboard.
2. [Tạo một paywall và thêm sản phẩm vào đó](create-paywall) trong Adapty Dashboard.
3. [Tạo các placement và thêm paywall vào đó](create-placement) trong Adapty Dashboard.
4. Cài đặt [Adapty SDK](sdk-installation-android) trong ứng dụng mobile của bạn.
</details>

## Lấy paywall được thiết kế bằng Paywall Builder \{#fetch-paywall-designed-with-paywall-builder\}

Nếu bạn đã [thiết kế paywall bằng Paywall Builder](adapty-paywall-builder), bạn không cần lo lắng về việc render nó trong code ứng dụng để hiển thị cho người dùng. Một paywall như vậy chứa cả nội dung cần hiển thị lẫn cách thức hiển thị. Tuy nhiên, bạn vẫn cần lấy ID của nó qua placement, cấu hình view, rồi trình bày nó trong ứng dụng mobile.

Để đảm bảo hiệu suất tốt nhất, việc lấy paywall và [cấu hình view](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) càng sớm càng tốt là rất quan trọng, cho phép đủ thời gian để tải hình ảnh trước khi hiển thị cho người dùng.

Để lấy một paywall, sử dụng phương thức `getPaywall`:

<Tabs groupId="current-os" queryString>

<TabItem value="kotlin" label="Kotlin" default>

```kotlin showLineNumbers

...

Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en", loadTimeout = 10.seconds) { result ->
    when (result) {
        is AdaptyResult.Success -> {
            val paywall = result.value
            // the requested paywall
        }
        is AdaptyResult.Error -> {
            val error = result.error
            // handle the error
        }
    }
}
```
</TabItem>
<TabItem value="java" label="Java" default>

```java showLineNumbers

...

Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", TimeInterval.seconds(10), result -> {
    if (result instanceof AdaptyResult.Success) {
        AdaptyPaywall paywall = ((AdaptyResult.Success<AdaptyPaywall>) result).getValue();
        // the requested paywall
      
    } else if (result instanceof AdaptyResult.Error) {
        AdaptyError error = ((AdaptyResult.Error) result).getError();
        // handle the error
      
    }
});
```
</TabItem>

</Tabs>

Tham số:

| Tham số | Bắt buộc | Mô tả |
|---------|--------|-----------|
| **placementId** | bắt buộc | Định danh của [Placement](placements) mong muốn. Đây là giá trị bạn đã chỉ định khi tạo placement trong Adapty Dashboard. |
| **locale** | <p>tùy chọn</p><p>mặc định: `en`</p> | <p>Định danh của [bản địa hóa paywall](add-paywall-locale-in-adapty-paywall-builder). Tham số này cần là mã ngôn ngữ gồm một hoặc hai thẻ con phân tách bằng ký tự gạch ngang (**-**). Thẻ con đầu tiên là ngôn ngữ, thẻ con thứ hai là vùng.</p><p></p><p>Ví dụ: `en` là tiếng Anh, `pt-br` là tiếng Bồ Đào Nha Brazil.</p><p>Xem [Bản địa hóa và mã locale](localizations-and-locale-codes) để biết thêm thông tin về mã locale và cách chúng tôi khuyến nghị sử dụng.</p> |
| **fetchPolicy** | mặc định: `.reloadRevalidatingCacheData` | <p>Theo mặc định, SDK sẽ cố tải dữ liệu từ server và trả về dữ liệu đã cache trong trường hợp thất bại. Chúng tôi khuyến nghị cách này vì nó đảm bảo người dùng luôn nhận được dữ liệu mới nhất.</p><p></p><p>Tuy nhiên, nếu bạn cho rằng người dùng của mình có kết nối internet không ổn định, hãy cân nhắc sử dụng `.returnCacheDataElseLoad` để trả về dữ liệu đã cache nếu có. Trong trường hợp này, người dùng có thể không nhận được dữ liệu mới nhất tuyệt đối, nhưng sẽ có thời gian tải nhanh hơn, bất kể kết nối internet của họ có chập chờn đến đâu. Cache được cập nhật thường xuyên, nên an toàn khi sử dụng trong suốt phiên để tránh các yêu cầu mạng.</p><p></p><p>Lưu ý rằng cache vẫn còn nguyên sau khi khởi động lại ứng dụng và chỉ bị xóa khi gỡ cài đặt ứng dụng hoặc dọn dẹp thủ công.</p><p></p><p>Adapty SDK lưu trữ paywalls cục bộ theo hai lớp: cache được cập nhật thường xuyên như mô tả ở trên và [paywall dự phòng](fallback-paywalls). Chúng tôi cũng dùng CDN để tải paywalls nhanh hơn và một server dự phòng độc lập trong trường hợp CDN không thể truy cập. Hệ thống này được thiết kế để đảm bảo bạn luôn nhận được phiên bản mới nhất của paywalls trong khi vẫn đảm bảo độ tin cậy ngay cả khi kết nối internet kém.</p> |
| **loadTimeout** | mặc định: 5 giây | <p>Giá trị này giới hạn thời gian chờ cho phương thức này. Nếu hết thời gian chờ, dữ liệu đã cache hoặc fallback cục bộ sẽ được trả về.</p><p>Lưu ý rằng trong một số trường hợp hiếm gặp, phương thức này có thể hết thời gian chờ muộn hơn một chút so với `loadTimeout` đã chỉ định, vì thao tác có thể bao gồm nhiều yêu cầu bên dưới.</p><p>Đối với Android: Bạn có thể tạo `TimeInterval` với các hàm mở rộng (như `5.seconds`, trong đó `.seconds` được import từ `import com.adapty.utils.seconds`), hoặc `TimeInterval.seconds(5)`. Để không giới hạn, sử dụng `TimeInterval.INFINITE`.</p> |

Tham số phản hồi:

| Tham số | Mô tả                                                                                                                                                     |
| :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Paywall   | Một đối tượng [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) với danh sách ID sản phẩm, định danh paywall, Remote Config và một số thuộc tính khác. |

## Lấy cấu hình view của paywall được thiết kế bằng Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\}

:::important
Đảm bảo bật toggle **Show on device** trong paywall builder. Nếu tùy chọn này chưa được bật, cấu hình view sẽ không thể lấy được.
:::

Sau khi lấy paywall, hãy kiểm tra xem nó có chứa `ViewConfiguration` không — điều này cho biết paywall được tạo bằng Paywall Builder. Thông tin này sẽ hướng dẫn bạn cách hiển thị paywall. Nếu có `ViewConfiguration`, hãy xử lý nó như một paywall Paywall Builder; nếu không, [xử lý nó như một remote config paywall](present-remote-config-paywalls).

<Tabs groupId="current-os" queryString>

<TabItem value="kotlin" label="Kotlin" default>

Sử dụng phương thức `getViewConfiguration` để tải cấu hình view.

```kotlin showLineNumbers
if (!paywall.hasViewConfiguration) {
    // use your custom logic
    return
}

AdaptyUI.getViewConfiguration(paywall, loadTimeout = 10.seconds) { result ->
    when(result) {
        is AdaptyResult.Success -> {
            val viewConfiguration = result.value
            // use loaded configuration
        }
        is AdaptyResult.Error -> {
            val error = result.error
            // handle the error
        }
    }
}
```
| Tham số         | Bắt buộc       | Mô tả                                                        |
| :-------------- | :------------- | :----------------------------------------------------------- |
| **paywall**     | bắt buộc       | Một đối tượng `AdaptyPaywall` để lấy controller cho paywall mong muốn. |
| **loadTimeout** | mặc định: 5 giây | Giá trị này giới hạn thời gian chờ cho phương thức này. Nếu hết thời gian chờ, dữ liệu đã cache hoặc fallback cục bộ sẽ được trả về. Lưu ý rằng trong một số trường hợp hiếm gặp, phương thức này có thể hết thời gian chờ muộn hơn một chút so với `loadTimeout` đã chỉ định, vì thao tác có thể bao gồm nhiều yêu cầu bên dưới. |

</TabItem>
<TabItem value="java" label="Java" default>

Sử dụng phương thức `getViewConfiguration` để tải cấu hình view.

```java showLineNumbers
if (!paywall.hasViewConfiguration()) {
    // use your custom logic
    return;
}

AdaptyUI.getViewConfiguration(paywall, TimeInterval.seconds(10), result -> {
    if (result instanceof AdaptyResult.Success) {
        AdaptyUI.LocalizedViewConfiguration viewConfiguration =
          ((AdaptyResult.Success<AdaptyUI.LocalizedViewConfiguration>) result).getValue();
        // use loaded configuration
    } else if (result instanceof AdaptyResult.Error) {
        AdaptyError error = ((AdaptyResult.Error) result).getError();
        // handle the error
    }
});
```
| Tham số                  | Bắt buộc       | Mô tả                                                        |
| :----------------------- | :------------- | :----------------------------------------------------------- |
| **paywall**              | bắt buộc       | Một đối tượng `AdaptyPaywall` để lấy controller cho paywall mong muốn. |
| **loadTimeout**          | mặc định: 5 giây | Giá trị này giới hạn thời gian chờ cho phương thức này. Nếu hết thời gian chờ, dữ liệu đã cache hoặc fallback cục bộ sẽ được trả về. Lưu ý rằng trong một số trường hợp hiếm gặp, phương thức này có thể hết thời gian chờ muộn hơn một chút so với `loadTimeout` đã chỉ định, vì thao tác có thể bao gồm nhiều yêu cầu bên dưới. |

</TabItem>

</Tabs>

:::note
Nếu bạn đang sử dụng nhiều ngôn ngữ, hãy tìm hiểu cách thêm [bản địa hóa Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) và cách sử dụng mã locale đúng cách [tại đây](android-localizations-and-locale-codes).
:::

Sau khi tải xong, [trình bày paywall](android-present-paywalls).

## Lấy paywall cho đối tượng mặc định để tải nhanh hơn \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\}

Thông thường, paywalls được tải gần như ngay lập tức, nên bạn không cần lo lắng về việc tăng tốc quá trình này. Tuy nhiên, trong trường hợp bạn có nhiều đối tượng và paywalls, và người dùng có kết nối internet yếu, việc tải paywall có thể mất nhiều thời gian hơn mong muốn. Trong tình huống đó, bạn có thể muốn hiển thị một paywall mặc định để đảm bảo trải nghiệm người dùng mượt mà thay vì không hiển thị paywall nào cả.

Để giải quyết vấn đề này, bạn có thể sử dụng phương thức `getPaywallForDefaultAudience`, phương thức này lấy paywall của placement được chỉ định cho đối tượng **All Users**. Tuy nhiên, điều quan trọng cần hiểu là cách tiếp cận được khuyến nghị là lấy paywall bằng phương thức `getPaywall`, như đã mô tả chi tiết trong phần [Lấy thông tin Paywall](#fetch-paywall-designed-with-paywall-builder) ở trên.

:::warning
Tại sao chúng tôi khuyến nghị sử dụng `getPaywall`

Phương thức `getPaywallForDefaultAudience` có một số nhược điểm đáng kể:

- **Vấn đề tương thích ngược tiềm ẩn**: Nếu bạn cần hiển thị các paywall khác nhau cho các phiên bản ứng dụng khác nhau (hiện tại và tương lai), bạn có thể gặp khó khăn. Bạn sẽ phải thiết kế các paywall hỗ trợ phiên bản hiện tại (cũ) hoặc chấp nhận rằng người dùng có phiên bản hiện tại (cũ) có thể gặp sự cố với các paywall không được render.
- **Mất khả năng targeting**: Tất cả người dùng sẽ thấy cùng một paywall được thiết kế cho đối tượng **All Users**, có nghĩa là bạn mất khả năng targeting cá nhân hóa (bao gồm theo quốc gia, marketing attribution hoặc các thuộc tính tùy chỉnh của bạn).

Nếu bạn sẵn sàng chấp nhận những nhược điểm này để được lợi từ việc tải paywall nhanh hơn, hãy sử dụng phương thức `getPaywallForDefaultAudience` như sau. Nếu không, hãy tiếp tục dùng `getPaywall` như đã mô tả [ở trên](#fetch-paywall-designed-with-paywall-builder).
:::

<Tabs groupId="current-os" queryString>

<TabItem value="kotlin" label="Kotlin" default>
```kotlin showLineNumbers
Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") { result ->
    when (result) {
        is AdaptyResult.Success -> {
            val paywall = result.value
            // the requested paywall
        }
        is AdaptyResult.Error -> {
            val error = result.error
            // handle the error
        }
    }
}
```
</TabItem>
<TabItem value="java" label="Java" default>
```java showLineNumbers
Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> {
    if (result instanceof AdaptyResult.Success) {
        AdaptyPaywall paywall = ((AdaptyResult.Success<AdaptyPaywall>) result).getValue();
        // the requested paywall

    } else if (result instanceof AdaptyResult.Error) {
        AdaptyError error = ((AdaptyResult.Error) result).getError();
        // handle the error
      
    }
});
```
</TabItem>

</Tabs>

:::note
Phương thức `getPaywallForDefaultAudience` có sẵn từ Android SDK 2.11.3 trở lên
:::

| Tham số | Bắt buộc | Mô tả |
|---------|--------|-----------|
| **placementId** | bắt buộc | Định danh của [Placement](placements). Đây là giá trị bạn đã chỉ định khi tạo placement trong Adapty Dashboard. |
| **locale** | <p>tùy chọn</p><p>mặc định: `en`</p> | <p>Định danh của [bản địa hóa paywall](add-remote-config-locale). Tham số này cần là mã ngôn ngữ gồm một hoặc nhiều thẻ con phân tách bằng ký tự gạch ngang (**-**). Thẻ con đầu tiên là ngôn ngữ, thẻ con thứ hai là vùng.</p><p></p><p>Ví dụ: `en` là tiếng Anh, `pt-br` là tiếng Bồ Đào Nha Brazil.</p><p></p><p>Xem [Bản địa hóa và mã locale](localizations-and-locale-codes) để biết thêm thông tin về mã locale và cách chúng tôi khuyến nghị sử dụng.</p> |
| **fetchPolicy** | mặc định: `.reloadRevalidatingCacheData` | <p>Theo mặc định, SDK sẽ cố tải dữ liệu từ server và trả về dữ liệu đã cache trong trường hợp thất bại. Chúng tôi khuyến nghị cách này vì nó đảm bảo người dùng luôn nhận được dữ liệu mới nhất.</p><p></p><p>Tuy nhiên, nếu bạn cho rằng người dùng của mình có kết nối internet không ổn định, hãy cân nhắc sử dụng `.returnCacheDataElseLoad` để trả về dữ liệu đã cache nếu có. Trong trường hợp này, người dùng có thể không nhận được dữ liệu mới nhất tuyệt đối, nhưng sẽ có thời gian tải nhanh hơn, bất kể kết nối internet của họ có chập chờn đến đâu. Cache được cập nhật thường xuyên, nên an toàn khi sử dụng trong suốt phiên để tránh các yêu cầu mạng.</p><p></p><p>Lưu ý rằng cache vẫn còn nguyên sau khi khởi động lại ứng dụng và chỉ bị xóa khi gỡ cài đặt ứng dụng hoặc dọn dẹp thủ công.</p> |

## Tùy chỉnh assets \{#customize-assets\}

Để tùy chỉnh hình ảnh và video trong paywall, hãy triển khai các custom assets.

Hình ảnh hero và video có các ID được định nghĩa sẵn: `hero_image` và `hero_video`. Trong một bundle custom asset, bạn nhắm đến các phần tử này bằng ID của chúng và tùy chỉnh hành vi của chúng.

Đối với các hình ảnh và video khác, bạn cần [đặt ID tùy chỉnh](custom-media) trong Adapty dashboard.

Ví dụ, bạn có thể:

- Hiển thị hình ảnh hoặc video khác cho một số người dùng.
- Hiển thị ảnh xem trước cục bộ trong khi hình ảnh chính từ xa đang tải.
- Hiển thị ảnh xem trước trước khi chạy video.

:::important
Để sử dụng tính năng này, hãy cập nhật Adapty Android SDK lên phiên bản 3.7.0 trở lên.
:::

Đây là ví dụ về cách bạn có thể cung cấp custom assets thông qua một dictionary đơn giản:

```kotlin showLineNumbers
val customAssets = AdaptyCustomAssets.of(
    "hero_image" to
            AdaptyCustomImageAsset.remote(
                url = "https://example.com/image.jpg",
                preview = AdaptyCustomImageAsset.file(
                    FileLocation.fromAsset("images/hero_image_preview.png"),
                )
            ),
    "hero_video" to
            AdaptyCustomVideoAsset.file(
                FileLocation.fromResId(requireContext(), R.raw.custom_video),
                preview = AdaptyCustomImageAsset.file(
                    FileLocation.fromResId(requireContext(), R.drawable.video_preview),
                ),
            ),
)

val paywallView = AdaptyUI.getPaywallView(
    activity,
    viewConfiguration,
    products,
    eventListener,
    insets,
    customAssets,
)
```

:::note
Nếu không tìm thấy asset, paywall sẽ quay về giao diện mặc định của nó.
:::