概览

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

Maven Central

安装

需要 Android API 23+ 和 Java 8+。

CloudX SDK 及其适配器发布在 Maven Central (https://repo1.maven.org/maven2/)。请确保您的项目在 settings.gradle.kts 中从该仓库解析依赖:

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()   // https://repo1.maven.org/maven2/
    }
}

然后将 CloudX SDK 添加到您应用的 build.gradle:

dependencies {
    implementation("io.cloudx:sdk:4.6.0")

    // 广告网络适配器
    implementation("io.cloudx:adapter-digitalturbine:8.4.7.0")     // Digital Turbine Marketplace SDK 8.4.7
    implementation("io.cloudx:adapter-googlewaterfall:25.2.0.5")   // Google Mobile Ads SDK 25.2.0
    implementation("io.cloudx:adapter-inmobi:11.4.0.1")            // InMobi SDK 11.4.0
    implementation("io.cloudx:adapter-magnite:1.0.0.1")            // Magnite Ads SDK 1.0.0
    implementation("io.cloudx:adapter-meta:6.22.0.0")              // Meta Audience Network 6.22.0
    implementation("io.cloudx:adapter-mintegral:17.1.71.0")        // Mintegral SDK 17.1.71
    implementation("io.cloudx:adapter-mobilefuse:1.11.0.1")        // MobileFuse SDK 1.11.0
    implementation("io.cloudx:adapter-moloco:4.11.0.0")            // Moloco SDK 4.11.0
    implementation("io.cloudx:adapter-pangle:8.2.0.4.0")           // Pangle SDK 8.2.0.4
    implementation("io.cloudx:adapter-taurusx:1.18.3.0")           // TaurusX SDK 1.18.3
    implementation("io.cloudx:adapter-unityads:4.19.0.1")          // Unity Ads SDK 4.19.0
    implementation("io.cloudx:adapter-verve:3.9.0.1")              // Verve HyBid SDK 3.9.0
    implementation("io.cloudx:adapter-vungle:7.7.7.0")             // Vungle SDK 7.7.7
}

初始化

// 使用应用密钥初始化
CloudX.initialize(
    configuration = CloudXInitializationConfiguration.builder("your-app-key-here")
        .build(),
    listener = object : CloudXInitializationListener {
        override fun onInitialized(configuration: CloudXSdkConfiguration) {
            Log.d("CloudX", "CloudX SDK 初始化成功")
        }

        override fun onInitializationFailed(cloudXError: CloudXError) {
            Log.e("CloudX", "CloudX SDK 初始化失败: ${cloudXError.message}")
        }
    }
)

广告格式

CloudX 支持横幅、MREC、插屏、激励视频、原生和 App Open 广告集成。请使用对应广告格式指南查看实现细节:

广告信息 (CloudXAd)

CloudXAd 对象在监听器回调中传递,包含已加载/已展示广告的信息:

属性类型描述
adFormatCloudXAdFormat广告格式 (BANNER、MREC、INTERSTITIAL、REWARDED、NATIVE、APP_OPEN)
adUnitIdString广告单元 ID
networkNameString获胜广告网络的名称
networkPlacementString?网络特定的广告位 ID
placementString?通过 setPlacement() 设置的自定义广告位
revenueDouble竞价时收入估算(以美元计价)
adValuesMap<String, String>SDK 提供的广告元数据,可用于 Trusted Arbiter 等功能
override fun onAdLoaded(cloudXAd: CloudXAd) {
    Log.d("CloudX", "广告格式: ${cloudXAd.adFormat}")
    Log.d("CloudX", "网络: ${cloudXAd.networkName}")
    Log.d("CloudX", "竞价时收入: ${cloudXAd.revenue}")
}

错误处理

所有 SDK 错误都以 CloudXError 对象的形式在监听器回调中返回:

属性类型描述
codeCloudXErrorCode错误类别
messageString人类可读的描述
causeThrowable?可选的底层异常
formattedMessageString预格式化的消息,包含代码和描述

错误代码类别

范围类别常见代码
0一般INTERNAL_ERROR
100-199网络NETWORK_ERRORNETWORK_TIMEOUTNETWORK_SERVER_ERRORNETWORK_NO_CONNECTION
200-299初始化NOT_INITIALIZEDSDK_DISABLEDNO_ADAPTERS_FOUNDINVALID_APP_KEY
300-399广告加载NO_FILLINVALID_AD_UNITADS_DISABLED
400-499展示AD_NOT_READYAD_ALREADY_SHOWING
600-699适配器ADAPTER_NO_FILLADAPTER_TIMEOUTADAPTER_LOAD_TIMEOUTADAPTER_INITIALIZATION_ERROR

高级功能

调试日志

CloudX.setMinLogLevel(CloudXLogLevel.DEBUG)  // 启用调试日志
CloudX.setMinLogLevel(CloudXLogLevel.NONE)   // 禁用所有日志

日志级别: VERBOSE < DEBUG < INFO < WARN < ERROR < NONE

使用标签 CloudX 过滤 logcat 以查看 SDK 日志。

发布商上报收入数据

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

字段必填描述
platformCloudXRevenuePlatform.ADMOBCloudXRevenuePlatform.INMOBICloudXRevenuePlatform.TOPONCloudXRevenuePlatform.custom("MyProvider")
revenue单次展示收入,使用传入货币;不是 CPM/eCPM
adFormat广告格式字符串,例如 bannermrecinterstitialrewardednativeapp_open
currencyCodeISO 4217 货币代码(如已知)
precisionCloudXRevenuePrecision.EXACTESTIMATEDPUBLISHER_DEFINEDUNDEFINED
networkName获胜广告网络名称(如已知)
adUnitId聚合平台广告单元 ID
thirdPartyAdPlacementId广告网络侧广告单元或 placement ID
creativeId广告网络返回的创意 ID
networkPlacement广告网络 placement 标识
countryCode用户国家代码(如已知)
userSegment用户分群(如已知)

当事件被 CloudX 收益链路接受时,reportRevenueData() 返回 true。如果 SDK 尚未初始化、服务端未启用收益跟踪,或平台名称为空,则返回 false。接受事件不保证一定送达。

AdMob paid event

AdMob Android 的 AdValue.valueMicros 以所提供货币的微单位上报,因此请先除以 1_000_000.0,再传给 CloudX。

private fun Int.toCloudXRevenuePrecision(): CloudXRevenuePrecision = when (this) {
    AdValue.PrecisionType.PRECISE -> CloudXRevenuePrecision.EXACT
    AdValue.PrecisionType.ESTIMATED -> CloudXRevenuePrecision.ESTIMATED
    AdValue.PrecisionType.PUBLISHER_PROVIDED -> CloudXRevenuePrecision.PUBLISHER_DEFINED
    else -> CloudXRevenuePrecision.UNDEFINED
}

private fun reportAdMobPaidEvent(
    adValue: AdValue,
    adFormat: String,
    adUnitId: String,
    responseInfo: ResponseInfo?,
): Boolean {
    val servedBy = responseInfo?.loadedAdapterResponseInfo

    return CloudX.reportRevenueData(
        CloudXRevenueData.builder(
            platform = CloudXRevenuePlatform.ADMOB,
            revenue = adValue.valueMicros / 1_000_000.0,
            adFormat = adFormat,
        )
            .currencyCode(adValue.currencyCode)
            .precision(adValue.precisionType.toCloudXRevenuePrecision())
            .networkName(servedBy?.adSourceName)
            .adUnitId(adUnitId)
            .thirdPartyAdPlacementId(servedBy?.adSourceInstanceName)
            .build(),
    )
}

bannerView.setOnPaidEventListener { adValue ->
    reportAdMobPaidEvent(
        adValue = adValue,
        adFormat = "banner",
        adUnitId = adUnitId,
        responseInfo = bannerView.responseInfo,
    )
}

InMobi impression event

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

private var latestInMobiMetaInfo: AdMetaInfo? = null

override fun onAdFetchSuccessful(ad: InMobiBanner, info: AdMetaInfo) {
    latestInMobiMetaInfo = info
}

override fun onAdImpression(ad: InMobiBanner) {
    latestInMobiMetaInfo?.let { metaInfo ->
        reportInMobiImpression(
            metaInfo = metaInfo,
            adFormat = "banner",
            placementId = inMobiPlacementId.toString(),
        )
    }
    latestInMobiMetaInfo = null
}

private fun reportInMobiImpression(
    metaInfo: AdMetaInfo,
    adFormat: String,
    placementId: String,
): Boolean =
    CloudX.reportRevenueData(
        CloudXRevenueData.builder(
            platform = CloudXRevenuePlatform.INMOBI,
            revenue = metaInfo.bid,
            adFormat = adFormat,
        )
            .precision(CloudXRevenuePrecision.ESTIMATED)
            .thirdPartyAdPlacementId(placementId)
            .creativeId(metaInfo.creativeID)
            .build(),
    )

对于 InMobi 插屏和激励视频广告,请在 InterstitialAdEventListener 中使用相同模式:在 onAdFetchSuccessful 中保存 AdMetaInfo,然后在 onAdImpression 中上报。

TopOn revenue event

TopOn Android 会在 onAdRevenuePaid(ATAdInfo) 中提供收入。请在广告对象上设置 ATAdRevenueListener,并把 adInfo.getPublisherRevenue() 直接传给 CloudX。不要像 AdMob 微单位或 CPM 那样再做除法。

private fun reportTopOnRevenue(
    adInfo: ATAdInfo,
    adFormat: String,
): Boolean =
    CloudX.reportRevenueData(
        CloudXRevenueData.builder(
            platform = CloudXRevenuePlatform.TOPON,
            revenue = adInfo.getPublisherRevenue(),
            adFormat = adFormat,
        )
            .currencyCode(adInfo.getCurrency())
            .networkName(adInfo.getNetworkName())
            .adUnitId(adInfo.getPlacementId())
            .thirdPartyAdPlacementId(adInfo.getNetworkPlacementId())
            .networkPlacement(adInfo.getAdsourceId())
            .build(),
    )

mBannerView.setAdRevenueListener(object : ATAdRevenueListener {
    override fun onAdRevenuePaid(adInfo: ATAdInfo) {
        reportTopOnRevenue(
            adInfo = adInfo,
            adFormat = "banner",
        )
    }
})

对于其他 TopOn 广告格式,请在已加载的广告对象上设置相同 listener,并传入对应的 CloudX adFormat

自定义平台事件

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

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

private fun reportCustomRevenueEvent(
    providerName: String,
    revenue: Double,
    adFormat: String,
    currencyCode: String,
    adUnitId: String,
    placementId: String,
): Boolean =
    CloudX.reportRevenueData(
        CloudXRevenueData.builder(
            platform = CloudXRevenuePlatform.custom(providerName),
            revenue = revenue,
            adFormat = adFormat,
        )
            .currencyCode(currencyCode)
            .precision(CloudXRevenuePrecision.PUBLISHER_DEFINED)
            .adUnitId(adUnitId)
            .thirdPartyAdPlacementId(placementId)
            .build(),
    )

展示级收入追踪

在任何广告格式上设置 revenueListener 以接收收入回调。CloudXAd.revenue 包含以美元计价的竞价时收入估算。

bannerAd.revenueListener = object : CloudXAdRevenueListener {
    override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
        Log.d("CloudX", "竞价时收入: ${cloudXAd.revenue},来自 ${cloudXAd.networkName}")
    }
}

适用于所有广告格式(横幅、MREC、插屏、激励视频)。

测试模式

测试模式由服务器控制,通过设备白名单实现。这提供了更好的安全性,并能控制哪些设备接收测试广告。

启用测试模式:

  1. 初始化 SDK 并检查 logcat 中的设备广告 ID:

    [CloudX][AdvertisingIdProvider] Device IFA for test whitelisting: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX (LAT: false)
    
  2. 复制广告 ID 并将其添加到 CloudX 服务器控制台的设备白名单中

  3. SDK 将自动为测试模式配置适配器,并在竞价请求中包含测试标志

注意: 测试模式由服务器决定,因此您无需在开发和生产构建之间更改任何代码。

隐私合规

CloudX SDK 通过从 SharedPreferences 读取标准 IAB 隐私字符串来支持 GDPR 和 CCPA 隐私合规。这些值通常由您的同意管理平台(CMP)自动设置,如 Google UMP、OneTrust 或 Sourcepoint。

工作原理

SDK 自动检测用户位置并读取同意信号:

  1. 欧盟用户 (GDPR):根据 IAB 全球供应商列表 检查 TCF v2 目的 1 和 2 的同意和供应商同意(CloudX 供应商 ID:1510
  2. 美国用户 (CCPA):检查销售/共享退出信号
  3. 其他地区:不应用限制

当同意被拒绝或用户选择退出时,SDK 会从广告请求中删除个人身份信息:

  • 广告 ID (GAID) 被清除
  • 地理坐标(经纬度)被删除
  • 用户键值对不发送
  • 哈希用户 ID 会从发送给竞价方的请求中移除,并且不会写入展示级报表

支持的隐私密钥

密钥标准描述
IABGPP_HDR_GppStringGPP全球隐私平台字符串(现代)
IABGPP_GppSIDGPP部分 ID(例如,“2” 代表欧盟,“7” 代表美国国家,“8” 代表美国加州)
IABTCF_TCStringTCF v2GDPR 同意字符串(传统)
IABTCF_gdprAppliesTCF v2GDPR 是否适用(1 = 是,0 = 否)
IABUSPrivacy_StringUS PrivacyCCPA 隐私字符串(传统,例如 “1YNN”)

注意:当 GPP(现代标准)和传统 TCF/US Privacy 字符串同时存在时,SDK 优先使用 GPP。

手动隐私 API

如果您自行管理用户同意(不使用 CMP),可以直接设置 GDPR 和 CCPA 隐私状态。这些方法必须在 SDK 初始化之前调用。

// GDPR 同意:true、false 或 null(回退到 CMP)
CloudX.setHasUserConsent(true)

// CCPA do-not-sell:true、false 或 null(回退到 CMP)
CloudX.setDoNotSell(true)

用户定向

// 设置哈希用户 ID 用于定向
CloudX.setHashedUserId("hashed-user-id")

// 设置自定义用户键值对
CloudX.setUserKeyValue("age", "25")
CloudX.setUserKeyValue("gender", "male")
CloudX.setUserKeyValue("location", "US")

// 设置自定义应用键值对
CloudX.setAppKeyValue("app_version", "1.0.0")
CloudX.setAppKeyValue("user_level", "premium")

// 清除所有自定义键值对
CloudX.clearAllKeyValues()

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

用户和应用键值对也会出现在请求活动导出中。使用 setUserKeyValue 设置 SDK 会话范围内的用户属性,使用 setAppKeyValue 设置 SDK 会话范围内的应用属性。SDK 会在之后的每个竞价请求中发送当前值。

身份透传

通过 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 不是同一回事。

CloudX.setUserKeyValue("uidapi.com", uid2Token)
CloudX.setUserKeyValue("euid.eu", euidToken)
CloudX.setUserKeyValue("liveramp.com", liveRampEnvelope)
CloudX.setUserKeyValue("id5-sync.com", id5Id)

如需为单个广告对象或加载添加元数据,请在调用 load 前使用 setExtraParameter

adView.setExtraParameter("requestId", "request-456")
adView.setExtraParameter("impressionKey", "impression-789")
adView.load()

额外参数会保留在该广告对象上,直到被修改或清除。SDK 会为每次加载创建参数快照。CloudX 会在请求导出的 extra_parameters 列中返回完整参数对象。保留的 tags 键还会控制基于标签的路由;请使用其他键存储关联元数据。

只有当整个紧凑 JSON 对象不超过 256 个 UTF-8 字节时,CloudX 才会存储对应的参数对象。每个导出列分别适用该限制,且计数包含所有键、值、引号、分隔符和大括号的合计大小,并非每个键值对可各用 256 字节。如果隐私规则禁止持久化发布商数据,或者对象格式错误或过大,则对应导出单元格为空。请勿包含原始个人数据、密钥或同意字符串。

技术支持

如需支持,请联系 support@cloudx.io