Trusted Arbiter 会比较已加载的 CloudX 出价与受支持的第三方出价,并返回选中的平台。CloudX SDK 4.1.0 及更高版本支持 CloudX、Unity LevelPlay 和 PubMatic 出价输入。
请在 CloudX.initialize() 完成后再调用 CloudX.arbiter()。在仲裁服务可用之前,SDK 会在传入的出价中回退选择可比较美元出价最高的平台。
基础 API
从已加载的广告创建出价候选项,然后传给 CloudX.arbiter()。
// cloudXAd 是 CloudX onAdLoaded 回调中的 CloudXAd 对象。
// levelPlayAdInfo 是 Unity LevelPlay 广告信息对象。
// pobBid 是 PubMatic/OpenWrap 出价对象。
val bids = listOf(
CloudXArbiterBid.cloudX(cloudXAd),
CloudXArbiterBid.levelPlay(
networkName = levelPlayAdInfo.adNetwork,
revenue = levelPlayAdInfo.revenue,
precision = levelPlayAdInfo.precision,
),
CloudXArbiterBid.pubmatic(
price = pobBid.price,
partnerName = pobBid.partnerName,
)
)
val configuration = CloudXArbiterConfiguration.builder(bids).build()
CloudX.arbiter(configuration, object : CloudXArbiterListener {
override fun onCompleted(result: CloudXArbiterResult) {
Log.d("CloudX", "选中的平台: ${result.platform.name}")
}
})
CloudXArbiterBid.cloudX() 接收 CloudX 加载回调中的 CloudXAd 对象。levelPlay() 接收 Unity LevelPlay 广告信息值。pubmatic() 接收 PubMatic OpenWrap 出价价格和可选的合作伙伴名称。出价工厂方法中的 partnerName 和 extras 映射均为可选参数。onCompleted() 在主线程上回调,因此你可以直接在其中展示广告或更新 UI。
result.platform 在选中平台时为 CloudXArbiterPlatform.CLOUDX、LEVELPLAY 或 PUBMATIC;当无法选出获胜平台时(例如未传入任何出价),则为 CloudXArbiterPlatform.NONE。
Kotlin 调用方可以使用挂起函数重载来代替监听器,它会返回相同的 CloudXArbiterResult:val result = CloudX.arbiter(configuration)
Log.d("CloudX", "选中的平台: ${result.platform.name}")
分步示例:在 CloudX 与 LevelPlay 之间仲裁
本演练展示了应读取哪个 Unity LevelPlay 回调,以及应将哪些值传入 CloudX.arbiter()。示例使用插屏广告,但相同的字段映射适用于任何广告格式。
加载两个候选项
创建 CloudX 和 LevelPlay 插屏广告,绑定监听器,并为每个平台启动加载。val cloudXInterstitial = CloudX.createInterstitial(context, "YOUR_CLOUDX_AD_UNIT_ID")
cloudXInterstitial.listener = cloudXListener
cloudXInterstitial.load()
val levelPlayInterstitial = LevelPlayInterstitialAd("YOUR_LEVELPLAY_AD_UNIT_ID")
levelPlayInterstitial.setListener(levelPlayListener)
levelPlayInterstitial.loadAd()
保存每个平台已加载的广告
LevelPlay 在其 onAdLoaded 回调中提供 LevelPlayAdInfo;CloudX 在 onAdLoaded 中提供 CloudXAd。请保存两者——下一步会从中读取仲裁输入。private var cloudXAd: CloudXAd? = null
private var levelPlayInfo: LevelPlayAdInfo? = null
// CloudXInterstitialListener
override fun onAdLoaded(cloudXAd: CloudXAd) {
this.cloudXAd = cloudXAd
}
// LevelPlayInterstitialAdListener
override fun onAdLoaded(levelPlayAdInfo: LevelPlayAdInfo) {
levelPlayInfo = levelPlayAdInfo
}
将值映射为出价
从 LevelPlayAdInfo 读取 LevelPlay 字段,并传给 CloudXArbiterBid.levelPlay()。CloudX 出价直接接收 CloudXAd。listOfNotNull 只会提交实际加载成功的平台。LevelPlayAdInfo 字段 | 类型 | CloudXArbiterBid.levelPlay 参数 |
|---|
adNetwork | String | networkName |
revenue | Double | revenue |
precision | String | precision |
val bids = listOfNotNull(
cloudXAd?.let { CloudXArbiterBid.cloudX(it) },
levelPlayInfo?.let { info ->
CloudXArbiterBid.levelPlay(
networkName = info.adNetwork, // LevelPlayAdInfo.adNetwork
revenue = info.revenue, // LevelPlayAdInfo.revenue
precision = info.precision, // LevelPlayAdInfo.precision
)
},
)
运行仲裁器
将出价封装进 CloudXArbiterConfiguration,连同监听器传给 CloudX.arbiter()。onCompleted() 在主线程上回调。val configuration = CloudXArbiterConfiguration.builder(bids).build()
CloudX.arbiter(configuration, object : CloudXArbiterListener {
override fun onCompleted(result: CloudXArbiterResult) {
showWinner(result)
}
})
展示获胜平台
根据 result.platform 进行分支,展示获胜平台的广告。CloudXArbiterPlatform.NONE 表示未选出获胜平台——此时不展示广告,继续应用流程。private fun showWinner(result: CloudXArbiterResult) {
when (result.platform) {
CloudXArbiterPlatform.CLOUDX -> cloudXInterstitial.show(activity)
CloudXArbiterPlatform.LEVELPLAY -> levelPlayInterstitial.showAd(activity)
else -> { } // CloudXArbiterPlatform.NONE——无获胜平台;不展示广告
}
}
下方的 ArbiterInterstitialController 将上述步骤封装为一个可复用的组件,会在到达广告位之前提前准备好获胜平台。
插屏广告示例
这个插屏广告示例会在两个平台之间仲裁:CloudX 和 Unity LevelPlay。在到达广告位之前先准备好获胜平台:
- 并行加载 CloudX 和 LevelPlay。
- 等待两个平台都加载完成或加载失败。
- 只将已加载的候选项提交给 Trusted Arbiter。
- 缓存选中的平台。
- 到达广告位时,立即展示缓存的获胜广告。
如果两个平台都加载失败,开始新的加载周期。如果到达广告位时还没有准备好获胜平台,则继续应用流程,不展示广告。
ArbiterInterstitialController.kt
/**
* 提前准备好 Trusted Arbiter 的获胜平台,以便在到达广告位时立即展示插屏广告。
*
* 并行加载 [cloudXInterstitial] 和 [levelPlayInterstitial],等待两者都加载完成或加载失败后,
* 将已加载的候选项提交给 [CloudX.arbiter],并将选中的 [CloudXArbiterPlatform] 缓存到
* [nextWinner] 中。
*/
class ArbiterInterstitialController(
private val cloudXInterstitial: CloudXInterstitialAd,
private val levelPlayInterstitial: LevelPlayInterstitialAd,
) {
/** 在获胜平台准备就绪后接收仲裁结果。 */
interface Listener {
/** 当仲裁器为下一次展示选定 [platform] 时调用。 */
fun onWinnerPrepared(platform: CloudXArbiterPlatform)
}
/** 设置该属性以监听 [Listener.onWinnerPrepared] 回调。 */
var listener: Listener? = null
private var cloudXAd: CloudXAd? = null
private var cloudXLoadDone = false
private var levelPlayAdInfo: LevelPlayAdInfo? = null
private var levelPlayLoadDone = false
private var nextWinner: CloudXArbiterPlatform? = null
init {
cloudXInterstitial.listener = createCloudXListener()
levelPlayInterstitial.setListener(createLevelPlayListener())
}
/** 为当前没有缓存广告的每个平台启动加载。 */
fun loadMissingAds() {
if (cloudXAd == null) cloudXInterstitial.load()
if (levelPlayAdInfo == null) levelPlayInterstitial.loadAd()
}
/**
* 在 [activity] 上展示已准备好的获胜广告,仅在实际调用展示方法时返回 true。
*
* 当没有就绪的获胜平台,或缓存的广告已不再可用时返回 false,此时会启动新的加载周期。
*/
fun showAtPlacement(activity: Activity): Boolean {
return when (nextWinner) {
CloudXArbiterPlatform.CLOUDX -> showCloudX(activity)
CloudXArbiterPlatform.LEVELPLAY -> showLevelPlay(activity)
else -> false
}
}
/**
* 在两个平台都完成加载后运行仲裁器,然后缓存获胜平台。
*
* 在两个加载都完成之前会提前返回。如果两个平台都未加载成功,则重新启动加载周期;
* 否则将已加载的候选项提交给 [CloudX.arbiter]。
*/
private fun maybePrepareWinner() {
if (!cloudXLoadDone || !levelPlayLoadDone) return
if (cloudXAd == null && levelPlayAdInfo == null) {
cloudXLoadDone = false
levelPlayLoadDone = false
loadMissingAds()
return
}
val bids = listOfNotNull(
cloudXAd?.let { CloudXArbiterBid.cloudX(it) },
levelPlayAdInfo?.let { adInfo ->
CloudXArbiterBid.levelPlay(
networkName = adInfo.adNetwork,
revenue = adInfo.revenue,
precision = adInfo.precision,
)
}
)
CloudX.arbiter(
configuration = CloudXArbiterConfiguration.builder(bids).build(),
listener = object : CloudXArbiterListener {
override fun onCompleted(result: CloudXArbiterResult) {
nextWinner = result.platform
listener?.onWinnerPrepared(result.platform)
}
}
)
}
private fun showCloudX(activity: Activity): Boolean {
if (cloudXInterstitial.isAdReady) {
cloudXInterstitial.show(activity)
return true
}
clearCloudXAndLoadMissingAds()
return false
}
private fun showLevelPlay(activity: Activity): Boolean {
if (levelPlayInterstitial.isAdReady) {
levelPlayInterstitial.showAd(activity)
return true
}
clearLevelPlayAndLoadMissingAds()
return false
}
private fun clearCloudXAndLoadMissingAds() {
cloudXAd = null
cloudXLoadDone = false
nextWinner = null
loadMissingAds()
}
private fun clearLevelPlayAndLoadMissingAds() {
levelPlayAdInfo = null
levelPlayLoadDone = false
nextWinner = null
loadMissingAds()
}
private fun createCloudXListener() = object : CloudXInterstitialListener {
override fun onAdLoaded(cloudXAd: CloudXAd) {
this@ArbiterInterstitialController.cloudXAd = cloudXAd
cloudXLoadDone = true
maybePrepareWinner()
}
override fun onAdLoadFailed(adUnitId: String, cloudXError: CloudXError) {
cloudXAd = null
cloudXLoadDone = true
maybePrepareWinner()
}
override fun onAdDisplayed(cloudXAd: CloudXAd) = Unit
override fun onAdDisplayFailed(cloudXAd: CloudXAd, cloudXError: CloudXError) {
clearCloudXAndLoadMissingAds()
}
override fun onAdHidden(cloudXAd: CloudXAd) {
clearCloudXAndLoadMissingAds()
}
override fun onAdClicked(cloudXAd: CloudXAd) = Unit
}
private fun createLevelPlayListener() = object : LevelPlayInterstitialAdListener {
override fun onAdLoaded(levelPlayAdInfo: LevelPlayAdInfo) {
this@ArbiterInterstitialController.levelPlayAdInfo = levelPlayAdInfo
levelPlayLoadDone = true
maybePrepareWinner()
}
override fun onAdLoadFailed(levelPlayAdError: LevelPlayAdError) {
levelPlayAdInfo = null
levelPlayLoadDone = true
maybePrepareWinner()
}
override fun onAdInfoChanged(levelPlayAdInfo: LevelPlayAdInfo) {
this@ArbiterInterstitialController.levelPlayAdInfo = levelPlayAdInfo
}
override fun onAdDisplayed(levelPlayAdInfo: LevelPlayAdInfo) = Unit
override fun onAdDisplayFailed(
levelPlayAdError: LevelPlayAdError,
levelPlayAdInfo: LevelPlayAdInfo
) {
clearLevelPlayAndLoadMissingAds()
}
override fun onAdClosed(levelPlayAdInfo: LevelPlayAdInfo) {
clearLevelPlayAndLoadMissingAds()
}
override fun onAdClicked(levelPlayAdInfo: LevelPlayAdInfo) = Unit
}
}
showAtPlacement() 只有在实际调用广告展示方法时才会返回 true。onAdInfoChanged() 会在 LevelPlay 广告仍然处于已加载状态时,保持缓存的 LevelPlay 候选项为最新。
对于 PubMatic OpenWrap,使用 CloudXArbiterBid.pubmatic(price, partnerName) 创建第三方出价。如果仲裁服务不可用,SDK 会在传入的受支持出价中回退选择可比较美元出价最高的平台。