ToBid Android 接入指南
本文档指导开发者在 Android 端将优聚智汇 SDK 以**自定义广告网络(Custom Adapter)**形式接入 ToBid(Sigmob WindMill)聚合平台。
阅读前置
请先阅读 ToBid 自定义接入概述,了解反向集成模式、工作原理、后台配置与常见问题。本文仅介绍 Android 端的依赖引入、SDK 初始化、广告加载与混淆规则。
依赖引入
1. 引入优聚 SDK 核心库
确保工程已引入优聚智汇 SDK 核心模块与 ADX 模块(ToBid 适配器运行时依赖):
// app 模块的 build.gradle.kts
dependencies {
// 优聚 SDK 核心 + ADX(本地 aar 或 maven 坐标二选一)
implementation("com.ujusdk:uju-ad-core:3.1.49")
implementation("com.ujusdk:uju-ad-adx:1.0.24")
}2. 引入 ToBid 聚合 SDK
ToBid(Sigmob WindMill)SDK 以本地 aar 形式提供,需将以下 aar 文件放入 app 模块的 libs/ 目录:
| 文件 | 说明 |
|---|---|
windmill-sdk-4.3.11.aar | WindMill 聚合 SDK 主包 |
wind-sdk-4.19.8.aar | Wind 广告核心包 |
wind-common-1.7.6.aar | Wind 公共基础库 |
oaid_sdk_1.0.25.aar | OAID 采集(含华为 ads-identifier) |
dependencies {
// ToBid 聚合 SDK 及其依赖(本地 aar)
implementation(files("libs/windmill-sdk-4.3.11.aar"))
implementation(files("libs/wind-sdk-4.19.8.aar"))
implementation(files("libs/wind-common-1.7.6.aar"))
implementation(files("libs/oaid_sdk_1.0.25.aar"))
// ToBid 运行所需的网络与 UI 依赖
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okio:okio:3.6.0")
implementation("com.google.code.gson:gson:2.8.5")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
// 荣耀广告标识服务(华为 ads-identifier 已由 oaid_sdk 提供,无需重复引入)
implementation("com.hihonor.mcs:ads-identifier:1.0.2.301")
}3. 引入优聚 ToBid 适配器
引入优聚官方提供的 ToBid 自定义适配器模块,运行时由 ToBid 反射加载:
dependencies {
// 优聚 ToBid 自定义适配器(必须 implementation,运行时被 ToBid 反射加载)
implementation("com.ujusdk:uju-custom-tobid-adapter:4.3.11")
}必须使用 implementation
适配器必须以 implementation 方式引入,确保其类被编译进宿主 APK,供 ToBid 运行时通过反射发现并调用。
ToBid SDK 初始化
开发者只需初始化 ToBid SDK,优聚 SDK 的初始化由 ToBid 在启动时自动触发(通过适配器的 ADN 初始化入口)。
在 Application.onCreate() 中初始化 ToBid:
import android.app.Application
import android.util.Log
import com.windmill.sdk.WindMillAd
import com.windmill.sdk.WMNetworkInitListener
class App : Application() {
private val TAG = "App"
override fun onCreate() {
super.onCreate()
initToBidSdk()
}
private fun initToBidSdk() {
Log.d(TAG, "initToBidSdk 开始")
try {
// 获取 ToBid SDK 单例
val ads = WindMillAd.sharedAds()
// 是否成年(可选参数,默认是成年用户)
ads.setAdult(true)
// 是否开启个性化推荐(可选参数,默认开启)
ads.setPersonalizedAdvertisingOn(true)
// 开启 Debug 日志(调试阶段建议开启)
ads.setDebugEnable(true)
// 渠道初始化监听(可选):监听各广告网络初始化结果
ads.setNetworkInitListener(object : WMNetworkInitListener {
override fun onNetworkInitBefore(channel_id: Int, initInstance: Any?) {
Log.d(TAG, "onNetworkInitBefore: channel_id=$channel_id")
}
override fun onNetworkInitSuccess(channel_id: Int) {
Log.d(TAG, "onNetworkInitSuccess: channel_id=$channel_id")
}
override fun onNetworkInitFailed(channel_id: Int, error_code: Int, error_msg: String?) {
Log.w(TAG, "onNetworkInitFailed: channel_id=$channel_id, code=$error_code, msg=$error_msg")
}
})
// 启动 ToBid SDK,传入 ToBid 后台分配的 AppId
ads.startWithAppId(
this,
TOBID_APP_ID,
object : WindMillAd.WindMillAdInitListener {
override fun onInitSuccess() {
Log.d(TAG, "ToBid SDK 初始化成功")
}
override fun onInitFailed(error_code: Int, error_msg: String?) {
Log.e(TAG, "ToBid SDK 初始化失败: code=$error_code, msg=$error_msg")
}
}
)
} catch (e: Exception) {
Log.e(TAG, "initToBidSdk 异常: ${e.message}", e)
}
}
companion object {
// ToBid 平台分配的 AppId
private const val TOBID_APP_ID = "YOUR_TOBID_APP_ID"
}
}优聚 SDK 无需单独初始化
ToBid SDK 启动后会自动触发优聚 SDK 的 init + start 流程,开发者无需也不应调用 UjuAdSdk.init() / UjuAdSdk.start()。
广告加载示例
以下以激励视频为例,展示通过 ToBid 标准接口加载广告的完整流程。开屏、插屏、原生广告的调用方式类似,仅广告对象类名不同。
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import com.windmill.sdk.models.AdInfo
import com.windmill.sdk.reward.WMRewardAd
import com.windmill.sdk.reward.WMRewardAdListener
import com.windmill.sdk.reward.WMRewardAdRequest
import com.windmill.sdk.WindMillError
class RewardAdActivity : ComponentActivity() {
private val TAG = "RewardAdActivity"
// 激励视频广告对象
private var rewardAd: WMRewardAd? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
loadRewardAd()
}
private fun loadRewardAd() {
Log.d(TAG, "开始加载激励视频广告: placementId=$REWARD_PLACEMENT_ID")
try {
// 构造广告请求(placementId 必填,userId 和 options 可选)
val request = WMRewardAdRequest(
REWARD_PLACEMENT_ID,
"", // userId 可选
null // options 可选
)
// 创建激励视频广告对象
rewardAd = WMRewardAd(this, request)
// 设置监听回调
rewardAd?.setRewardedAdListener(object : WMRewardAdListener {
override fun onVideoAdLoadSuccess(placementId: String?) {
Log.d(TAG, "广告加载成功: $placementId")
// 加载成功后可调用 show 展示
}
override fun onVideoAdLoadError(error: WindMillError?, placementId: String?) {
Log.e(TAG, "广告加载失败: ${error?.errorCode}-${error?.message}")
}
override fun onVideoAdPlayStart(adInfo: AdInfo?) {
Log.d(TAG, "广告开始播放")
}
override fun onVideoAdPlayError(error: WindMillError?, placementId: String?) {
Log.e(TAG, "广告播放失败: ${error?.errorCode}-${error?.message}")
}
override fun onVideoAdPlayEnd(adInfo: AdInfo?) {
Log.d(TAG, "广告播放结束")
}
override fun onVideoAdClicked(adInfo: AdInfo?) {
Log.d(TAG, "广告被点击")
}
override fun onVideoRewarded(adInfo: AdInfo?, rewardInfo: com.windmill.sdk.reward.WMRewardInfo?) {
Log.d(TAG, "获得奖励: isReward=${rewardInfo?.isReward()}")
// 在此发放应用内奖励
}
override fun onVideoAdClosed(adInfo: AdInfo?) {
Log.d(TAG, "广告关闭")
}
})
// 发起加载
rewardAd?.loadAd()
} catch (e: Exception) {
Log.e(TAG, "加载异常: ${e.message}", e)
}
}
private fun showRewardAd() {
try {
// 空指针检查:广告对象存在且就绪才展示
if (rewardAd != null && rewardAd?.isReady() == true) {
rewardAd?.show(this, null)
} else {
Log.w(TAG, "广告未就绪,无法展示")
}
} catch (e: Exception) {
Log.e(TAG, "展示异常: ${e.message}", e)
}
}
override fun onDestroy() {
super.onDestroy()
// 销毁广告对象,释放资源
rewardAd?.destroy()
rewardAd = null
}
companion object {
// ToBid 后台配置的广告位 ID(对应优聚广告位)
private const val REWARD_PLACEMENT_ID = "YOUR_TOBID_REWARD_PLACEMENT_ID"
}
}各广告类型对应类
| 广告类型 | ToBid 广告类 | 请求类 |
|---|---|---|
| 开屏 | WMSplashAd | WMSplashAdRequest |
| 激励视频 | WMRewardAd | WMRewardAdRequest |
| 插屏 | WMInterstitialAd | WMInterstitialAdRequest |
| 原生 | WMNativeAd | WMNativeAdRequest |
横幅广告说明
Android 端暂未提供独立的 ToBid Banner 适配器。如需 Banner,可参考其他适配器实现自行扩展,或联系优聚技术支持。
ProGuard 混淆规则
引入 ToBid 适配器后,需在 app 模块的 proguard-rules.pro 中添加以下规则,避免反射调用的类被混淆:
# 保留优聚 ToBid 自定义适配器类(ToBid 通过反射调用,不能混淆)
-keep class com.ujusdk.tobid.** { *; }
# 保留 ToBid SDK 的 WMCustom* 基类(避免编译期引用丢失)
-keep class com.windmill.sdk.custom.** { *; }
-keep class com.windmill.sdk.models.** { *; }
-keep class com.windmill.sdk.natives.** { *; }
-keep class com.windmill.sdk.base.** { *; }
-keep class com.windmill.sdk.WMConstants { *; }
-keep class com.windmill.sdk.WindMillError { *; }consumer-rules 已内置
优聚 ToBid 适配器模块的 consumer-rules.pro 已包含 com.ujusdk.tobid.** 的保留规则,引入该模块的 app 会自动应用。上述规则中 WindMill SDK 部分需开发者自行添加。
适配器架构说明
优聚 ToBid 适配器位于 com.ujusdk.tobid 包下,采用 ToBid 自定义广告网络标准接口实现:
- 初始化代理:实现 ToBid 的 ADN 初始化接口,在 ToBid 启动时解析后台
CustomInfo(appId/appKey/channel),完成优聚 SDK 的init+start流程,并回调 ToBid 初始化结果 - 广告适配器:每种广告类型(开屏/激励/插屏/原生)对应一个独立的适配器类,实现 ToBid 的
WMCustom*Adapter接口,负责广告的加载、展示、销毁与事件回调转发 - 初始化等待机制:适配器内部维护初始化状态追踪,各广告适配器在
loadAd入口会等待优聚 SDK 初始化完成后再执行实际加载,避免 "no strategy" 错误 - 配置解析:统一解析 ToBid 后台下发的
CustomInfoJSON 字符串,提取 appId/appKey/channel(ADN 级别)与 placementId(广告位级别)
内部实现无需关注
适配器内部的所有类、方法与状态机均为 SDK 内部实现细节,开发者无需直接调用。开发者只需通过 ToBid 标准接口(WindMillAd / WMRewardAd 等)使用广告,后台配置正确的 CustomInfo 即可。
相关链接
- ToBid 自定义接入概述 — 反向集成模式、工作原理、后台配置、常见问题
- iOS 接入指南 — iOS 端接入步骤
- 自定义广告平台概述 — 反向集成概念说明
- Android SDK 初始化 — 优聚 SDK 标准初始化流程(参考)
