在 Unity SDK 中使用 Flow Builder 启用购买功能

本指南使用 Adapty Unity SDK v4(测试版)API。如果您使用的是 v3,请参阅迁移指南了解对应的方法名称。

要启用应用内购买,您需要了解以下三个核心概念:

  • 产品 – 用户可以购买的任何内容(订阅、消耗型商品、永久授权)
  • 流程 – 向用户展示产品的屏幕序列,在无代码的 Flow Builder 中构建。SDK 通过 GetFlow 获取流程。如果你更倾向于用自己的代码构建 UI,请使用付费墙代替——参见手动实现付费墙
  • 版位 – 在应用中展示流程的位置和时机(如 mainonboardingsettings)。你在看板中将流程绑定到版位,然后在代码中通过版位 ID 请求它们。这样可以轻松运行 A/B 测试,并向不同用户展示不同的流程。

Adapty 为您提供三种在应用中开启购买功能的方式。请根据您的应用需求选择其中一种:

实现方式复杂度适用场景
Adapty Flow Builder✅ 简单在无代码编辑工具中创建完整的、可直接购买的流程。Adapty 自动渲染并在后台处理所有复杂的购买流程、收据验证和订阅管理。
手动创建付费墙🟡 中等你在应用代码中自行实现付费墙 UI,但仍从 Adapty 获取流程对象,以保持产品组合的灵活性。请参阅指南
观察者模式🔴 困难你已有自己的购买处理基础设施,并希望继续使用它。请注意,观察者模式在 Adapty 中存在一定限制。请参阅相关文章
Important

以下步骤介绍如何在应用中实现在 Adapty 付费墙编辑工具中创建的流程。

如果你希望自行构建付费墙 UI,请参阅手动实现付费墙

要展示在 Adapty 付费墙编辑工具中创建的流程,你只需在应用代码中完成以下操作:

  1. 获取流程:从 Adapty 获取流程。
  2. 展示流程,Adapty 将为你处理购买逻辑:在应用中显示视图。
  3. 处理按钮操作:将用户交互与应用的相应响应关联起来。例如,在用户点击按钮时打开链接或关闭流程。

开始之前

在开始之前,请完成以下步骤:

  1. 在 Adapty 看板中将您的应用连接到 App Store 和/或 Google Play
  2. 在 Adapty 中创建产品
  3. 创建流程并向其添加产品
  4. 创建版位并将您的流程添加到其中
  5. 在您的应用代码中安装并激活 Adapty SDK
Tip

完成这些步骤最快的方式是参照快速入门指南,或使用 Developer CLI 创建流程和版位。

1. 获取流程

你的流程与在看板中配置的版位相关联。通过版位,你可以针对不同的目标受众展示不同的流程,或运行 A/B 测试

要获取在 Adapty 付费墙编辑工具中创建的流程,需要:

  1. 使用 GetFlow 方法,通过版位 ID 获取 flow 对象。

  2. 使用 CreateFlowView 方法创建流程视图。该视图包含展示流程所需的 UI 元素和样式。如果流程未配置视图,CreateFlowView 将返回错误——请在回调中处理该错误。

Important

要获取视图,必须在 Flow Builder 中开启 Show on device 开关。否则,CreateFlowView 将返回错误,流程将无法显示。

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

本快速入门提供了显示流程所需的最低配置。如需高级配置详情,请参阅我们的获取流程指南

2. 展示流程

现在,当你拥有流程视图后,只需添加几行代码即可展示它。

要展示流程,请对由 CreateFlowView 方法创建的 view 调用 view.Present() 方法。每个 view 只能使用一次:关闭后,需再次调用 CreateFlowView 来重新展示流程。

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

有关如何展示流程的更多详情,请参阅我们的指南

3. 处理按钮操作

当用户点击流程中的按钮时,Unity SDK 会自动处理购买和恢复操作。但其他按钮具有自定义或预定义的 ID,需要在代码中处理相应操作。

例如,你的流程可能包含关闭按钮以及需要打开的 URL(如使用条款和隐私政策)。要处理这些操作,你的类需要实现 IAdaptyFlowsEventsListener 接口并注册为监听器。

请注意,流程在购买成功后会保持打开状态。如果您希望在购买完成后关闭它,请在 FlowViewDidFinishPurchase 回调中关闭该视图。

Tip

阅读我们关于如何处理按钮操作事件的指南。

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);
        }
    }
}

下一步

Tip

有疑问或遇到问题?欢迎访问我们的支持论坛,在那里你可以找到常见问题的解答,也可以提出自己的问题。我们的团队和社区随时为你提供帮助!

您的流程已准备好在应用中展示。请在 App Store 沙盒Google Play Store 中测试购买,确保您可以从流程中完成测试购买。

现在,您需要检查用户的访问等级,以确保您向正确的用户展示流程或授予付费功能的访问权限。

完整示例

以下是将所有步骤整合到应用中的完整示例。

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();
    }
}