概览
CloudX iOS SDK 设置和核心功能概览
需要 iOS 13.0+、Xcode 16.0+ 和 Swift 6.0+。
安装
Swift Package Manager
请参阅 Swift Package Manager 安装指南,了解受支持的软件包、精确的适配器版本和项目要求。
CocoaPods
platform :ios, '15.0'
target 'YourApp' do
use_frameworks!
# 核心 SDK
pod 'CloudXCore', '~> 3.11.0'
# 广告网络适配器(根据需要添加)。
# 每个适配器独立按 <网络 SDK 版本>.<适配器修订号> 版本化,
# 并针对该确切网络 SDK 版本构建。
pod 'CloudXBigoAdapter', '~> 6.1.0.0' # BigoADS 6.1.0
pod 'CloudXMetaAdapter', '~> 6.22.0.1' # FBAudienceNetwork 6.22.0
pod 'CloudXVungleAdapter', '~> 7.7.6.1' # VungleAds 7.7.6
pod 'CloudXInMobiAdapter', '~> 11.5.0.0' # InMobiSDK 11.5.0
pod 'CloudXMintegralAdapter', '~> 8.1.7.0' # MintegralAdSDK 8.1.7
pod 'CloudXUnityAdsAdapter', '~> 4.20.1.1' # UnityAds 4.20.1
pod 'CloudXMagniteAdapterV2', '~> 1.0.4.2' # MagniteSDK 1.0.4
pod 'CloudXMobileFuseAdapter', '~> 1.12.0.0' # MobileFuseSDK 1.12.0
pod 'CloudXMolocoAdapter', '~> 4.11.1.1' # MolocoSDKiOS 4.11.1
pod 'CloudXVerveAdapter', '~> 3.9.0.1' # HyBid 3.9.0
pod 'CloudXDigitalTurbineAdapter', '~> 8.4.10.1' # Fyber Marketplace SDK 8.4.10
pod 'CloudXGoogleWaterfallAdapter', '~> 13.9.0.0' # Google Mobile Ads SDK 13.9.0
pod 'CloudXPangleAdapter', '~> 8.3.0.6.1' # Ads-Global(Pangle / 字节跳动)8.3.0.6
pod 'CloudXTaurusXAdapter', '~> 1.18.2.1' # TaurusxAdsSDK 1.18.2
endpod install --repo-update初始化
#import <CloudXCore/CloudXCore.h>
CLXInitializationConfiguration *config =
[CLXInitializationConfiguration configurationWithAppKey:@"your-app-key-here"];
[[CloudXCore shared] initializeWithConfiguration:config completion:^(CLXSdkConfiguration *sdkConfig, CLXError * _Nullable error) {
if (sdkConfig) {
NSLog(@"CloudX SDK 初始化成功");
} else {
NSLog(@"CloudX SDK 初始化失败: %@", error.localizedDescription);
}
}];import CloudXCore
let config = CLXInitializationConfiguration.configuration(appKey: "your-app-key-here", builderBlock: nil)
CloudXCore.shared.initialize(with: config) { sdkConfig, error in
if sdkConfig != nil {
print("CloudX SDK 初始化成功")
} else {
print("CloudX SDK 初始化失败: \(error?.localizedDescription ?? "未知错误")")
}
}应用启动预热
链接 CloudXCore 后,SDK 会在应用启动时、您调用 initialize 之前预先完成部分工作。这是一项性能优化:它可以让 SDK 更快地完成初始化并加载首个广告,同时不会拖慢应用的启动速度。
预热不会占用应用的启动路径;除轻量的后台准备外,其余工作都会等到应用变为活跃状态后才执行。从未变为活跃状态的启动(例如后台获取或静默推送)只执行这部分轻量准备。应用扩展完全跳过预热。
这并不会初始化 SDK。您仍然需要调用 initialize,调用的时机和方式均无需改变。预热是尽力而为的:如果预热尚未完成,SDK 会在需要时自行完成这些工作,预热也不会导致应用启动失败。
如需关闭预热,请在应用的 Info.plist 中添加以下键:
<key>CloudXStartupWarmDisabled</key>
<true/>两种方式的行为相同。设置该键后,SDK 会在您调用 initialize 时执行这些准备工作,因此首次初始化和首次广告加载会明显变慢。
广告格式
CloudX 支持横幅、MREC、插屏、激励、原生和 App Open 广告集成。请使用对应广告格式指南查看实现细节:
横幅和 MREC 广告
创建固定尺寸展示广告位,并可选择控制刷新。
插屏广告
加载和展示全屏插屏广告位。
原生广告
在应用的自定义布局中渲染原生创意。
激励广告
在用户完成激励广告观看后发放奖励。
App Open 广告
面向应用启动和回到前台时刻的全屏广告位。
广告信息 (CLXAd)
CLXAd 对象会传递给代理回调,包含已加载/展示广告的信息:
| 属性 | 类型 | 描述 |
|---|---|---|
adFormat | CLXAdFormat | 广告格式(横幅、MREC、插屏、激励、原生) |
adUnitId | NSString? | 广告单元 ID |
adUnitName | NSString? | 广告单元名称 |
networkName | NSString? | 获胜广告网络的名称 |
networkPlacement | NSString? | 网络特定的展示位置 ID |
placement | NSString? | 通过 placement 属性设置的自定义展示位置 |
revenue | NSNumber? | 展示级别收入(美元) |
revenuePrecision | NSString? | 获胜广告网络提供的收入精度 |
creativeIdentifier | NSString? | 用于素材级问题排查的素材标识符 |
requestLatency | NSTimeInterval | 从广告请求到广告响应的耗时(秒) |
nativeAd | CLXNativeAd? | 原生广告的素材容器;非原生格式为 nil |
adValues | NSDictionary<NSString *, NSString *> | SDK 为已加载广告提供的元数据;具体值可能因格式或网络而缺失 |
当需求方未返回素材 ID 时,creativeIdentifier 为 nil。它与您在 CLXRevenueData 中传入的 creativeId 不同,后者描述的是在 CloudX 广告流程之外竞得的展示。
- (void)didLoadAd:(CLXAd *)ad {
NSLog(@"广告格式: %ld", (long)ad.adFormat);
NSLog(@"网络: %@", ad.networkName);
NSLog(@"收入: %@", ad.revenue);
}func didLoad(_ ad: CLXAd) {
print("广告格式: \(ad.adFormat)")
print("网络: \(ad.networkName ?? "unknown")")
print("收入: \(ad.revenue ?? 0)")
}错误处理
所有 SDK 错误都作为 CLXError 对象在代理回调中返回:
| 属性 | 类型 | 描述 |
|---|---|---|
code | CLXErrorCode | 错误类别 |
localizedDescription | NSString | 人类可读的描述 |
underlyingError | NSError? | 可选的底层错误 |
错误代码类别
| 范围 | 类别 | 常见代码 |
|---|---|---|
| 0 | 通用 | CLXErrorCodeInternalError |
| 100-199 | 网络 | CLXErrorCodeNetworkError、CLXErrorCodeNetworkTimeout、CLXErrorCodeServerError、CLXErrorCodeNoConnection |
| 200-299 | 初始化 | CLXErrorCodeNotInitialized、CLXErrorCodeSDKDisabled、CLXErrorCodeNoAdaptersFound、CLXErrorCodeInvalidAppKey |
| 300-399 | 广告加载 | CLXErrorCodeNoFill、CLXErrorCodeInvalidAdUnit、CLXErrorCodeAdsDisabled |
| 400-499 | 展示 | CLXErrorCodeAdNotReady、CLXErrorCodeAdAlreadyShowing |
| 600-699 | 适配器 | CLXErrorCodeAdapterNoFill、CLXErrorCodeAdapterTimeout、CLXErrorCodeAdapterLoadTimeout、CLXErrorCodeAdapterInitializationError |
高级功能
调试日志
[CloudXCore setMinLogLevel:CLXLogLevelDebug]; // 启用调试日志
[CloudXCore setMinLogLevel:CLXLogLevelNone]; // 禁用所有日志CloudXCore.setMinLogLevel(.debug) // 启用调试日志
CloudXCore.setMinLogLevel(.none) // 禁用所有日志日志级别: verbose < debug < info < warn < error < none
展示级别收入追踪
在任何广告格式上设置 revenueDelegate 以接收展示级别收入(ILR)回调。CLXAd 对象包含以美元计价的收入值和获胜网络名称。
self.bannerAd.revenueDelegate = self;
- (void)didPayRevenueForAd:(CLXAd *)ad {
NSLog(@"收入: %@ 来自 %@", ad.revenue, ad.networkName);
}bannerAd?.revenueDelegate = self
func didPayRevenue(for ad: CLXAd) {
print("收入: \(ad.revenue ?? 0) 来自 \(ad.networkName ?? "unknown")")
}适用于所有广告格式(横幅、MREC、插屏、激励、原生)。
将广告收入上报至 MMP
如需将 CloudX 广告收入转发至移动归因合作伙伴(MMP),请添加相应的连接器,而不要自行实现收入代理:Adjust、AppsFlyer 或 Singular。每个连接器都会在每次 CloudX 竞得的展示时上报一次,无需发布商编写胶水代码。在 CloudX 竞价中由 AppLovin MAX 或 Google 瀑布流赢得的展示不会被转发,因为这些 SDK 已自行向您的 MMP 上报该部分收入。
无需在 MMP 后台进行任何 CloudX 专属配置,但您的 MMP 账户需要启用广告收入上报。对于 Adjust,收入目前计入通用来源,而非 CloudX 标签。详见在 Adjust UI 中查看 CloudX 收入。
发布商上报收入数据
如果您的应用在 CloudX 广告流程之外接收来自 AdMob、InMobi、TopOn 或其他聚合平台的展示级收入回调或 bid 元数据,请在 CloudX 初始化完成后将这些事件转发给 CloudX:
| 字段 | 必填 | 描述 |
|---|---|---|
platform | 是 | Objective-C 中使用 CLXRevenuePlatformAdMob、CLXRevenuePlatformInMobi、CLXRevenuePlatformTopOn 或 CLXRevenuePlatformCustom(@"MyProvider");Swift 中使用 .adMob、.inMobi、.topOn 或 .custom("MyProvider") |
revenue | 是 | 单次展示收入,使用传入货币;不是 CPM/eCPM |
adFormat | 是 | 广告格式字符串,例如 banner、mrec、interstitial、rewarded、native 或 app_open |
currencyCode | 否 | ISO 4217 货币代码(如已知) |
precision | 否 | exact、estimated、publisherDefined 或 undefined |
networkName | 否 | 获胜广告网络名称(如已知) |
adUnitId | 否 | 聚合平台广告单元 ID |
thirdPartyAdPlacementId | 否 | 广告网络侧广告单元或 placement ID |
creativeId | 否 | 广告网络返回的素材 ID |
networkPlacement | 否 | 广告网络 placement 标识 |
countryCode | 否 | 用户国家代码(如已知) |
userSegment | 否 | 用户分群(如已知) |
当事件被 CloudX 收益链路接受时,reportRevenueData(_:) 返回 true。如果 SDK 尚未初始化、服务端未启用收益跟踪,或平台名称为空,则返回 false。接受事件不保证一定送达。
AdMob paid event
AdMob iOS 的 AdValue.value 已经是所提供货币的正常单位,因此请直接传给 CloudX。不要除以 1_000_000.0。
static CLXRevenuePrecision *CLXRevenuePrecisionFromGAD(GADAdValuePrecision precision) {
switch (precision) {
case GADAdValuePrecisionPrecise: return CLXRevenuePrecision.exact;
case GADAdValuePrecisionEstimated: return CLXRevenuePrecision.estimated;
case GADAdValuePrecisionPublisherProvided: return CLXRevenuePrecision.publisherDefined;
case GADAdValuePrecisionUnknown: return CLXRevenuePrecision.undefined;
}
return CLXRevenuePrecision.undefined;
}
- (BOOL)reportAdMobPaidEventWithAdValue:(GADAdValue *)adValue
adFormat:(NSString *)adFormat
adUnitId:(NSString *)adUnitId
responseInfo:(GADResponseInfo *)responseInfo {
GADAdNetworkResponseInfo *servedBy = responseInfo.loadedAdNetworkResponseInfo;
CLXRevenueData *data =
[CLXRevenueData revenueDataWithPlatform:CLXRevenuePlatformAdMob
revenue:adValue.value.doubleValue
adFormat:adFormat
builderBlock:^(CLXRevenueDataBuilder *builder) {
builder.currencyCode = adValue.currencyCode;
builder.precision = CLXRevenuePrecisionFromGAD(adValue.precision);
builder.networkName = servedBy.adSourceName;
builder.adUnitId = adUnitId;
builder.thirdPartyAdPlacementId = servedBy.adSourceInstanceName;
}];
return [[CloudXCore shared] reportRevenueData:data];
}
__weak GADBannerView *weakBannerView = bannerView;
bannerView.paidEventHandler = ^(GADAdValue *adValue) {
[self reportAdMobPaidEventWithAdValue:adValue
adFormat:@"banner"
adUnitId:adUnitId
responseInfo:weakBannerView.responseInfo];
};private func toCloudXRevenuePrecision(_ precision: AdValuePrecision) -> CLXRevenuePrecision {
switch precision {
case .precise:
return .exact
case .estimated:
return .estimated
case .publisherProvided:
return .publisherDefined
case .unknown:
return .undefined
@unknown default:
return .undefined
}
}
private func reportAdMobPaidEvent(
_ adValue: AdValue,
adFormat: String,
adUnitId: String,
responseInfo: ResponseInfo?
) -> Bool {
let servedBy = responseInfo?.loadedAdNetworkResponseInfo
let data = CLXRevenueData.revenueData(
platform: .adMob,
revenue: adValue.value.doubleValue,
adFormat: adFormat
) { builder in
builder.currencyCode = adValue.currencyCode
builder.precision = toCloudXRevenuePrecision(adValue.precision)
builder.networkName = servedBy?.adSourceName
builder.adUnitId = adUnitId
builder.thirdPartyAdPlacementId = servedBy?.adSourceInstanceName
}
return CloudXCore.shared.reportRevenueData(data)
}
bannerView.paidEventHandler = { [weak bannerView] adValue in
_ = reportAdMobPaidEvent(
adValue,
adFormat: "banner",
adUnitId: adUnitId,
responseInfo: bannerView?.responseInfo
)
}InMobi impression event
对于 InMobi,请在 banner(_:didReceiveWithMetaInfo:) 中保存 IMAdMetaInfo。当 bannerAdImpressed(_:) 触发时,把保存的 metaInfo.getBid() 上报给 CloudX,然后清空保存的值。
@property (nonatomic, strong, nullable) IMAdMetaInfo *latestInMobiMetaInfo;
- (void)banner:(IMBanner *)banner didReceiveWithMetaInfo:(IMAdMetaInfo *)info {
self.latestInMobiMetaInfo = info;
}
- (void)bannerAdImpressed:(IMBanner *)banner {
if (!self.latestInMobiMetaInfo) {
return;
}
[self reportInMobiImpressionWithMetaInfo:self.latestInMobiMetaInfo
adFormat:@"banner"
placementId:inMobiPlacementId];
self.latestInMobiMetaInfo = nil;
}
- (BOOL)reportInMobiImpressionWithMetaInfo:(IMAdMetaInfo *)metaInfo
adFormat:(NSString *)adFormat
placementId:(NSString *)placementId {
CLXRevenueData *data =
[CLXRevenueData revenueDataWithPlatform:CLXRevenuePlatformInMobi
revenue:[metaInfo getBid]
adFormat:adFormat
builderBlock:^(CLXRevenueDataBuilder *builder) {
builder.precision = CLXRevenuePrecision.estimated;
builder.thirdPartyAdPlacementId = placementId;
builder.creativeId = metaInfo.creativeID;
}];
return [[CloudXCore shared] reportRevenueData:data];
}private var latestInMobiMetaInfo: IMAdMetaInfo?
func banner(_ banner: IMBanner, didReceiveWithMetaInfo info: IMAdMetaInfo) {
latestInMobiMetaInfo = info
}
func bannerAdImpressed(_ banner: IMBanner) {
guard let metaInfo = latestInMobiMetaInfo else {
return
}
_ = reportInMobiImpression(
metaInfo,
adFormat: "banner",
placementId: inMobiPlacementId
)
latestInMobiMetaInfo = nil
}
private func reportInMobiImpression(
_ metaInfo: IMAdMetaInfo,
adFormat: String,
placementId: String
) -> Bool {
let data = CLXRevenueData.revenueData(
platform: .inMobi,
revenue: metaInfo.getBid(),
adFormat: adFormat
) { builder in
builder.precision = .estimated
builder.thirdPartyAdPlacementId = placementId
builder.creativeId = metaInfo.creativeID
}
return CloudXCore.shared.reportRevenueData(data)
}对于 InMobi 插屏和激励视频广告,请在 IMInterstitialDelegate 中使用相同模式:在 interstitial(_:didReceiveWithMetaInfo:) 中保存 IMAdMetaInfo,然后在 interstitialAdImpressed(_:) 中上报。
TopOn revenue event
TopOn iOS 会在 didRevenueForPlacementID:extra: 中提供收入。请使用 extra 中的 publisher_revenue 作为单次展示收入,并使用 currency 作为货币代码。
static NSString *CLXTopOnStringValue(NSDictionary *extra, NSString *key) {
id value = extra[key];
return [value isKindOfClass:NSString.class] ? value : nil;
}
static CLXRevenuePrecision *CLXRevenuePrecisionFromTopOn(NSString *precision) {
if ([precision isEqualToString:@"exact"]) return CLXRevenuePrecision.exact;
if ([precision isEqualToString:@"estimated"]) return CLXRevenuePrecision.estimated;
if ([precision isEqualToString:@"publisher_defined"]) return CLXRevenuePrecision.publisherDefined;
return CLXRevenuePrecision.undefined;
}
- (BOOL)reportTopOnRevenueForPlacementID:(NSString *)placementID
extra:(NSDictionary *)extra
adFormat:(NSString *)adFormat {
NSNumber *revenue = extra[@"publisher_revenue"];
if (![revenue isKindOfClass:NSNumber.class]) {
return NO;
}
CLXRevenueData *data =
[CLXRevenueData revenueDataWithPlatform:CLXRevenuePlatformTopOn
revenue:revenue.doubleValue
adFormat:adFormat
builderBlock:^(CLXRevenueDataBuilder *builder) {
builder.currencyCode = CLXTopOnStringValue(extra, @"currency");
builder.precision = CLXRevenuePrecisionFromTopOn(CLXTopOnStringValue(extra, @"precision"));
builder.networkName = CLXTopOnStringValue(extra, @"network_name");
builder.adUnitId = placementID;
builder.thirdPartyAdPlacementId = CLXTopOnStringValue(extra, @"network_placement_id");
builder.networkPlacement = CLXTopOnStringValue(extra, @"adsource_id");
builder.countryCode = CLXTopOnStringValue(extra, @"country");
}];
return [[CloudXCore shared] reportRevenueData:data];
}
- (void)didRevenueForPlacementID:(NSString *)placementID extra:(NSDictionary *)extra {
[self reportTopOnRevenueForPlacementID:placementID
extra:extra
adFormat:@"banner"];
}private func topOnRevenuePrecision(_ precision: String?) -> CLXRevenuePrecision {
switch precision {
case "exact":
return .exact
case "estimated":
return .estimated
case "publisher_defined":
return .publisherDefined
default:
return .undefined
}
}
private func reportTopOnRevenue(
placementID: String,
extra: [AnyHashable: Any],
adFormat: String
) -> Bool {
guard let revenue = (extra["publisher_revenue"] as? NSNumber)?.doubleValue else {
return false
}
let data = CLXRevenueData.revenueData(
platform: .topOn,
revenue: revenue,
adFormat: adFormat
) { builder in
builder.currencyCode = extra["currency"] as? String
builder.precision = topOnRevenuePrecision(extra["precision"] as? String)
builder.networkName = extra["network_name"] as? String
builder.adUnitId = placementID
builder.thirdPartyAdPlacementId = extra["network_placement_id"] as? String
builder.networkPlacement = extra["adsource_id"] as? String
builder.countryCode = extra["country"] as? String
}
return CloudXCore.shared.reportRevenueData(data)
}
func didRevenue(forPlacementID placementID: String, extra: [AnyHashable: Any]) {
_ = reportTopOnRevenue(
placementID: placementID,
extra: extra,
adFormat: "banner"
)
}自定义平台事件
对于没有 CloudX SDK 内置常量的 provider,请使用 Custom;AdMob、InMobi 和 TopOn 已有内置常量。这里的值只表示 provider 名称,例如 Objective-C 中的 CLXRevenuePlatformCustom(@"TradPlus") 或 Swift 中的 CLXRevenuePlatform.custom("TradPlus")。请保持名称稳定,便于 CloudX 一致归类该 provider 的收益。
不要把金额或币种放进 provider 名称里。如果一条 TradPlus 展示带来 USD 0.01 收入,请传 platform TradPlus、revenue 0.01 和 currency code USD。如果来源返回 CPM/eCPM,请先除以 1_000.0。
- (BOOL)reportCustomRevenueEventWithProviderName:(NSString *)providerName
revenue:(double)revenue
adFormat:(NSString *)adFormat
currencyCode:(NSString *)currencyCode
adUnitId:(NSString *)adUnitId
placementId:(NSString *)placementId {
CLXRevenueData *data =
[CLXRevenueData revenueDataWithPlatform:CLXRevenuePlatformCustom(providerName)
revenue:revenue
adFormat:adFormat
builderBlock:^(CLXRevenueDataBuilder *builder) {
builder.currencyCode = currencyCode;
builder.precision = CLXRevenuePrecision.publisherDefined;
builder.adUnitId = adUnitId;
builder.thirdPartyAdPlacementId = placementId;
}];
return [[CloudXCore shared] reportRevenueData:data];
}private func reportCustomRevenueEvent(
providerName: String,
revenue: Double,
adFormat: String,
currencyCode: String,
adUnitId: String,
placementId: String
) -> Bool {
let data = CLXRevenueData.revenueData(
platform: .custom(providerName),
revenue: revenue,
adFormat: adFormat
) { builder in
builder.currencyCode = currencyCode
builder.precision = .publisherDefined
builder.adUnitId = adUnitId
builder.thirdPartyAdPlacementId = placementId
}
return CloudXCore.shared.reportRevenueData(data)
}代理回调线程
发布方代理回调会在主队列上派发,并且可能相对于触发它们的 SDK 调用以内联方式触发。如果代理方法会再次调用 SDK,请确保处理逻辑可重入。
测试模式
测试模式通过设备白名单进行服务端控制。这提供了更好的安全性和对哪些设备接收测试广告的控制。
启用测试模式:
-
初始化 SDK 并检查日志中的设备 IFA:
[CloudX][INFO] Device IFA for test whitelisting: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -
复制 IFA 并将其添加到 CloudX 服务器仪表板的设备白名单中
-
SDK 将自动为测试模式配置适配器并在竞价请求中包含测试标志
隐私合规
CloudX SDK 通过从 NSUserDefaults 读取标准 IAB 隐私字符串来支持 GDPR 和 CCPA 隐私合规。这些值通常由您的同意管理平台(CMP)自动设置,如 Google UMP、OneTrust 或 Sourcepoint。
工作原理
SDK 自动检测用户位置并读取同意信号:
- 欧盟用户(GDPR):根据 IAB 全球供应商列表 检查 TCF v2 对目的 1 和 2 的同意和供应商同意(CloudX 供应商 ID:1510)
- 美国用户(CCPA):检查销售/共享选择退出信号
- 其他地区:无限制
当用户拒绝同意或选择退出时,SDK 会从广告请求中移除 PII:
- 广告标识符(IDFA)被清除
- 地理坐标(纬度/经度)被移除
- 用户键值不会发送
- 哈希用户 ID 会从发送给竞价方的请求中移除,并且不会写入展示级报表
支持的隐私密钥
| 密钥 | 标准 | 描述 |
|---|---|---|
IABGPP_HDR_GppString | GPP | 全球隐私平台字符串(现代) |
IABGPP_GppSID | GPP | Section IDs(如 “2” 为欧盟,“7” 为美国国家,“8” 为美国加州) |
IABTCF_TCString | TCF v2 | GDPR 同意字符串(旧版) |
IABTCF_gdprApplies | TCF v2 | GDPR 是否适用(1 = 是,0 = 否) |
IABUSPrivacy_String | US Privacy | CCPA 隐私字符串(旧版,如 “1YNN”) |
应用追踪透明度(ATT)
在 iOS 14.5+ 上,您必须在 SDK 可以访问 IDFA 之前请求应用追踪透明度授权。在初始化 CloudX SDK 之前请求 ATT 权限:
#import <AppTrackingTransparency/AppTrackingTransparency.h>
if (@available(iOS 14.5, *)) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
// 在 ATT 响应后初始化 CloudX SDK
[self initializeCloudX];
}];
} else {
[self initializeCloudX];
}import AppTrackingTransparency
if #available(iOS 14.5, *) {
ATTrackingManager.requestTrackingAuthorization { status in
// 在 ATT 响应后初始化 CloudX SDK
self.initializeCloudX()
}
} else {
initializeCloudX()
}在 Info.plist 中添加 NSUserTrackingUsageDescription 键,并说明您需要追踪权限的原因。
手动隐私 API
如果您自行管理用户同意(不使用 CMP),可以直接设置 GDPR 和 CCPA 隐私状态。请在初始化 SDK 之前调用这些方法 — 部分广告网络 SDK 要求在初始化时设置隐私参数,初始化后设置的值可能不会生效。
// 在初始化 SDK 之前设置隐私
[CloudXCore setHasUserConsent:@YES];
[CloudXCore setDoNotSell:@NO];
[[CloudXCore shared] initializeWithConfiguration:config completion:completion];// 在初始化 SDK 之前设置隐私
CloudXCore.setHasUserConsent(true)
CloudXCore.setDoNotSell(false)
CloudXCore.shared.initialize(with: config) { sdkConfig, error in
// ...
}用户定向
// 设置哈希用户 ID 用于定向
[[CloudXCore shared] setHashedUserID:@"hashed-user-id"];
// 设置自定义用户键值对(受隐私法规清除)
[[CloudXCore shared] setUserKeyValue:@"age" value:@"25"];
[[CloudXCore shared] setUserKeyValue:@"gender" value:@"male"];
[[CloudXCore shared] setUserKeyValue:@"location" value:@"US"];
// 设置用于请求定向的自定义应用键值对
[[CloudXCore shared] setAppKeyValue:@"app_version" value:@"1.0.0"];
[[CloudXCore shared] setAppKeyValue:@"user_level" value:@"premium"];
// 清除所有自定义键值
[[CloudXCore shared] clearAllKeyValues];// 设置哈希用户 ID 用于定向
CloudXCore.shared.setHashedUserID("hashed-user-id")
// 设置自定义用户键值对(受隐私法规清除)
CloudXCore.shared.setUserKeyValue("age", value: "25")
CloudXCore.shared.setUserKeyValue("gender", value: "male")
CloudXCore.shared.setUserKeyValue("location", value: "US")
// 设置用于请求定向的自定义应用键值对
CloudXCore.shared.setAppKeyValue("app_version", value: "1.0.0")
CloudXCore.shared.setAppKeyValue("user_level", value: "premium")
// 清除所有自定义键值
CloudXCore.shared.clearAllKeyValues()哈希用户 ID 是由发布商提供的假名标识符。当适用的隐私信号允许时,CloudX 会在请求和展示活动导出中以 hashed_user_id 返回竞价时记录的值。使用 auction_id 关联这些导出。您可以使用该 ID 将 CloudX 活动与自己的用户数据分群关联。未设置 ID、隐私信号阻止持久化或值超过 128 个字符时,导出值为空。请勿传递未经哈希的个人数据。
用户和应用键值对也会出现在请求活动导出中。使用 setUserKeyValue 设置 SDK 会话范围内的用户属性,使用 setAppKeyValue 设置 SDK 会话范围内的应用属性。SDK 会在之后的每个竞价请求中发送当前值。
身份透传
通过 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 不是同一回事。
CloudXCore.shared.setUserKeyValue("uidapi.com", value: uid2Token)
CloudXCore.shared.setUserKeyValue("euid.eu", value: euidToken)
CloudXCore.shared.setUserKeyValue("liveramp.com", value: liveRampEnvelope)
CloudXCore.shared.setUserKeyValue("id5-sync.com", value: id5Id)
CloudXCore.shared.setUserKeyValue("intentiq.com", value: intentIQId)[[CloudXCore shared] setUserKeyValue:@"uidapi.com" value:uid2Token];
[[CloudXCore shared] setUserKeyValue:@"euid.eu" value:euidToken];
[[CloudXCore shared] setUserKeyValue:@"liveramp.com" value:liveRampEnvelope];
[[CloudXCore shared] setUserKeyValue:@"id5-sync.com" value:id5Id];
[[CloudXCore shared] setUserKeyValue:@"intentiq.com" value:intentIQId];如需为单个广告对象或加载添加元数据,请在调用 load 前使用 setExtraParameter:
banner?.setExtraParameter("requestId", value: "request-456")
banner?.setExtraParameter("impressionKey", value: "impression-789")
banner?.load()[self.banner setExtraParameter:@"requestId" value:@"request-456"];
[self.banner setExtraParameter:@"impressionKey" value:@"impression-789"];
[self.banner load];额外参数会保留在该广告对象上,直到被修改或清除。SDK 会为每次加载创建参数快照。CloudX 会在请求导出的 extra_parameters 列中返回完整参数对象。保留的 tags 键还会控制基于标签的路由;请使用其他键存储关联元数据。
只有当整个紧凑 JSON 对象不超过 256 个 UTF-8 字节时,CloudX 才会存储对应的参数对象。每个导出列分别适用该限制,且计数包含所有键、值、引号、分隔符和大括号的合计大小,并非每个键值对可各用 256 字节。如果隐私规则禁止持久化发布商数据,或者对象格式错误或过大,则对应导出单元格为空。请勿包含原始个人数据、密钥或同意字符串。
技术支持
如需支持,请联系 support@cloudx.io