---
title: "Android - Hiển thị paywall mới với Paywall Builder"
description: "Tìm hiểu cách hiển thị paywall trên Android để tối ưu hóa monetization."
---

Nếu bạn đã tùy chỉnh paywall bằng 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. Paywall đó đã bao gồm cả nội dung cần hiển thị lẫn cách hiển thị.

:::warning

Hướng dẫn này chỉ dành cho **paywall Paywall Builder mới** yêu cầu SDK v3.0. Quy trình hiển thị paywall khác nhau tùy theo phiên bản Paywall Builder được sử dụng, paywall remote config, và [chế độ Observer](observer-vs-full-mode).

- Để hiển thị **paywall Remote config**, xem [Render paywall được thiết kế bằng remote config](present-remote-config-paywalls).
- Để hiển thị **paywall ở chế độ Observer**, xem [Android - Hiển thị paywall Paywall Builder trong chế độ Observer](android-present-paywall-builder-paywalls-in-observer-mode)

:::

Để lấy đối tượng `viewConfiguration` được dùng bên dưới, xem [Fetch paywall Paywall Builder và cấu hình của chúng](android-get-pb-paywalls).

<Tabs groupId="current-os" queryString>
<TabItem value="views" label="Views" default>

Để hiển thị paywall trực quan trên màn hình thiết bị, bạn phải cấu hình nó trước. Để làm điều này, gọi phương thức `AdaptyUI.getPaywallView()` hoặc tạo `AdaptyPaywallView` trực tiếp:

<Tabs groupId="current-os" queryString>
  <TabItem value="kotlin" label="Kotlin (option 1)" default>

```kotlin showLineNumbers
   val paywallView = AdaptyUI.getPaywallView(
       activity,
       viewConfiguration,
       products,
       eventListener,
       insets,
       personalizedOfferResolver,
       tagResolver,
       timerResolver,
   )
```
</TabItem>
<TabItem value="kotlin2" label="Kotlin (option 2)" default>

```kotlin showLineNumbers
   val paywallView =
        AdaptyPaywallView(activity) // or retrieve it from xml
   ...
   with(paywallView) {
       showPaywall(
           viewConfiguration,
           products,
					 eventListener,
           insets,
           personalizedOfferResolver,
           tagResolver,
           timerResolver,
       )
   }
```

</TabItem>
<TabItem value="java" label="Java (option 1)" default>

```java showLineNumbers
AdaptyPaywallView paywallView = AdaptyUI.getPaywallView(
        activity,
        viewConfiguration,
        products,
        eventListener,
        insets,
        personalizedOfferResolver,
        tagResolver,
        timerResolver
);
```
</TabItem>
<TabItem value="java2" label="Java (option 2)" default>

```java showLineNumbers
AdaptyPaywallView paywallView =
  new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml
...
paywallView.showPaywall(viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver);
```

</TabItem>
<TabItem value="XML" label="XML" default>

```xml showLineNumbers
<com.adapty.ui.AdaptyPaywallView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
```
</TabItem>
</Tabs>

Sau khi view được tạo thành công, bạn có thể thêm nó vào hệ thống view và hiển thị trên màn hình thiết bị.

Nếu bạn lấy `AdaptyPaywallView` _không_ thông qua `AdaptyUI.getPaywallView()`, bạn cũng cần gọi phương thức `.showPaywall()`.

</TabItem>
<TabItem value="compose" label="Jetpack Compose" default>

Để hiển thị paywall trực quan trên màn hình thiết bị, bạn phải cấu hình nó trước. Để làm điều này, sử dụng composable function sau:

```kotlin showLineNumbers
AdaptyPaywallScreen(
    viewConfiguration,
    products,
    eventListener,
    insets,
    personalizedOfferResolver,
    tagResolver,
    timerResolver,
)
```
</TabItem>
</Tabs>

Các tham số yêu cầu:

| Tham số                       | Bắt buộc | Mô tả                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| :---------------------------- | :------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **viewConfiguration**         | bắt buộc | Cung cấp đối tượng `AdaptyUI.LocalizedViewConfiguration` chứa thông tin trực quan của paywall. Dùng phương thức `Adapty.getViewConfiguration(paywall)` để tải nó. Tham khảo chủ đề [Fetch cấu hình trực quan của paywall](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) để biết thêm chi tiết.                                                                                                                               |
| **products**                  | tùy chọn | Cung cấp mảng `AdaptyPaywallProduct` để tối ưu thời điểm hiển thị sản phẩm trên màn hình. Nếu truyền `null`, AdaptyUI sẽ tự động fetch các sản phẩm cần thiết.                                                                                                                                                                                                                                                                                                                  |
| **eventListener**             | tùy chọn | Cung cấp `AdaptyUiEventListener` để theo dõi các sự kiện paywall. Nên extend `AdaptyUiDefaultEventListener` để dễ sử dụng hơn. Tham khảo chủ đề [Xử lý sự kiện paywall](android-handling-events) để biết thêm chi tiết.                                                                                                                                                                                                                                                        |
| **insets**                    | tùy chọn | <p>Insets là các khoảng cách xung quanh paywall để ngăn các phần tử tương tác bị ẩn sau thanh hệ thống.</p><p>Mặc định: `UNSPECIFIED` — Adapty sẽ tự động điều chỉnh insets, phù hợp với paywall edge-to-edge. </p><p>Nếu paywall của bạn không phải edge-to-edge, bạn có thể muốn đặt insets tùy chỉnh. Cách thực hiện được mô tả trong phần [Thay đổi insets paywall](android-present-paywalls#change-paywall-insets) bên dưới.</p>                                           |
| **personalizedOfferResolver** | tùy chọn | Để chỉ định giá cá nhân hóa ([đọc thêm](https://developer.android.com/google/play/billing/integrate#personalized-price)), hãy implement `AdaptyUiPersonalizedOfferResolver` và truyền logic của bạn để ánh xạ `AdaptyPaywallProduct` thành `true` nếu giá sản phẩm được cá nhân hóa, ngược lại là `false`.                                                                                                                                                                      |
| **tagResolver**               | tùy chọn | Dùng `AdaptyUiTagResolver` để resolve các custom tag trong văn bản paywall. Resolver này nhận tham số tag và resolve thành chuỗi tương ứng. Tham khảo chủ đề Custom tags trong Paywall Builder để biết thêm chi tiết.                                                                                                                                                                                                                                                            |
| **timerResolver**             | tùy chọn | Truyền resolver vào đây nếu bạn sử dụng chức năng timer tùy chỉnh.                                                                                                                                                                                                                                                                                                                                                                                                              |

:::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.

:::

## Thay đổi insets paywall \{#change-paywall-insets\}

Insets là các khoảng cách xung quanh paywall để ngăn các phần tử tương tác bị ẩn sau thanh hệ thống. Mặc định, Adapty sẽ tự động điều chỉnh insets, phù hợp với paywall edge-to-edge.

Nếu paywall của bạn không phải edge-to-edge, bạn có thể muốn đặt insets tùy chỉnh:

- Nếu cả thanh trạng thái lẫn thanh điều hướng đều không che `AdaptyPaywallView`, dùng `AdaptyPaywallInsets.NONE`.
- Với các cấu hình tùy chỉnh hơn, ví dụ nếu paywall của bạn chồng lên thanh trạng thái trên cùng nhưng không chồng lên phần dưới, bạn có thể chỉ đặt `bottomInset` thành `0` như ví dụ bên dưới:

<Tabs groupId="current-os" queryString>
<TabItem value="kotlin" label="Kotlin" default>
```kotlin showLineNumbers

//create extension function
fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) {
    ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets ->
        val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
        ViewCompat.setOnApplyWindowInsetsListener(this, null)
        action(systemBarInsets)
        insets
    }
}
//and then use it with the view
paywallView.onReceiveSystemBarsInsets { insets ->
    val paywallInsets = AdaptyPaywallInsets.vertical(insets.top, 0)
    paywallView.showPaywall(
           viewConfiguration,
           products,
					 eventListener,
           paywallInsets,
           personalizedOfferResolver,
           tagResolver,
           timerResolver,
       )
}
```
</TabItem>
<TabItem value="java" label="Java" default>
```java showLineNumbers

...

ViewCompat.setOnApplyWindowInsetsListener(paywallView, (view, insets) -> {
    Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
    ViewCompat.setOnApplyWindowInsetsListener(paywallView, null);

    AdaptyPaywallInsets paywallInsets =
                AdaptyPaywallInsets.of(systemBarInsets.top, 0);
    paywallView.showPaywall(paywall, products, viewConfiguration, paywallInsets, productTitleResolver);

    return insets;
});
```
</TabItem>
</Tabs>

## Sử dụng timer do lập trình viên định nghĩa \{#use-developer-defined-timer\}

Để sử dụng timer tùy chỉnh trong ứng dụng, hãy tạo đối tượng `timerResolver`—một dictionary hoặc map ánh xạ các timer tùy chỉnh với giá trị chuỗi sẽ thay thế chúng khi paywall được render. Ví dụ:

<Tabs groupId="current-os" queryString>
<TabItem value="kotlin" label="Kotlin" default>

```kotlin showLineNumbers

...

val customTimers = mapOf(
    "CUSTOM_TIMER_NY" to Calendar.getInstance(TimeZone.getDefault()).apply { set(2025, 0, 1) }.time, // New Year 2025
)
val timerResolver = AdaptyUiTimerResolver { timerId ->
    customTimers.getOrElse(timerId, { Date(System.currentTimeMillis() + 3600 * 1000L) /* in 1 hour */ } )
}
```

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

```java showLineNumbers

...

Map<String, Date> customTimers = new HashMap<>();
customTimers.put(
        "CUSTOM_TIMER_NY",
        new Calendar.Builder().setTimeZone(TimeZone.getDefault()).setDate(2025, 0, 1).build().getTime()
);
AdaptyUiTimerResolver timerResolver = new AdaptyUiTimerResolver() {
    @NonNull
    @Override
    public Date timerEndAtDate(@NonNull String timerId) {
        Date date = customTimers.get(timerId);
        return date != null ? date : new Date(System.currentTimeMillis() + 3600 * 1000L); /* in 1 hour */
    }
};
```

</TabItem>

</Tabs>

Trong ví dụ này, `CUSTOM_TIMER_NY` là **Timer ID** của timer do lập trình viên định nghĩa mà bạn đã thiết lập trong Adapty dashboard. `timerResolver` đảm bảo ứng dụng của bạn cập nhật động timer với giá trị chính xác—ví dụ như `13d 09h 03m 34s` (được tính bằng thời điểm kết thúc timer, chẳng hạn Ngày Đầu Năm Mới, trừ đi thời gian hiện tại).

## Sử dụng custom tag \{#use-custom-tags\}

Để sử dụng custom tag trong ứng dụng, hãy tạo đối tượng `tagResolver`—một dictionary hoặc map ánh xạ các custom tag với giá trị chuỗi sẽ thay thế chúng khi paywall được render. Ví dụ:

<Tabs groupId="current-os" queryString>
<TabItem value="kotlin" label="Kotlin" default>

```kotlin showLineNumbers
val customTags = mapOf("USERNAME" to "John")
val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] }
```

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

```java showLineNumbers
Map<String, String> customTags = new HashMap<>();
customTags.put("USERNAME", "John");
AdaptyUiTagResolver tagResolver = customTags::get;
```

</TabItem>
</Tabs>

Trong ví dụ này, `USERNAME` là custom tag bạn đã nhập trong Adapty dashboard dưới dạng `<USERNAME/>`. `tagResolver` đảm bảo ứng dụng của bạn tự động thay thế custom tag này bằng giá trị được chỉ định—ví dụ như `John`.

Chúng tôi khuyến nghị tạo và điền vào `tagResolver` ngay trước khi hiển thị paywall. Khi đã sẵn sàng, truyền nó vào phương thức AdaptyUI mà bạn dùng để hiển thị paywall.

## Thay đổi màu loading indicator của paywall \{#change-paywall-loading-indicator-color\}

Bạn có thể ghi đè màu mặc định của loading indicator theo cách sau:

```xml showLineNumbers title = "XML"

<style name="AppTheme" parent="android:Theme.Material.Light.NoActionBar">

    <item name="adapty_progressIndicatorColor">@color/yourColor</item>
</style>
```