概览

CloudX Unity SDK 设置和核心功能概览

CloudX Unity SDK 使您能够在 iOS 和 Android 上通过横幅、MREC、插屏、激励和 App Open 广告实现 Unity 游戏变现。

安装

CloudX Unity SDK 以 .unitypackage 文件形式分发。

  1. CloudX Unity SDK 4.5.1 发布页 下载 CloudXSdk-4.5.1.unitypackage
  2. 在 Unity 中,转到 Assets > Import Package > Custom Package
  3. 选择下载的 .unitypackage 文件
  4. 提示时导入所有资源

广告网络适配器

CloudX SDK 需要广告网络适配器来投放广告。在 Assets/CloudXSdk/Editor/CloudXDependencies.xml 中取消注释相应行即可启用。各适配器的详细设置(包括 iOS Info.plist 要求),请参阅适配器章节。

初始化

在加载任何广告之前初始化 SDK。您可以在初始化之前选择性地配置用户和应用属性。

using CloudX;
using UnityEngine;

public class MyGameManager : MonoBehaviour
{
    void Start()
    {
        InitializeCloudX();
    }

    void InitializeCloudX()
    {
        // 初始化前配置(可选)
        CloudXSdk.SetHashedUserId("hashed-user-id");
        CloudXSdk.SetUserKeyValue("user_level", "premium");
        CloudXSdk.SetAppKeyValue("app_version", "1.0.0");

        // 在初始化之前订阅回调
        CloudXInitializationCallbacks.OnSdkInitializedEvent += OnSdkInitialized;
        CloudXInitializationCallbacks.OnSdkInitializationFailedEvent += OnSdkInitializationFailed;

        // 初始化 SDK
        var config = CloudXInitializationConfiguration.Create("YOUR_APP_KEY").Build();
        CloudXSdk.Initialize(config);
    }

    private void OnSdkInitialized(CloudXSdkConfiguration config)
    {
        Debug.Log("CloudX SDK 初始化成功");
        // 现在可以加载广告
    }

    private void OnSdkInitializationFailed(CloudXError error)
    {
        Debug.LogError($"SDK 初始化失败: {error}");
    }
}

广告格式

CloudX Unity SDK 支持横幅、MREC、插屏、激励和 App Open 广告集成。请查阅各格式专属指南了解实现详情:

高级功能

隐私控制

如果您的应用没有使用 CMP,可以在初始化之前手动覆盖隐私状态。

// 在 Initialize() 之前可选地设置手动隐私覆盖
CloudXSdk.SetHasUserConsent(true);
CloudXSdk.SetDoNotSell(false);

// 传入 null 可清除手动覆盖,重新交由 CMP 或 IAB 信号决定
CloudXSdk.SetHasUserConsent(null);
CloudXSdk.SetDoNotSell(null);
  • SetHasUserConsent(bool?) 用于设置 GDPR 同意覆盖。
  • SetDoNotSell(bool?) 用于设置 CCPA do-not-sell 覆盖。
  • 如果存在 IAB 同意或隐私信号,它们会优先于这些手动覆盖值。

iOS ATT 使用说明文案

从 Unity SDK 2.2.4 开始,如果您的应用尚未在 Info.plist 中定义 NSUserTrackingUsageDescription,CloudX 的 iOS 后处理步骤会自动添加该字段。

  • 默认值:This uses device info for more personalized ads and content
  • 如果您已经提供了 NSUserTrackingUsageDescription,CloudX 会保留您现有的值不变。
  • 如果您希望展示自定义的 ATT 提示文案,请在 Info.plist 中显式设置自己的值。

用户定向

配置用户和应用属性以获得更好的广告定向。在 Initialize 之前调用这些方法。

// 设置哈希用户 ID
CloudXSdk.SetHashedUserId("hashed-user-id-12345");

// 设置用户级键值对
CloudXSdk.SetUserKeyValue("user_level", "premium");
CloudXSdk.SetUserKeyValue("age_group", "25-34");

// 设置应用级键值对
CloudXSdk.SetAppKeyValue("app_version", "1.0.0");
CloudXSdk.SetAppKeyValue("build_number", "123");

// 清除所有自定义键值对
CloudXSdk.ClearAllKeyValues();

哈希用户 ID 是由发布商提供的假名标识符。当适用的隐私信号允许时,CloudX 会在竞价时记录该值,并在展示级收入导出中以 hashed_user_id 返回。您可以使用该值将 CloudX 收入与自己的用户数据分群关联。未设置 ID、隐私信号阻止持久化或值超过 128 个字符时,导出值为空。请勿传递未经哈希的个人数据。

身份透传

通过 SetUserKeyValue 传入 UID 2.0、EUID、LiveRamp 和 ID5。有值时设置一次,刷新后再设一次。

传入内容
uidapi.comUID2 广告 token,不要传 refresh token。不要解密。UID2 文档
euid.euEUID 广告 token,不要传 refresh token。不要解密。EUID 文档
liveramp.comLiveRamp ATS 信封,不要传 RampID。LiveRamp 文档
id5-sync.comID5 通用 UID。不要传 0ID5 文档

CloudX 不会生成这些 ID。请先用 UID2、EUID、LiveRamp ATS 或 ID5 生成,再把字符串传进来。这与哈希用户 ID 不是同一回事。

CloudXSdk.SetUserKeyValue("uidapi.com", uid2Token);
CloudXSdk.SetUserKeyValue("euid.eu", euidToken);
CloudXSdk.SetUserKeyValue("liveramp.com", liveRampEnvelope);
CloudXSdk.SetUserKeyValue("id5-sync.com", id5Id);

收入追踪

所有广告格式都通过 OnAdRevenuePaid 事件提供收入回调。CloudXAd 对象包含收入信息:

CloudXAdsCallbacks.Banner.OnAdRevenuePaid += (ad) =>
{
    Debug.Log($"收入: ${ad.Revenue:F4}");
    Debug.Log($"广告网络: {ad.NetworkName}");
    Debug.Log($"广告单元: {ad.AdUnitId}");
    Debug.Log($"广告格式: {ad.AdFormat}");
    Debug.Log($"广告位: {ad.Placement}");
    Debug.Log($"网络广告位: {ad.NetworkPlacement}");

    // 在您的分析中追踪收入
    TrackRevenue(ad.Revenue, ad.NetworkName);
};

MMP 广告收入连接器

如果您的应用使用 Adjust 或 AppsFlyer,可以无需编写 Unity C# 胶水代码,直接将 CloudX 竞得展示收入转发给移动归因合作伙伴。请在 Assets/CloudXSdk/Editor/CloudXDependencies.xml 中取消注释连接器依赖,然后运行 EDM4U 依赖解析。

请只选择连接器或您自己的 OnAdRevenuePaid 转发代码其中一种方式,不要同时使用。

发布者上报的收入数据

如果您的应用在 CloudX 广告流程之外接收来自 AdMob、Google Ad Manager、InMobi、TopOn 或其他聚合平台的展示级收入回调或 bid 元数据,请在 CloudX 初始化完成后将这些事件转发给 CloudX:

字段必填描述
PlatformCloudXRevenuePlatform.AdMobCloudXRevenuePlatform.GamCloudXRevenuePlatform.InMobiCloudXRevenuePlatform.TopOnCloudXRevenuePlatform.Custom("MyProvider")
Revenue单次展示收入,使用 CurrencyCode 对应货币;不是 CPM/eCPM
AdFormat广告格式字符串,例如 bannermrecinterstitialrewarded
CurrencyCodeISO 4217 货币代码(如已知)
PrecisionCloudXRevenuePrecision.ExactEstimatedPublisherDefinedUndefined
NetworkName获胜广告网络名称(如已知)
AdUnitId聚合平台广告单元 ID
ThirdPartyAdPlacementId广告网络侧广告单元或 placement ID
CreativeId广告网络返回的创意 ID
NetworkPlacement广告网络 placement 标识
CountryCode用户国家代码(如已知)
UserSegment用户分群(如已知)

当事件被 CloudX 收益链路接受时,CloudXSdk.ReportRevenueData() 返回 true。当 payload 无效、SDK 尚未初始化或收入追踪不可用时,它返回 false

AdMob paid event

使用 Google Mobile Ads Unity 插件时,每个广告对象都会暴露 OnAdPaid。回调中的 AdValue.Value 以微单位上报,因此传给 CloudX 前请先除以 1_000_000.0

private static CloudXRevenuePrecision ToCloudXRevenuePrecision(AdValue.PrecisionType precision) => precision switch
{
    AdValue.PrecisionType.Precise => CloudXRevenuePrecision.Exact,
    AdValue.PrecisionType.Estimated => CloudXRevenuePrecision.Estimated,
    AdValue.PrecisionType.PublisherProvided => CloudXRevenuePrecision.PublisherDefined,
    _ => CloudXRevenuePrecision.Undefined,
};

private static bool ReportAdMobPaidEvent(AdValue adValue, string adFormat, string adUnitId)
{
    return CloudXSdk.ReportRevenueData(new CloudXRevenueData(
        Platform: CloudXRevenuePlatform.AdMob,
        Revenue: adValue.Value / 1_000_000.0,
        AdFormat: adFormat,
        CurrencyCode: adValue.CurrencyCode,
        Precision: ToCloudXRevenuePrecision(adValue.Precision),
        AdUnitId: adUnitId,
    ));
}

bannerView.OnAdPaid += adValue =>
{
    ReportAdMobPaidEvent(adValue, "banner", ADMOB_BANNER_UNIT_ID);
};

Google Ad Manager paid event 的上报方式与 AdMob paid event 相同,但需要使用 CloudXRevenuePlatform.Gam 和 Ad Manager 广告单元 ID。

private static bool ReportGamPaidEvent(AdValue adValue, string adFormat, string adUnitId)
{
    return CloudXSdk.ReportRevenueData(new CloudXRevenueData(
        Platform: CloudXRevenuePlatform.Gam,
        Revenue: adValue.Value / 1_000_000.0,
        AdFormat: adFormat,
        CurrencyCode: adValue.CurrencyCode,
        Precision: ToCloudXRevenuePrecision(adValue.Precision),
        AdUnitId: adUnitId,
    ));
}

adManagerInterstitial.OnAdPaid += adValue =>
{
    ReportGamPaidEvent(adValue, "interstitial", GAM_INTERSTITIAL_UNIT_ID);
};

InMobi impression event

对于 InMobi,请在 OnAdFetchSuccessful 中保存 args.AdMetaInfo。当 OnAdImpression 触发时,把保存的 metaInfo.Bid 上报给 CloudX,然后清空保存的值。

private AdMetaInfo bannerMetaInfo;

private static bool ReportInMobiImpression(AdMetaInfo metaInfo, string adFormat, string placementId)
{
    return CloudXSdk.ReportRevenueData(new CloudXRevenueData(
        Platform: CloudXRevenuePlatform.InMobi,
        Revenue: metaInfo.Bid,
        AdFormat: adFormat,
        Precision: CloudXRevenuePrecision.Estimated,
        ThirdPartyAdPlacementId: placementId,
        CreativeId: metaInfo.CreativeID,
    ));
}

bannerAd.OnAdFetchSuccessful += (_, args) =>
{
    bannerMetaInfo = args.AdMetaInfo;
};

bannerAd.OnAdImpression += (_, _) =>
{
    ReportInMobiImpression(bannerMetaInfo, "banner", INMOBI_BANNER_PLACEMENT_ID);
    bannerMetaInfo = null;
};

TopOn revenue event

使用 TopOn Unity plugin v2.1.8 或更高版本时,请在广告对象上设置 IATAdRevenueListener。使用 adInfo.publisher_revenue 作为单次展示收入;不要使用 adInfo.adsource_price,因为 TopOn 将该值作为 CPM/eCPM 上报。

using AnyThinkAds.Api;
using CloudX;

private static CloudXRevenuePrecision ToTopOnRevenuePrecision(string precision)
{
    return precision switch
    {
        "exact" => CloudXRevenuePrecision.Exact,
        "estimated" => CloudXRevenuePrecision.Estimated,
        "publisher_defined" => CloudXRevenuePrecision.PublisherDefined,
        _ => CloudXRevenuePrecision.Undefined,
    };
}

private sealed class TopOnRevenueListener : IATAdRevenueListener
{
    public void onAdRevenuePaid(string placementId, ATCallbackInfo adInfo)
    {
        ReportTopOnRevenue(adInfo, "banner", placementId);
    }
}

private static bool ReportTopOnRevenue(ATCallbackInfo adInfo, string adFormat, string placementId)
{
    return CloudXSdk.ReportRevenueData(new CloudXRevenueData(
        Platform: CloudXRevenuePlatform.TopOn,
        Revenue: adInfo.publisher_revenue,
        AdFormat: adFormat,
        CurrencyCode: adInfo.currency,
        Precision: ToTopOnRevenuePrecision(adInfo.precision),
        NetworkName: adInfo.network_name,
        AdUnitId: placementId,
        ThirdPartyAdPlacementId: adInfo.network_placement_id,
        NetworkPlacement: adInfo.adsource_id,
        CountryCode: adInfo.country,
    ));
}

ATBannerAd.Instance.setAdRevenueListener(TOPON_BANNER_PLACEMENT_ID, new TopOnRevenueListener());

自定义平台事件

对于没有 CloudX SDK 内置常量的 provider,请使用 Custom;AdMob、Google Ad Manager、InMobi 和 TopOn 已有内置常量。这里的值只表示 provider 名称,例如 CloudXRevenuePlatform.Custom("TradPlus")CloudXRevenuePlatform.Custom("Nimbus")。请保持名称稳定,便于 CloudX 一致归类该 provider 的收益。

不要把金额或币种放进 provider 名称里。如果一条 TradPlus 展示带来 USD 0.01 收入,请传 Platform: CloudXRevenuePlatform.Custom("TradPlus")Revenue: 0.01CurrencyCode: "USD"。如果来源返回 CPM/eCPM,请先除以 1_000.0

private static bool ReportCustomRevenueEvent(
    string providerName,
    double revenue,
    string adFormat,
    string currencyCode,
    string adUnitId,
    string placementId)
{
    return CloudXSdk.ReportRevenueData(new CloudXRevenueData(
        Platform: CloudXRevenuePlatform.Custom(providerName),
        Revenue: revenue,
        AdFormat: adFormat,
        CurrencyCode: currencyCode,
        Precision: CloudXRevenuePrecision.PublisherDefined,
        AdUnitId: adUnitId,
        ThirdPartyAdPlacementId: placementId,
    ));
}