概览

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

pub package

CloudX Flutter SDK 可让您通过横幅、MREC、插屏和激励视频广告,在 iOS 和 Android 上为 Flutter 应用变现。

安装

要求

以下版本与 pub.dev 上已发布的软件包约束一致:

要求版本
Dart SDK>=2.17.1 <4.0.0
Flutter>=3.0.0
iOS13.0+
AndroidminSdk 23 (API 23)

Dart 版本范围刻意放宽,以便仍在较旧 Flutter LTS 线上的应用可以添加 cloudx_flutter,而不必升级整套工具链。

pubspec.yaml 中添加 SDK:

dependencies:
  cloudx_flutter: ^2.2.3

然后运行:

flutter pub get

iOS 设置

ios/Podfile 中添加广告网络适配器 Pod:

target 'Runner' do
  # ... 现有配置 ...

  # CloudX 广告网络适配器(按需添加;版本需与原生栈一致)
  pod 'CloudXMetaAdapter', '~> 2.2.3'
  pod 'CloudXVungleAdapter', '~> 2.2.3'
  pod 'CloudXInMobiAdapter', '~> 2.2.3'
  pod 'CloudXMintegralAdapter', '~> 2.2.3'
  pod 'CloudXUnityAdsAdapter', '~> 2.2.3'
  pod 'CloudXRenderer', '~> 2.2.3'
end

然后安装 Pod:

cd ios && pod install

App 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 设置

将 CloudX SDK 和适配器依赖添加到应用模块 —— 通常是 android/app/build.gradleandroid/app/build.gradle.kts

dependencies {
    // CloudX Android SDK(版本应与 cloudx_flutter 锁定的原生发行版一致)
    implementation("io.cloudx:sdk:2.2.3")

    // 广告网络适配器(按需添加)
    implementation("io.cloudx:adapter-meta:2.2.3")
    implementation("io.cloudx:adapter-vungle:2.2.3")
    implementation("io.cloudx:adapter-inmobi:2.2.3")
    implementation("io.cloudx:adapter-mintegral:2.2.3")
    implementation("io.cloudx:adapter-unityads:2.2.3")
}

Mintegral 适配器与 Maven 仓库

如果您引入 io.cloudx:adapter-mintegral,Gradle 必须从 Mintegral 自己的 Maven 服务器(而不是 Maven Central)解析 Mintegral SDK。请在 Android Gradle 的 repositories 配置中添加该仓库(通常是项目级 build.gradle / build.gradle.kts,例如 Flutter 应用里的 allprojects { repositories { … } })。

完整步骤、Kotlin/Groovy 代码片段和排障说明见 Android Mintegral 适配器 — Maven 仓库

初始化

在加载任何广告之前初始化 SDK。通常放在主 Widget 的 initState 中:

import 'package:cloudx_flutter/cloudx.dart';

// 可选:启用详细日志(仅用于开发)
CloudX.setMinLogLevel(CloudXLogLevel.verbose);

// 使用您的应用密钥初始化
final config = await CloudX.initialize(appKey: 'YOUR_APP_KEY');
if (config != null) {
  print('CloudX initialized');
} else {
  print('CloudX init failed');
}

CloudX.initialize() 成功时返回非空的 CloudXConfiguration,失败时返回 null。该配置对象目前没有属性——返回值仅作为成功信号。

其他初始化工具方法:

final initialized = await CloudX.isInitialized();
final version = await CloudX.getVersion();

广告集成

横幅广告(320x50)

横幅采用程序化浮层方式 —— 以固定屏幕位置覆盖在您的内容之上。

import 'package:cloudx_flutter/cloudx.dart';

const adUnitId = 'home_banner';

// 设置事件监听器
CloudX.setBannerListener(CloudXAdViewListener(
  onAdLoaded: (ad) {
    print('Banner loaded from ${ad.networkName}');
  },
  onAdLoadFailed: (adUnitId, error) {
    print('Banner failed: ${error.code} ${error.message}');
  },
  onAdClicked: (ad) {
    print('Banner clicked');
  },
  onAdRevenuePaid: (ad) {
    print('Banner revenue: ${ad.revenue}');
  },
));

// 创建并展示
CloudX.createBanner(adUnitId: adUnitId, position: CloudXAdViewPosition.bottomCenter);
CloudX.showBanner(adUnitId: adUnitId);

// 完成后隐藏 / 销毁
CloudX.hideBanner(adUnitId: adUnitId);
CloudX.destroyBanner(adUnitId: adUnitId);

默认启用自动刷新。如需手动控制:

CloudX.stopBannerAutoRefresh(adUnitId: adUnitId);
CloudX.startBannerAutoRefresh(adUnitId: adUnitId);

横幅位置

使用 CloudXAdViewPosition 放置横幅:

topLefttopCentertopRightcenterLeftcenteredcenterRightbottomLeftbottomCenterbottomRight

创建后如需更新位置:

CloudX.updateBannerPosition(adUnitId: adUnitId, position: CloudXAdViewPosition.topCenter);

其他横幅 API

CloudX.setBannerPlacement(adUnitId: adUnitId, placement: 'home_screen');
CloudX.setBannerCustomData(adUnitId: adUnitId, customData: 'custom_data');
CloudX.loadBanner(adUnitId: adUnitId); // 手动重新加载

横幅事件

回调类型
onAdLoadedCloudXAd
onAdLoadFailedString adUnitId, CloudXError
onAdClickedCloudXAd
onAdExpandedCloudXAd(可选)
onAdCollapsedCloudXAd(可选)
onAdRevenuePaidCloudXAd(可选)

MREC 广告(300x250)

MREC 与横幅用法相同,只是尺寸为 300x250。请使用 MREC 方法:

const adUnitId = 'home_mrec';

CloudX.setMRecListener(CloudXAdViewListener(
  onAdLoaded: (ad) {
    print('MREC loaded from ${ad.networkName}');
  },
  onAdLoadFailed: (adUnitId, error) {
    print('MREC failed: ${error.code} ${error.message}');
  },
));

CloudX.createMREC(adUnitId: adUnitId, position: CloudXAdViewPosition.centered);
CloudX.showMREC(adUnitId: adUnitId);

// 完成后销毁
CloudX.destroyMREC(adUnitId: adUnitId);

MREC API 与横幅 API 相同 —— 同样的方法和事件都可用,包括 updateMRECPositionsetMRECPlacementsetMRECCustomData、自动刷新控制以及全部事件监听器。

插屏广告

在自然过渡点展示的全屏广告。

import 'package:cloudx_flutter/cloudx.dart';

const adUnitId = 'level_complete';

// 设置事件监听器
CloudX.setInterstitialListener(CloudXInterstitialListener(
  onAdLoaded: (ad) {
    print('Interstitial loaded');
  },
  onAdLoadFailed: (adUnitId, error) {
    print('Interstitial load failed: ${error.code} ${error.message}');
  },
  onAdDisplayed: (ad) {
    print('Interstitial displayed');
  },
  onAdDisplayFailed: (ad, error) {
    print('Interstitial display failed: ${error.code} ${error.message}');
  },
  onAdHidden: (ad) {
    // 为下次使用重新加载
    CloudX.loadInterstitial(adUnitId: adUnitId);
  },
  onAdClicked: (ad) {
    print('Interstitial clicked');
  },
  onAdRevenuePaid: (ad) {
    print('Revenue: ${ad.revenue}');
  },
));

// 加载
CloudX.loadInterstitial(adUnitId: adUnitId);

// 就绪后展示(可选 placement 和 custom data)
final isReady = await CloudX.isInterstitialReady(adUnitId: adUnitId);
if (isReady) {
  CloudX.showInterstitial(adUnitId: adUnitId);
  // 或:CloudX.showInterstitial(adUnitId: adUnitId, placement: 'placement_name', customData: 'custom_data');
}

// 完成后销毁
CloudX.destroyInterstitial(adUnitId: adUnitId);

插屏事件

回调类型
onAdLoadedCloudXAd
onAdLoadFailedString adUnitId, CloudXError
onAdDisplayedCloudXAd
onAdDisplayFailedCloudXAd, CloudXError
onAdClickedCloudXAd
onAdHiddenCloudXAd
onAdRevenuePaidCloudXAd(可选)

激励视频广告

完成后向用户发放奖励的全屏广告。

import 'package:cloudx_flutter/cloudx.dart';

const adUnitId = 'rewarded_coins';

// 设置事件监听器
CloudX.setRewardedAdListener(CloudXRewardedListener(
  onAdLoaded: (ad) {
    print('Rewarded loaded');
  },
  onAdLoadFailed: (adUnitId, error) {
    print('Rewarded load failed: ${error.code} ${error.message}');
  },
  onAdDisplayed: (ad) {
    print('Rewarded displayed');
  },
  onAdDisplayFailed: (ad, error) {
    print('Rewarded display failed: ${error.code} ${error.message}');
  },
  onAdReceivedReward: (ad, reward) {
    print('Earned ${reward.amount} ${reward.label}');
  },
  onAdHidden: (ad) {
    // 为下次使用重新加载
    CloudX.loadRewardedAd(adUnitId: adUnitId);
  },
  onAdClicked: (ad) {
    print('Rewarded clicked');
  },
  onAdRevenuePaid: (ad) {
    print('Revenue: ${ad.revenue}');
  },
));

// 加载
CloudX.loadRewardedAd(adUnitId: adUnitId);

// 就绪后展示(可选 placement 和 custom data)
final isReady = await CloudX.isRewardedAdReady(adUnitId: adUnitId);
if (isReady) {
  CloudX.showRewardedAd(adUnitId: adUnitId);
  // 或:CloudX.showRewardedAd(adUnitId: adUnitId, placement: 'placement_name', customData: 'custom_data');
}

// 完成后销毁
CloudX.destroyRewardedAd(adUnitId: adUnitId);

激励视频事件

回调类型
onAdLoadedCloudXAd
onAdLoadFailedString adUnitId, CloudXError
onAdDisplayedCloudXAd
onAdDisplayFailedCloudXAd, CloudXError
onAdClickedCloudXAd
onAdHiddenCloudXAd
onAdReceivedRewardCloudXAd, CloudXReward
onAdRevenuePaidCloudXAd(可选)

CloudXReward 对象包含:

  • label — 奖励标签(例如 "coins"
  • amount — 奖励数量

基于 Widget 的广告视图

除程序化浮层外,您还可以使用 CloudXAdView 将横幅和 MREC 直接嵌入 Widget 树:

CloudXAdView(
  adUnitId: 'home_banner',
  adFormat: CloudXAdFormat.banner,
  listener: CloudXAdViewListener(
    onAdLoaded: (ad) => print('Widget banner loaded'),
    onAdLoadFailed: (adUnitId, error) => print('Widget banner failed'),
  ),
)

这会通过 Flutter 的平台视图系统(AndroidView / UiKitView)把原生广告视图内嵌到 Flutter Widget 中。

高级功能

错误处理

所有错误回调都会收到带有 codemessage 属性的 CloudXError

范围类别常见错误码
0通用internalError
100-199网络networkError, networkTimeout, networkServerError, networkNoConnection
200-299初始化notInitialized, noAdaptersFound, sdkDisabled, invalidAppKey
300-399广告加载noFill, invalidAdUnit, adsDisabled
400-499展示adNotReady, adAlreadyShowing, dontKeepActivitiesEnabled
600-699适配器adapterNoFill, adapterLoadTimeout, adapterTimeout, adapterInitializationError

完整错误码列表见 CloudXErrorCode

收入追踪

所有广告格式都提供收入回调。CloudXAd 包含 adUnitIdadFormatnetworkNamerevenue(美元)、可选 placement 以及可选 networkPlacement

CloudX.setInterstitialListener(CloudXInterstitialListener(
  onAdRevenuePaid: (ad) {
    trackRevenue(ad.revenue, ad.networkName, ad.adUnitId);
  },
  // ... 其他回调
));

用户定向

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 返回。您可以使用该值将 CloudX 收入与自己的用户数据分群关联。未设置 ID、隐私信号阻止持久化或值超过 128 个字符时,导出值为空。请勿传递未经哈希的个人数据。

身份透传

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

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

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

CloudX.setUserKeyValue('uidapi.com', uid2Token);
CloudX.setUserKeyValue('liveramp.com', liveRampEnvelope);
CloudX.setUserKeyValue('id5-sync.com', id5Id);

隐私合规

NSUserDefaults / SharedPreferences 读取 IAB GPP、TCF v2 和 US Privacy 字符串(通常由 CMP 写入)。

标准说明
IABGPP_HDR_GppStringGPP全球隐私平台字符串
IABGPP_GppSIDGPP部分 ID
IABTCF_TCStringTCF v2GDPR 同意字符串
IABUSPrivacy_StringUS PrivacyCCPA 字符串

手动 API: 当您不使用 CMP,或需要覆盖直到清除时,使用 CloudX.setHasUserConsent(bool?)CloudX.setDoNotSell(bool?)null 会移除覆盖;解析顺序与原生 SDK 一致(已存储的 IAB 字符串以及这些覆盖)。可在 CloudX.initialize() 之前调用。

CloudX.setHasUserConsent(true);
CloudX.setDoNotSell(false);
CloudX.setHasUserConsent(null);

测试模式

测试模式由服务端控制,通过设备白名单实现:

  1. 启用详细日志后初始化 SDK
  2. 在控制台日志中找到设备广告 ID
  3. 在 CloudX 控制台将该设备加入白名单

调试日志

import 'package:cloudx_flutter/cloudx.dart';

// 启用详细日志(在 initialize 之前调用)
CloudX.setMinLogLevel(CloudXLogLevel.verbose);

// 可用级别:verbose、debug、info、warn、error、none

可视化调试

启用可视化调试叠加层,以查看广告单元边界和广告网络信息(仅 iOS):

CloudX.setVisualDebuggingEnabled(true);

技术支持

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