Android SDK
ADBNK Android SDK 用于在原生 Android App 中展示广告。API 命名与 Google Mobile Ads(AdMob)一致:AdRequest、AdLoadCallback、FullScreenContentCallback、OnUserEarnedRewardListener。
版本:以你拿到的 SDK 包为准。运行时可通过 AdbnkSdk.getVersion() 获取。
环境要求
| 项目 | 要求 |
|---|---|
| minSdk | 21(Android 5.0) |
| compileSdk | 34 及以上 |
| 语言 | Kotlin 或 Java(Java 8 字节码) |
| 权限 | INTERNET 和 ACCESS_NETWORK_STATE 由 SDK 的 manifest 自动合并,无需自行声明 |
每个广告位还需要一个广告位 ID。在流量主后台创建 App SDK 广告位,进入广告位管理,点击获取代码即可复制该广告位 ID。
安装
SDK 以二进制 AAR 形式交付。如需获取 SDK 包,请联系你的 ADBNK 客户经理。
把 AAR 复制到 app/libs/,然后连同 SDK 依赖的库一起添加:
// app/build.gradle.kts
dependencies {
implementation(files("libs/adbnk-sdk.aar")) // use the file name from your package
// Required by the ADBNK SDK
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.browser:browser:1.7.0")
}这些都是标准的 AndroidX 与 Kotlin 库,新建的 Android 项目默认即可解析。AAR 自带 consumer ProGuard/R8 规则,开启代码压缩时无需额外添加 keep 规则。
初始化
在 Application.onCreate() 中初始化一次,且须在加载任何广告之前完成。
import android.app.Application
import app.adbnk.sdk.AdbnkSdk
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
AdbnkSdk.init(
application = this,
appId = "com.example.myapp" // your app identifier
) { success, error ->
// success == true once the SDK is ready
}
}
}AdbnkSdk.AdConfig 字段:
| 字段 | 默认值 | 说明 |
|---|---|---|
testMode | false | 见测试模式 |
gdprConsent | null | GDPR 同意状态。null 表示未知,按未同意处理,见隐私与合规 |
coppaCompliance | false | 将所有请求视为面向儿童 |
AdbnkSdk 的其他方法:isInitialized()、getVersion()、getAppId()、getConfig()、setGdprConsent(Boolean)、setCoppaCompliance(Boolean) 和 setTestMode(Boolean)。
Java 调用
各广告类的 load 方法位于 companion object 上,Java 中写作 InterstitialAd.Companion.load(...)。AdbnkSdk 是 Kotlin object,Java 中通过 AdbnkSdk.INSTANCE 访问。
AdRequest
所有广告格式都可传入一个可选的 AdRequest,其中每个字段都是可选的。
val request = AdRequest.Builder()
.addKeyword("sports")
.setContentUrl("https://example.com/article/123")
.setNonPersonalizedAds(false)
.setTagForChildDirected(null) // true / false / null = not specified
.setTagForUnderAgeOfConsent(null)
.putExtra("placement", "home_feed")
.build()AdRequest.empty() 返回默认值的请求。不传 AdRequest 加载,等同于传入空请求。
广告格式
| 格式 | 类 | 形式 |
|---|---|---|
| 横幅 Banner | BannerAdView | 放在布局中的 View |
| 悬浮横幅(固定在屏幕顶部或底部) | FloatBannerAd | 浮层 |
| 原生 Native | NativeAd | 由你自行渲染素材 |
| 插屏 Interstitial | InterstitialAd | 全屏 |
| 激励 Rewarded | RewardedAd | 全屏 + 奖励 |
| 激励插屏 Rewarded interstitial | RewardedInterstitialAd | 全屏 + 奖励 |
| 开屏 Splash | SplashAd | App 启动时全屏 |
| 应用打开 App open | AppOpenAd | App 回到前台时全屏 |
| 弹窗 Popup | PopupAd | 对话框式浮层 |
请使用格式与类相匹配的广告位。如果广告位返回了当前 SDK 版本无法渲染的格式,加载会以 ERROR_CODE_UNSUPPORTED_FORMAT 失败,App 不会崩溃。
全屏格式:通用流程
插屏、激励、激励插屏、开屏、应用打开和弹窗广告的用法相同:
- 调用
XxxAd.load(zoneId, adRequest, AdLoadCallback<XxxAd>),也可以调用load(zoneId, callback)。 - 在
onAdLoaded中设置setFullScreenContentCallback(...)。 - 准备好后调用
ad.show(activity)。
每个加载成功的广告对象只能展示一次。广告展示后或过期后,isReady() 返回 false。下一次展示请重新加载广告。
interface FullScreenContentCallback {
fun onAdShowedFullScreenContent() {}
fun onAdDismissedFullScreenContent() {}
fun onAdFailedToShowFullScreenContent(error: AdError) {}
fun onAdImpression() {}
fun onAdClicked() {}
}以上方法都有默认实现,只需重写需要的方法。
插屏
import app.adbnk.sdk.*
import app.adbnk.sdk.ads.InterstitialAd
import app.adbnk.sdk.listener.AdError
private var interstitial: InterstitialAd? = null
fun loadInterstitial() {
InterstitialAd.load("YOUR_ZONE_ID", AdRequest.empty(), object : AdLoadCallback<InterstitialAd> {
override fun onAdLoaded(ad: InterstitialAd) {
ad.setFullScreenContentCallback(object : FullScreenContentCallback {
override fun onAdDismissedFullScreenContent() {
interstitial = null
loadInterstitial() // preload the next one
}
override fun onAdFailedToShowFullScreenContent(error: AdError) {
interstitial = null
}
})
interstitial = ad
}
override fun onAdFailedToLoad(error: AdError) {
interstitial = null
}
})
}
fun showInterstitial(activity: Activity) {
interstitial?.takeIf { it.isReady() }?.show(activity)
}激励与激励插屏
RewardedAd 与 RewardedInterstitialAd 的 API 相同。请在 OnUserEarnedRewardListener 中发放奖励,SDK 对每个广告最多回调一次。
import app.adbnk.sdk.ads.RewardedAd
import app.adbnk.sdk.models.RewardItem
RewardedAd.load("YOUR_ZONE_ID", object : AdLoadCallback<RewardedAd> {
override fun onAdLoaded(ad: RewardedAd) {
ad.setOnUserEarnedRewardListener { reward: RewardItem ->
grantReward(reward.amount, reward.type)
}
ad.setFullScreenContentCallback(object : FullScreenContentCallback {
override fun onAdDismissedFullScreenContent() { /* resume the game */ }
})
ad.show(activity)
}
override fun onAdFailedToLoad(error: AdError) { /* hide the reward button */ }
})奖励数量和类型在流量主后台的广告位上配置,以 RewardItem(amount: Int, type: String) 的形式传给你的 App。
开屏
在启动 Activity 中尽早加载开屏广告,加载成功后立即展示;广告关闭或展示失败后再进入主界面。
import app.adbnk.sdk.ads.SplashAd
SplashAd.load("YOUR_ZONE_ID", object : AdLoadCallback<SplashAd> {
override fun onAdLoaded(ad: SplashAd) {
ad.setFullScreenContentCallback(object : FullScreenContentCallback {
override fun onAdDismissedFullScreenContent() = goToMain()
override fun onAdFailedToShowFullScreenContent(error: AdError) = goToMain()
})
ad.show(this@SplashActivity)
}
override fun onAdFailedToLoad(error: AdError) = goToMain()
})开屏广告带倒计时和跳过按钮。
应用打开
手动方式: 与插屏一样,自行加载和展示:
import app.adbnk.sdk.ads.AppOpenAd
AppOpenAd.load("YOUR_ZONE_ID", object : AdLoadCallback<AppOpenAd> {
override fun onAdLoaded(ad: AppOpenAd) { appOpenAd = ad }
override fun onAdFailedToLoad(error: AdError) {}
})
// later, when the app comes back to the foreground:
appOpenAd?.takeIf { it.isReady() }?.show(activity)自动方式: 在 Application.onCreate() 中(init 之后)调用一次 setup。SDK 会预加载广告,并在 App 每次回到前台时展示。
AppOpenAd.setup(this, "YOUR_ZONE_ID")弹窗
import app.adbnk.sdk.ads.PopupAd
PopupAd.load("YOUR_ZONE_ID", object : AdLoadCallback<PopupAd> {
override fun onAdLoaded(ad: PopupAd) { ad.show(activity) }
override fun onAdFailedToLoad(error: AdError) {}
})关闭按钮的行为在流量主后台的广告位上配置。
横幅
BannerAdView 是一个 FrameLayout。在代码中创建,加入布局后调用 loadAd()。
import app.adbnk.sdk.ads.BannerAdView
import app.adbnk.sdk.ads.BannerSize
import app.adbnk.sdk.listener.AdError
import app.adbnk.sdk.listener.BannerAdListener
val banner = BannerAdView(context).apply {
zoneId = "YOUR_ZONE_ID"
bannerSize = BannerSize.BANNER // 320x50
adListener = object : BannerAdListener {
override fun onAdLoaded() {}
override fun onAdFailedToLoad(error: AdError) {}
override fun onAdClicked() {}
}
setAdRequest(AdRequest.empty()) // optional
}
container.addView(banner)
banner.loadAd()在 Activity 或 Fragment 中转发生命周期:
override fun onPause() { banner.pause(); super.onPause() }
override fun onResume() { super.onResume(); banner.resume() }
override fun onDestroy() { banner.destroy(); super.onDestroy() }BannerSize 取值:BANNER(320×50)、LARGE_BANNER(320×100)、MEDIUM_RECTANGLE(300×250)、FULL_BANNER(468×60)、LEADERBOARD(728×90)和 ADAPTIVE(撑满容器宽度)。请选择与广告位一致的尺寸。
自动刷新:如果广告位在后台设置了刷新间隔,以后台设置为准;否则使用 refreshInterval(单位秒,0 表示不刷新)。
WARNING
请在代码中创建 BannerAdView。当前版本不读取 app:adbnk_zone_id 等 XML 属性。
悬浮横幅
FloatBannerAd 以浮层形式把横幅固定在屏幕顶部或底部,不占用布局空间。它加载成功后会自动展示。
import app.adbnk.sdk.ads.FloatBannerAd
import app.adbnk.sdk.ads.FloatBannerPosition
val floatBanner = FloatBannerAd(activity).apply {
zoneId = "YOUR_ZONE_ID"
position = FloatBannerPosition.BOTTOM
showCloseButton = true
marginDp = 0
autoHideAfter = 0 // seconds, 0 = never
adListener = object : BannerAdListener {
override fun onAdLoaded() {}
override fun onAdFailedToLoad(error: AdError) {}
}
}
floatBanner.loadAd()
// floatBanner.hide() / floatBanner.show() / floatBanner.isShowing() / floatBanner.isLoaded()
// In onPause/onResume/onDestroy: floatBanner.pause() / resume() / destroy()原生
原生广告由 SDK 返回素材,你用自己的 View 排版。
import app.adbnk.sdk.ads.NativeAd
NativeAd.load("YOUR_ZONE_ID", object : AdLoadCallback<NativeAd> {
override fun onAdLoaded(ad: NativeAd) {
headlineView.text = ad.getHeadline()
bodyView.text = ad.getBody()
ctaButton.text = ad.getCallToAction()
advertiserView.text = ad.getAdvertiser()
sponsoredLabel.text = ad.getSponsoredLabel() // always show an ad label
ad.loadIcon { bmp -> iconView.setImageBitmap(bmp) }
ad.loadMainImage { bmp -> imageView.setImageBitmap(bmp) }
// Required: lets the SDK measure impressions and handle clicks
ad.registerViewForInteraction(adContainer, listOf(ctaButton, imageView))
nativeAd = ad
}
override fun onAdFailedToLoad(error: AdError) {}
})
// When the view is recycled or the screen closes:
nativeAd?.unregisterView()
nativeAd?.destroy()| Getter | 内容 |
|---|---|
getHeadline() | 标题 |
getBody() | 描述 |
getCallToAction() | 按钮文案 |
getAdvertiser() | 广告主或赞助方名称 |
getIconUrl() / loadIcon {} | 图标 |
getMainImageUrl() / loadMainImage {} | 主图 |
getStarRating() | 评分,1–5(可为空) |
getPrice() | 价格(可为空) |
getSponsoredLabel() | 广告标识文案 |
getAssets() | 以 NativeAdAssets 对象返回全部素材 |
原生广告的行为:
- 请调用
registerViewForInteraction,SDK 会据此测量展示并处理点击。 clickableViews为空时,整个容器都可点击。- 如需接收点击通知,调用
ad.setListener(object : NativeAdListener { override fun onAdClicked() {} })。
点击处理
无需编写任何点击处理代码。用户点击时,SDK 记录点击,若广告带有 App deeplink 则唤起该 App;deeplink 无法打开或广告没有 deeplink 时,打开落地页。
隐私与合规
ADBNK SDK 自身不弹出任何同意框或权限框。由你的 App 收集用户同意,再把结果传给 SDK。
GDPR / 欧洲经济区及英国用户: 用你自己的 CMP 收集同意,然后把结果传给 SDK:
AdbnkSdk.setGdprConsent(userConsented)WARNING
未设置时同意状态为未知,SDK 按未同意处理。拿到用户的选择后,请在加载广告之前调用 setGdprConsent(true) 或 setGdprConsent(false)。
非个性化广告: 使用 AdRequest.Builder().setNonPersonalizedAds(true)。
COPPA 与面向儿童的 App:
AdbnkSdk.setCoppaCompliance(true) // whole app
AdRequest.Builder().setTagForChildDirected(true) // per request
AdRequest.Builder().setTagForUnderAgeOfConsent(true) // users under the age of consent未获同意、或面向儿童/非个性化的请求,SDK 不使用广告标识。为保障流量安全,仍会处理有限的技术数据。
Google Play 数据安全: 请在数据安全表单中申报 SDK 的数据使用情况。如需 SDK 的数据披露说明,请联系 ADBNK 支持。
测试模式
testMode/setTestMode(true)会把请求标记为测试流量。ADBNK 目前不提供专用测试素材,开发期间看到的是真实广告。请勿在自己的设备上反复点击广告。- SDK 自动处理流量质量保护,无需任何配置。
错误码
AdError 包含 code、message 和 domain("app.adbnk.sdk")。错误码常量位于 AdError.Companion:
| 错误码 | 常量 | 含义 |
|---|---|---|
| 0 | ERROR_CODE_INTERNAL | 内部错误 |
| 1 | ERROR_CODE_INVALID_REQUEST | 请求无效 |
| 2 | ERROR_CODE_NETWORK | 网络错误 |
| 3 | ERROR_CODE_NO_FILL | 暂无可用广告。请稍后重试,避免密集重试 |
| 4 | ERROR_CODE_TIMEOUT | 请求超时 |
| 5 | ERROR_CODE_NOT_INITIALIZED | 未调用 AdbnkSdk.init() |
| 6 | ERROR_CODE_INVALID_ZONE_ID | 广告位 ID 为空或无效 |
| 7 | ERROR_CODE_AD_EXPIRED | 广告已过期或未就绪,请重新加载 |
| 8 | ERROR_CODE_AD_ALREADY_SHOWN | 该广告对象已展示过 |
| 9 | ERROR_CODE_AD_NOT_READY | 广告尚未准备好展示 |
| 10 | ERROR_CODE_AD_ALREADY_LOADING | 已有加载在进行中 |
| 11 | ERROR_CODE_UNSUPPORTED_FORMAT | 当前 SDK 版本不支持该广告位的广告格式 |
常见问题
总是返回无填充(3)。 检查三点:广告位 ID 是从获取代码中复制的;广告位是 App SDK 广告位,且格式与你加载的类一致;广告位在后台处于启用状态。新建的广告位初期填充率可能较低。
广告加载成功但 show() 没有反应。 确认 isReady() 返回 true。每个广告对象只能展示一次,并且一段时间后会过期。每次展示都请加载新的广告。
还能用旧的 lambda 写法 load(zoneId) { ad, error -> } 和 AdListener 风格的 API 吗? 仍可使用,但已废弃。请改用 AdLoadCallback 配合 FullScreenContentCallback。
排查信息: 每个广告对象都提供 getResponseInfo().responseId,联系支持时请附上。