Kích hoạt mua hàng với Flow & Paywall Builder trong Unity SDK

Hướng dẫn này sử dụng API của Adapty Unity SDK v4 (beta). Nếu bạn đang dùng v3, hãy xem hướng dẫn migration để biết tên phương thức tương ứng.

Để bật tính năng in-app purchase, bạn cần hiểu ba khái niệm chính:

  • Sản phẩm – bất kỳ thứ gì người dùng có thể mua (gói đăng ký, consumable, quyền truy cập trọn đời)
  • Flow & paywall – các màn hình trình bày sản phẩm đến người dùng, được xây dựng bằng Flow & Paywall Builder dạng no-code. SDK lấy chúng qua GetFlow. Nếu bạn muốn tự xây dựng giao diện bằng code, xem Triển khai paywall tùy chỉnh.
  • Placement – nơi và thời điểm bạn hiển thị flow & paywall trong ứng dụng (ví dụ: main, onboarding, settings). Bạn gắn chúng vào các placement trên dashboard, sau đó yêu cầu theo placement ID trong code. Điều này giúp dễ dàng chạy A/B test và hiển thị các nội dung khác nhau cho từng nhóm người dùng.

Adapty cung cấp cho bạn ba cách để bật tính năng mua hàng trong ứng dụng. Hãy chọn một trong số đó tùy theo yêu cầu của ứng dụng:

Cách triển khaiĐộ phức tạpKhi nào nên dùng
Adapty Flow & Paywall Builder✅ DễBạn tạo flow hoặc paywall hoàn chỉnh, sẵn sàng để mua hàng trong trình tạo no-code. Adapty tự động hiển thị và xử lý toàn bộ logic mua hàng phức tạp, xác thực biên lai, và quản lý gói đăng ký ở phía sau.
Paywall tùy chỉnh🟡 Trung bìnhBạn tự xây dựng giao diện paywall trong code của ứng dụng, nhưng vẫn lấy đối tượng flow từ Adapty để duy trì sự linh hoạt trong việc cung cấp sản phẩm. Xem hướng dẫn.
Observer mode🔴 KhóBạn đã có cơ sở hạ tầng xử lý mua hàng riêng và muốn tiếp tục sử dụng nó. Lưu ý rằng observer mode có một số hạn chế trong Adapty. Xem bài viết.
Important

Các bước dưới đây hướng dẫn cách triển khai một flow hoặc paywall được tạo trong Adapty Flow & Paywall Builder.

Nếu bạn muốn tự xây dựng giao diện paywall, hãy xem Triển khai paywall tùy chỉnh.

Để hiển thị một flow hoặc paywall được tạo trong Adapty Flow & Paywall Builder, trong code ứng dụng của bạn, bạn chỉ cần:

  1. Lấy flow hoặc paywall: Lấy từ Adapty.
  2. Hiển thị và để Adapty xử lý việc mua hàng cho bạn: Hiển thị view trong ứng dụng của bạn.
  3. Xử lý các hành động nút: Liên kết các tương tác của người dùng với phản hồi tương ứng trong ứng dụng. Ví dụ: mở liên kết hoặc đóng paywall khi người dùng nhấn nút.

Trước khi bắt đầu

Trước khi bắt đầu, hãy hoàn thành các bước sau:

  1. Kết nối ứng dụng của bạn với App Store và/hoặc Google Play trong Adapty Dashboard.
  2. Tạo sản phẩm trong Adapty.
  3. Tạo một flow hoặc paywall và thêm sản phẩm vào đó.
  4. Tạo một placement và thêm flow hoặc paywall vào đó.
  5. Cài đặt và kích hoạt SDK trong code ứng dụng của bạn.
Tip

Cách nhanh nhất để hoàn thành các bước này là làm theo hướng dẫn quickstart hoặc tạo flow và placement bằng Developer CLI.

1. Lấy flow hoặc paywall

Các flow và paywall của bạn được liên kết với các placement được cấu hình trên dashboard. Placement cho phép bạn hiển thị các flow hoặc paywall khác nhau cho các đối tượng khác nhau, hoặc chạy A/B test.

Để lấy một flow hoặc paywall được tạo trong Adapty Flow & Paywall Builder, bạn cần:

  1. Lấy đối tượng flow theo ID placement bằng phương thức GetFlow.

  2. Tạo flow view bằng phương thức CreateFlowView. View chứa các phần tử UI và styling cần thiết để hiển thị. Nếu flow chưa có view nào được cấu hình, CreateFlowView sẽ trả về lỗi — hãy xử lý lỗi này trong callback.

Important

Để lấy view, hãy xuất bản flow hoặc paywall. Một flow hoặc paywall có các chỉnh sửa chưa được xuất bản sẽ có trạng thái Dirty, và placement của nó vẫn tiếp tục phục vụ phiên bản đã xuất bản trước đó.

Adapty.GetFlow("YOUR_PLACEMENT_ID", (flow, error) => {
    if (error != null) {
        // handle the error
        return;
    }

    // Create the flow view
    AdaptyUI.CreateFlowView(flow, (view, error) => {
        if (error != null) {
            // the flow has no view configured, or view creation failed
            return;
        }

        // view - the flow view ready to be presented
    });
});
Info

Quickstart này cung cấp cấu hình tối thiểu cần thiết để hiển thị một flow hoặc paywall. Để biết thêm chi tiết về cấu hình nâng cao, hãy xem hướng dẫn lấy flow và paywall của chúng tôi.

2. Hiển thị flow hoặc paywall

Bây giờ, khi bạn đã có flow view, chỉ cần thêm vài dòng code để hiển thị nó.

Để hiển thị flow, sử dụng phương thức view.Present() trên view được tạo bởi phương thức CreateFlowView. Mỗi view chỉ có thể được sử dụng một lần: sau khi bạn đóng nó, hãy gọi lại CreateFlowView để hiển thị flow thêm một lần nữa.

view.Present((error) => {
    // handle the error
});
Info

Để biết thêm chi tiết về cách hiển thị flow hoặc paywall, xem hướng dẫn của chúng tôi.

3. Xử lý các hành động của nút

Khi người dùng nhấn các nút trong flow hoặc paywall, Unity SDK tự động xử lý việc mua hàng và khôi phục. Tuy nhiên, các nút khác có ID tùy chỉnh hoặc được định nghĩa sẵn và cần xử lý các hành động trong code của bạn.

Ví dụ, paywall của bạn thường có nút đóng và các URL cần mở (như điều khoản sử dụng và chính sách bảo mật). Để xử lý các hành động này, class của bạn cần triển khai interface IAdaptyFlowsEventsListener và đăng ký làm listener.

Lưu ý rằng flow vẫn giữ nguyên sau khi mua hàng thành công. Nếu bạn muốn đóng nó lại khi giao dịch hoàn tất, hãy dismiss view trong callback FlowViewDidFinishPurchase.

Tip

Đọc hướng dẫn của chúng tôi về cách xử lý actions và events của các nút bấm.

public class YourClass : MonoBehaviour, IAdaptyFlowsEventsListener
{
    void Start()
    {
        // Register this class as the flows events listener
        Adapty.SetFlowsEventsListener(this);
    }

    // IAdaptyFlowsEventsListener method - handles button actions
    public void FlowViewDidPerformAction(
        AdaptyUIFlowView view,
        AdaptyUIUserAction action
    ) {
        switch (action.Type) {
            case AdaptyUIUserActionType.Close:
                view.Dismiss(null);
                break;
            case AdaptyUIUserActionType.OpenUrl:
                AdaptyUI.OpenUrl(action.Value, AdaptyWebPresentation.ExternalBrowser, null);
                break;
            default:
                break;
        }
    }

    // IAdaptyFlowsEventsListener method - dismiss the flow after a purchase
    public void FlowViewDidFinishPurchase(
        AdaptyUIFlowView view,
        AdaptyPaywallProduct product,
        AdaptyPurchaseResult purchasedResult
    ) {
        if (purchasedResult.Type != AdaptyPurchaseResultType.UserCancelled) {
            view.Dismiss(null);
        }
    }
}

Các bước tiếp theo

Tip

Bạn có câu hỏi hoặc gặp sự cố? Hãy xem diễn đàn hỗ trợ của chúng tôi — nơi bạn có thể tìm câu trả lời cho các câu hỏi thường gặp hoặc đặt câu hỏi của riêng mình. Đội ngũ và cộng đồng của chúng tôi luôn sẵn sàng giúp đỡ!

Flow hoặc paywall của bạn đã sẵn sàng để hiển thị trong ứng dụng. Hãy kiểm tra các giao dịch mua trong sandbox App Store hoặc Google Play Store để đảm bảo bạn có thể hoàn thành một giao dịch mua thử từ flow.

Tiếp theo, bạn cần kiểm tra mức độ truy cập của người dùng để đảm bảo hiển thị paywall hoặc cấp quyền truy cập tính năng trả phí cho đúng người dùng.

Ví dụ đầy đủ

Dưới đây là cách tích hợp tất cả các bước đó vào ứng dụng của bạn.

using System;
using System.Collections.Generic;
using UnityEngine;
using AdaptySDK;

public class FlowManager : MonoBehaviour, IAdaptyFlowsEventsListener
{
    [SerializeField] private string placementId = "YOUR_PLACEMENT_ID";

    void Start()
    {
        // Register for flow events
        Adapty.SetFlowsEventsListener(this);
        GetAndDisplayFlow();
    }

    private void GetAndDisplayFlow()
    {
        Adapty.GetFlow(placementId, (flow, error) => {
            if (error != null) {
                Debug.LogError("Error getting flow: " + error.Message);
                return;
            }

            CreateAndPresentFlowView(flow);
        });
    }

    private void CreateAndPresentFlowView(AdaptyFlow flow)
    {
        AdaptyUI.CreateFlowView(flow, (view, error) => {
            if (error != null) {
                // the flow has no view configured — use custom logic
                Debug.LogError("Error creating flow view: " + error.Message);
                return;
            }

            view.Present((presentError) => {
                if (presentError != null) {
                    Debug.LogError("Error presenting flow: " + presentError.Message);
                    return;
                }

                Debug.Log("Flow presented successfully");
            });
        });
    }

    // IAdaptyFlowsEventsListener implementation
    public void FlowViewDidPerformAction(
        AdaptyUIFlowView view,
        AdaptyUIUserAction action
    ) {
        switch (action.Type) {
            case AdaptyUIUserActionType.Close:
                Debug.Log("Close button pressed");
                view.Dismiss(null);
                break;
            case AdaptyUIUserActionType.OpenUrl:
                AdaptyUI.OpenUrl(action.Value, AdaptyWebPresentation.ExternalBrowser, null);
                break;
            default:
                break;
        }
    }

    public void FlowViewDidFinishPurchase(
        AdaptyUIFlowView view,
        AdaptyPaywallProduct product,
        AdaptyPurchaseResult purchasedResult
    ) {
        if (purchasedResult.Type != AdaptyPurchaseResultType.UserCancelled) {
            view.Dismiss(null);
        }
    }

    // Required interface methods (implement as needed)
    public void FlowViewDidAppear(AdaptyUIFlowView view) { }
    public void FlowViewDidDisappear(AdaptyUIFlowView view) { }
    public void FlowViewDidSelectProduct(AdaptyUIFlowView view, string productId) { }
    public void FlowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) { }
    public void FlowViewDidFailPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyError error) { }
    public void FlowViewDidStartRestore(AdaptyUIFlowView view) { }
    public void FlowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { }
    public void FlowViewDidFailRestore(AdaptyUIFlowView view, AdaptyError error) { }
    public void FlowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) { }
    public void FlowViewDidFailLoadingProducts(AdaptyUIFlowView view, AdaptyError error) { }
    public void FlowViewDidFinishWebPaymentNavigation(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyError error) { }
    public void FlowViewDidReceiveAnalyticEvent(AdaptyUIFlowView view, string name, IDictionary<string, object> @params) { }

    public void ShowFlow()
    {
        GetAndDisplayFlow();
    }
}