概览
CloudX Flutter SDK 设置和核心功能概览
CloudX Flutter SDK 可让您通过横幅、MREC、插屏和激励视频广告,在 iOS 和 Android 上为 Flutter 应用变现。
安装
要求
| 要求 | 版本 |
|---|---|
| Dart SDK | >=2.17.1 <4.0.0 |
| Flutter | >=3.0.0 |
| iOS | 13.0+,Xcode 16.0+,Swift 6.0+ |
| Android | minSdk 23 |
Dart 版本范围特意放宽,使仍在较旧 Flutter LTS 线上的应用无需升级整个工具链即可接入 cloudx_flutter。您的应用实际的 iOS 下限取插件与所用 Flutter 版本中较高的一个:Flutter 3.47 所带引擎要求 iOS 15.0,因此使用该版本的应用需要在 Podfile 中设置 platform :ios, '15.0'。
个别适配器会抬高上述下限:部分适配器要求比插件本身更高的 compileSdk、minSdk、Kotlin 或 Xcode 版本,各适配器页面会给出各自的要求。较新的 Flutter 版本大多可以满足,因为 Flutter 3.47 要求 Gradle 8.14、AGP 8.11.1 和 Kotlin 2.2.20。设置版本下限前,请查阅您所启用适配器的页面。
在 pubspec.yaml 中添加 SDK:
dependencies:
cloudx_flutter: ^3.9.0然后运行:
flutter pub get原生 SDK 版本
插件为每个平台固定一个 CloudX 原生 SDK。插件自身版本跟随 iOS CloudXCore 线;Android 的固定版本在更新日志中按版本列出。
| 平台 | 依赖 | 版本 |
|---|---|---|
| Android | io.cloudx:sdk | 4.7.0 |
| iOS | CloudXCore | 3.9.0 |
iOS 设置
CloudXCore pod 会通过插件的 podspec 自动引入。广告网络适配器是独立的 pod,请按启用的广告网络逐个添加到 ios/Podfile 的 target 'Runner' 块中。
target 'Runner' do
# ... 现有 Flutter 配置 ...
# CloudX 广告网络适配器(按需添加)
pod 'CloudXMetaAdapter', '~> 6.22.0.0' # Meta Audience Network 6.22.0
pod 'CloudXVungleAdapter', '~> 7.7.6.0' # VungleAds 7.7.6
pod 'CloudXInMobiAdapter', '~> 11.4.1.0' # InMobiSDK 11.4.1
pod 'CloudXMintegralAdapter', '~> 8.1.6.0' # MintegralAdSDK 8.1.6
pod 'CloudXUnityAdsAdapter', '~> 4.19.0.0' # UnityAds 4.19.0
pod 'CloudXMagniteAdapterV2', '~> 1.0.0.1' # MagniteSDK 1.0.0
pod 'CloudXMobileFuseAdapter', '~> 1.11.0.1' # MobileFuseSDK 1.11.0
pod 'CloudXMolocoAdapter', '~> 4.8.0.0' # MolocoSDKiOS 4.8.0
pod 'CloudXVerveAdapter', '~> 3.9.0.0' # HyBid 3.9.0
pod 'CloudXDigitalTurbineAdapter', '~> 8.4.8.0' # Fyber Marketplace SDK 8.4.8
pod 'CloudXGoogleWaterfallAdapter', '~> 13.6.0.4' # Google Mobile Ads SDK 13.6.0
pod 'CloudXPangleAdapter', '~> 8.2.0.7.0' # Ads-Global(Pangle / 字节跳动)8.2.0.7
pod 'CloudXTaurusXAdapter', '~> 1.18.2.0' # TaurusX SDK 1.18.2
end各适配器页面给出该网络自身的要求:iOS 与 Xcode 版本下限、Info.plist 配置项、SKAdNetwork 标识符以及已知问题。iOS 集成指南为原生应用列出的是同一批 pod,因此 Flutter 应用安装的内容与 iOS 应用完全一致。
适配器按 <网络 SDK 版本>.<适配器修订号> 独立编号,与 CloudXCore 各自演进,因此适配器版本无需与核心版本一致。SDK 至少需要一个适配器才能投放广告。
Google 适配器需要在 ios/Runner/Info.plist 中以 GADApplicationIdentifier 提供您的 AdMob 应用 ID。google_mobile_ads 包单独使用时同样需要该项,因此只要应用中包含其中之一就请添加:
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy</string>然后安装 pod:
cd ios && pod installApp Transport Security
CloudX SDK 不需要禁用应用传输安全(App Transport Security)。如果某个聚合广告网络通过特定域名的纯 HTTP 提供素材,请在 ios/Runner/Info.plist 中为该域名单独配置例外,而不要在整个应用范围允许任意加载(全局 NSAllowsArbitraryLoads 会削弱应用的传输安全,并可能引起 App Store 审核关注):
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>example-ad-network.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>Android 设置
插件已经引入 io.cloudx:sdk,因此您只需添加需要的广告网络适配器,在应用模块的 dependencies 块中按启用的广告网络逐个声明,通常是 android/app/build.gradle.kts。
dependencies {
// CloudX 广告网络适配器(按需添加)
implementation("io.cloudx:adapter-bigo:6.0.1.0") // BIGO Ads SDK 6.0.1
implementation("io.cloudx:adapter-digitalturbine:8.4.7.1") // Digital Turbine Marketplace SDK 8.4.7
implementation("io.cloudx:adapter-googlewaterfall:25.4.0.0") // Google Mobile Ads SDK 25.4.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.1") // Mintegral SDK 17.1.71
implementation("io.cloudx:adapter-mobilefuse:1.12.0.0") // MobileFuse SDK 1.12.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
}各适配器页面给出该网络自身的要求:compileSdk 或 minSdk 下限、额外的 Maven 仓库、manifest 配置以及已知问题。Android 集成指南为原生应用列出的是同一批制品,因此 Flutter 应用声明的内容与 Android 应用完全一致。
SDK 至少需要一个适配器才能投放广告。适配器按 <网络 SDK 版本>.<适配器修订号> 独立编号,与核心 SDK 各自演进。
任一 Google 适配器都需要在 android/app/src/main/AndroidManifest.xml 中声明 Google 应用标识,接入 AdMob 需求的应用填入自己的 AdMob 应用 ID。即使没有安装 CloudX 的 Google 适配器,google_mobile_ads 包也需要该声明。下面两种形式都没有时,初始化会在 Google SDK 启动之前失败:
<application>
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy" />
</application>仅接入 Google Ad Manager 需求、没有 AdMob 应用 ID 的应用,改为声明布尔值 com.google.android.gms.ads.AD_MANAGER_APP。两者是二选一,请勿同时设置。
<application>
<meta-data
android:name="com.google.android.gms.ads.AD_MANAGER_APP"
android:value="true" />
</application>额外的 Maven 仓库
部分广告网络的 SDK 不在 Maven Central 上发布,对应适配器页面会给出需要添加的仓库地址。请按您的 Gradle 模板声明仓库的位置添加:项目级 android/build.gradle.kts 或 android/build.gradle 的 allprojects { repositories { ... } },或 android/settings.gradle.kts 或 android/settings.gradle 的 dependencyResolutionManagement.repositories。新建项目由 Flutter 生成 Kotlin DSL 文件名,较早的项目则是 Groovy 文件名。较新的模板会把仓库集中在 settings 文件中声明,此时项目级声明会被忽略或拒绝。
Mintegral、Verve、Pangle 与 TaurusX 适配器各需要一个。请添加到您的模板已有的那个块中,不要两处都加。Groovy 模板下的条目是同样的地址,写成 maven { url '...' }。
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
// io.cloudx:adapter-mintegral
maven { url = uri("https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_oversea") }
// io.cloudx:adapter-verve
maven { url = uri("https://verve.jfrog.io/artifactory/verve-gradle-release") }
// io.cloudx:adapter-pangle
maven { url = uri("https://artifact.bytedance.com/repository/pangle") }
// io.cloudx:adapter-taurusx
maven { url = uri("https://artifact.taurusx.com/artifactory/taurusx-sdk/") }
}
}allprojects {
repositories {
google()
mavenCentral()
// io.cloudx:adapter-mintegral
maven { url = uri("https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_oversea") }
// io.cloudx:adapter-verve
maven { url = uri("https://verve.jfrog.io/artifactory/verve-gradle-release") }
// io.cloudx:adapter-pangle
maven { url = uri("https://artifact.bytedance.com/repository/pangle") }
// io.cloudx:adapter-taurusx
maven { url = uri("https://artifact.taurusx.com/artifactory/taurusx-sdk/") }
}
}初始化
在加载任何广告之前初始化 SDK。通常放在主 Widget 的 initState 中:
import 'package:cloudx_flutter/cloudx.dart';
// 可选:启用详细日志(仅用于开发)
CloudX.setMinLogLevel(CloudXLogLevel.verbose);
// 使用您的应用密钥初始化
final result = await CloudX.initialize(appKey: 'YOUR_APP_KEY');
if (result.success) {
print('CloudX initialized');
} else {
print('CloudX init failed: ${result.errorCodeName} ${result.message}');
}CloudX.initialize() 返回 CloudXInitializationResult。请检查 result.success。失败时,errorCode、errorCodeName 和 message 会带上原生 SDK 自身的错误信息,因此可以区分应用密钥错误与网络失败;成功时这三个字段均为 null。该调用不会抛出异常,重复调用会返回首次调用的结果。
其他初始化工具方法:
final initialized = await CloudX.isInitialized();
final version = await CloudX.getVersion();广告格式
CloudX Flutter 支持横幅广告、MREC、插屏广告和激励视频广告。具体接入方式请参阅各格式指南:
广告信息(CloudXAd)
广告回调会收到一个 CloudXAd 对象:
| 属性 | 类型 | 说明 |
|---|---|---|
adUnitId | String | 广告单元 ID |
adFormat | CloudXAdFormat | 广告格式;用 adFormat.value 读取上报的名称 |
networkName | String | 竞得的广告网络名称 |
networkPlacement | String? | 广告网络侧的广告位 ID |
creativeId | String? | 用于素材级问题排查的素材标识符 |
placement | String? | 您的集成设置的自定义广告位 |
revenue | double | 收入(美元) |
adValues | Map<String, String> | SDK 提供的广告元数据,供 Trusted Arbiter 等功能使用 |
当需求方未返回素材 ID 时,creativeId 为 null。它与您在 reportRevenueData 中传入的 creativeId 不同,后者描述的是在 CloudX 广告流程之外竞得的展示。
CloudXAdFormat 包含 banner、mrec、interstitial 和 rewarded 四个常量。
高级功能
单次加载的额外参数
为单次广告加载附加广告网络或服务端配置。每种格式都有各自的设置方法,并通过广告单元 ID 定位:
CloudX.setBannerExtraParameter(
adUnitId: bannerAdUnitId,
key: 'requestId',
value: 'request-456',
);
CloudX.setMrecExtraParameter(
adUnitId: mrecAdUnitId,
key: 'section',
value: 'article_body',
);
CloudX.setInterstitialExtraParameter(
adUnitId: interstitialAdUnitId,
key: 'bidFloor',
value: 0.5,
);
CloudX.setRewardedExtraParameter(
adUnitId: rewardedAdUnitId,
key: 'keywords',
value: ['sports', 'scores'],
);value 可以是 null、bool、int、double、String,或由这些类型构成的列表和映射。这些值在加载运行时被读取,因此请在加载之前设置;对同一个键再次设置会覆盖此前的值。
每种格式都可以在首次加载之前调用设置方法。在广告尚未创建时设置的值会按广告单元暂存,并在创建广告时、加载之前应用:插屏广告和激励视频广告对应首次 loadInterstitial 或 loadRewarded,横幅广告和 MREC 则对应 createBanner 或 createMrec,由创建发起的那次加载同样会带上这些值。暂存的值会在广告单元销毁时一并丢弃。
CloudX 会在请求导出的 extra_parameters 列中返回完整的参数集合。保留键 tags 同时用于基于标签的路由;关联用的元数据请使用其他键名。请勿包含原始个人数据、密钥或同意串。
只有当整个紧凑 JSON 对象不超过 256 个 UTF-8 字节时,CloudX 才会存储该参数集合。该限制对每个导出列分别生效,user_key_values 和 app_key_values 同样适用,并且计入所有键、值、引号、分隔符和大括号的合计大小,并非每个键值对可各用 256 字节。参数集合过大、格式错误,或隐私规则禁止持久化时,对应的导出单元格为空;竞价本身不受影响。
错误处理
所有错误回调都会收到带有 code 和 message 属性的 CloudXError:
| 范围 | 类别 | 常见错误码 |
|---|---|---|
| 0 | 通用 | internalError |
| 100-199 | 网络 | networkError, networkTimeout, networkServerError, networkNoConnection |
| 200-299 | 初始化 | notInitialized, noAdaptersFound, sdkDisabled, invalidAppKey |
| 300-399 | 广告加载 | noFill, invalidAdUnit, adsDisabled, loadNotAllowedWhileShowing, loadFailed, loadRejectedConcurrency, loadRejectedTooManyConcurrentLoads |
| 400-499 | 展示 | adNotReady, adAlreadyShowing, dontKeepActivitiesEnabled, adNotFound, displayHostUnavailable |
| 600-699 | 适配器 | adapterNoFill, adapterLoadTimeout, adapterTimeout, adapterInitializationError |
在同一格式的全屏广告展示期间发起的加载会被拒绝,错误码为 loadNotAllowedWhileShowing(303)。当某个广告单元已有加载在进行中时,新发起的加载也可能被拒绝,而两个平台对此使用不同的编号:Android 为 loadRejectedConcurrency(305),iOS 为 loadRejectedTooManyConcurrentLoads(306),且互不上报对方的值,因此两个都要处理。请对每个广告单元一次只发起一次加载,并等待回调。
CloudXError.codeName 会带上 SDK 为该错误码定义的名称,例如 NO_FILL,因此日志会显示为 NO_FILL[302] 而不是 302。当插件无法为该错误码命名时,它为 null。
完整错误码列表见 CloudXErrorCode。
收入追踪
所有广告格式都提供收入回调。CloudXAd 包含 adUnitId、adFormat、networkName、revenue(美元)、可选 placement 以及可选 networkPlacement:
CloudX.setInterstitialListener(CloudXInterstitialListener(
onAdRevenuePaid: (ad) {
trackRevenue(ad.revenue, ad.networkName, ad.adUnitId);
},
// ... 其他回调
));发布商上报的收入数据
CloudX.reportRevenueData 会把其他中介平台向您的应用上报的展示收入转发给 CloudX,使 CloudX 了解该需求方的实际价格。AdMob 和 Ad Manager 的 Trusted Arbiter 出价依赖这些历史数据来定价,因此该上报是必需的。
final accepted = await CloudX.reportRevenueData(CloudXRevenueData(
platform: CloudXRevenuePlatform.adMob,
revenue: 0.0123,
adFormat: 'interstitial',
currencyCode: 'USD',
precision: CloudXRevenuePrecision.exact,
networkName: 'admob',
adUnitId: 'ca-app-pub-0000000000000000/1111111111',
));| 字段 | 类型 | 说明 |
|---|---|---|
platform | CloudXRevenuePlatform | 必填。adMob、gam、inMobi、topOn,或 CloudXRevenuePlatform.custom('name') |
revenue | double | 必填。单次展示的收入,单位为 currencyCode |
adFormat | String | 必填。例如 banner、interstitial、rewarded |
currencyCode | String? | revenue 的 ISO 4217 货币代码,例如 USD |
precision | CloudXRevenuePrecision? | exact、estimated、publisherDefined 或 undefined |
networkName | String? | 竞得的广告网络(如已知) |
adUnitId | String? | 该中介平台的广告单元 ID;请上报您传给出价的同一个 ID |
thirdPartyAdPlacementId | String? | 广告网络侧的广告位 ID |
creativeId | String? | 广告网络的素材 ID |
networkPlacement | String? | 广告网络广告位标识 |
countryCode | String? | 用户所在国家,ISO 3166-1 alpha-2 |
userSegment | String? | 您自定义的用户分层字符串 |
当数据被丢弃时该调用返回 false,例如 SDK 尚未初始化、平台名称为空,或 revenue 不是有限数值。对于 Google 需求方,请将 PrecisionType.precise 映射为 exact,estimated 映射为 estimated,publisherProvided 映射为 publisherDefined,其余映射为 undefined。
Trusted Arbiter
CloudX.arbiter 会把已加载的 CloudX 广告与您自行接入平台的出价进行比较,并返回应当展示的平台。完整流程(包括何时运行以及如何把 Google 付费事件回传给 CloudX)参见 Trusted Arbiter。
用户定向
import 'package:cloudx_flutter/cloudx.dart';
// 设置哈希用户 ID(传 null 可清除)
CloudX.setHashedUserId('hashed-user-id');
// 设置自定义键值对
CloudX.setUserKeyValue('age_group', '25-34');
CloudX.setAppKeyValue('app_version', '1.0.0');
// 清除所有自定义键值对
CloudX.clearAllKeyValues();哈希用户 ID 是由发布商提供的假名标识符。当适用的隐私信号允许时,CloudX 会在请求和展示活动导出中以 hashed_user_id 返回竞价时记录的值。使用 auction_id 关联这些导出。您可以使用该 ID 将 CloudX 活动与自己的用户数据分群关联。未设置 ID、隐私信号阻止持久化或值超过 128 个字符时,导出值为空。请勿传递未经哈希的个人数据。
身份透传
通过 setUserKeyValue 传入 UID 2.0、EUID、LiveRamp、ID5 和 Intent IQ。有值时设置一次,刷新后再设一次。
| 键 | 传入内容 |
|---|---|
uidapi.com | UID2 广告 token,不要传 refresh token。不要解密。UID2 文档 |
euid.eu | EUID 广告 token,不要传 refresh token。不要解密。EUID 文档 |
liveramp.com | LiveRamp ATS 信封,不要传 RampID。LiveRamp 文档 |
id5-sync.com | ID5 通用 UID。不要传 0。ID5 文档 |
intentiq.com | Intent IQ ID(IIQ ID),来自你的 Intent IQ 集成。Intent IQ 文档 |
CloudX 不会生成这些 ID。请先用 UID2、EUID、LiveRamp ATS、ID5 或 Intent IQ 生成,再把字符串传进来。这与哈希用户 ID 不是同一回事。
CloudX.setUserKeyValue('uidapi.com', uid2Token);
CloudX.setUserKeyValue('euid.eu', euidToken);
CloudX.setUserKeyValue('liveramp.com', liveRampEnvelope);
CloudX.setUserKeyValue('id5-sync.com', id5Id);
CloudX.setUserKeyValue('intentiq.com', intentIQId);隐私合规
从 NSUserDefaults / SharedPreferences 读取 IAB GPP、TCF v2 和 US Privacy 字符串(通常由 CMP 写入)。
| 键 | 标准 | 说明 |
|---|---|---|
IABGPP_HDR_GppString | GPP | 全球隐私平台字符串 |
IABGPP_GppSID | GPP | 部分 ID |
IABTCF_TCString | TCF v2 | GDPR 同意字符串 |
IABUSPrivacy_String | US Privacy | CCPA 字符串 |
手动 API: 当您不使用 CMP,或需要覆盖直到清除时,使用 CloudX.setHasUserConsent(bool?) 和 CloudX.setDoNotSell(bool?)。null 会移除覆盖;解析顺序与原生 SDK 一致(已存储的 IAB 字符串以及这些覆盖)。可在 CloudX.initialize() 之前调用。
CloudX.setHasUserConsent(true);
CloudX.setDoNotSell(false);
CloudX.setHasUserConsent(null);测试模式
测试模式由服务端控制,通过设备白名单实现:
- 启用详细日志后初始化 SDK
- 在控制台日志中找到设备广告 ID
- 在 CloudX 控制台将该设备加入白名单
调试日志
import 'package:cloudx_flutter/cloudx.dart';
// 启用详细日志(在 initialize 之前调用)
CloudX.setMinLogLevel(CloudXLogLevel.verbose);
// 可用级别:verbose、debug、info、warn、error、none技术支持
如需支持,请联系 support@cloudx.io