STEP 01添加仓库与下载鉴权
使用有包访问权限的 GitHub 用户名和 PAT(read:packages),通过环境变量注入。基础要求:Android minSdk 26、Java / JVM 17;SDK 源码使用 compileSdk 36。
// settings.gradle.kts → dependencyResolutionManagement.repositories
maven {
url = uri("https://maven.pkg.github.com/toukaRemax/remax_sdk")
credentials {
username = providers.environmentVariable("REMAX_SDK_USER").orNull
password = providers.environmentVariable("REMAX_SDK_TOKEN").orNull
}
}
// app/build.gradle.kts → dependencies
implementation("com.github.toukaremax:core:1.0.15")
implementation("com.github.toukaremax:bill:1.0.51_preloading.3")这两个环境变量是示例命名。鉴权用于下载依赖;广告展示接口无需再传此 Token。
同时添加第三方广告依赖仓库
// 同样放在 dependencyResolutionManagement.repositories 中
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
maven { url = uri("https://artifact.bytedance.com/repository/pangle/") }
maven { url = uri("https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_oversea") }
maven { url = uri("https://android-sdk.is.com/") }
maven { url = uri("https://jfrog.anythinktech.com/artifactory/overseas_sdk") }
maven { url = uri("https://cboost.jfrog.io/artifactory/chartboost-ads/") }
maven { url = uri("https://cboost.jfrog.io/artifactory/chartboost-mediation") }
maven { url = uri("https://cboost.jfrog.io/artifactory/chartboost-core") }使用在线广告配置时,宿主需配置自己的 Firebase 项目(google-services.json 和 Google Services Gradle 插件,或自行初始化 FirebaseApp)。
STEP 02设置日志与用户渠道
在 Application.attachBaseContext 的 super 调用后设置,早于广告初始化。
import com.android.common.bill.ads.log.AdLogger
import net.corekit.core.log.CoreLogger
import net.corekit.core.controller.ChannelUserController
CoreLogger.setLogEnabled(BuildConfig.DEBUG)
AdLogger.setLogEnabled(BuildConfig.DEBUG)
ChannelUserController.setDefaultChannel("natural") // natural / paid
// 得到用户归因结果后再调用;不要每次启动强制覆盖。
ChannelUserController.setChannel(ChannelUserController.UserChannelType.PAID)
val channel = ChannelUserController.getCurrentChannel()setDefaultChannel 设置未归因时的默认值;setChannel 受首次设置状态约束。渠道决定使用自然 / 买量广告策略。
STEP 03配置广告源并初始化
在主进程协程中调用一次,等待返回后再预加载或展示。下面按已有接入方式列出四个平台;用实际 ID / Key 替换占位符,仅填写接入的平台与广告类型。
import com.android.common.bill.BillConfig
import com.android.common.bill.ads.bidding.AppOpenBiddingInitializer
// suspend 代码;context 为宿主 Context,图标使用宿主资源。
AppOpenBiddingInitializer.initialize(context, R.mipmap.ic_launcher) {
externallyInitialized = false // 让库初始化平台 SDK
skipRuntimeAdIdConfig = false // 保留在线 ID 覆盖;仅用本地 ID 时设 true
googleMobileAds = BillConfig.GoogleMobileAdsConfig(
applicationId = "<GOOGLE_APP_ID>", // AdMob / GAM 共用
)
admob = BillConfig.AdmobConfig(
splashId = "<ID>", bannerId = "<ID>", interstitialId = "<ID>",
nativeId = "<ID>", fullNativeId = "<ID>", rewardedId = "<ID>",
)
gam = BillConfig.GamConfig(
splashId = "<ID>", bannerId = "<ID>", interstitialId = "<ID>",
nativeId = "<ID>", fullNativeId = "<ID>", rewardedId = "<ID>",
)
pangle = BillConfig.PangleConfig(
applicationId = "<PANGLE_APP_ID>",
splashId = "<ID>", bannerId = "<ID>", interstitialId = "<ID>",
nativeId = "<ID>", fullNativeId = "<ID>", rewardedId = "<ID>",
)
topon = BillConfig.ToponConfig(
applicationId = "<TOPON_APP_ID>", appKey = "<TOPON_APP_KEY>",
splashId = "<ID>", bannerId = "<ID>", interstitialId = "<ID>",
nativeId = "<ID>", fullNativeId = "<ID>", rewardedId = "<ID>",
)
// 在这里一并注册下面的全局回调与所需 Renderer。
}Google 初始化:本版本使用 GMA Next Gen,App ID 通过上面的 googleMobileAds 注入;不要为这条链路额外添加 Legacy 的 com.google.android.gms.ads.APPLICATION_ID Manifest 元数据或 Legacy Google Ads 依赖。
若宿主已自行初始化所有接入平台,设 externallyInitialized=true,仍需填写广告位和渲染配置。初始化返回表示流程结束,单个平台失败会记录日志,不代表所有平台都有可展示广告。
原生 / 全屏原生 / Loading 样式
使用原生广告前,实现并注入对应平台 Renderer 和布局。下列 My… 类、R.layout… 均由宿主提供,不是库内现成类。
// 放在 initialize 的配置块中;按实际平台注入。
admobNativeRenderer = MyAdmobNativeAdRenderer()
gamNativeRenderer = MyGamNativeAdRenderer()
pangleNativeRenderer = MyPangleNativeAdRenderer()
toponNativeRenderer = MyToponNativeAdRenderer()
admobFullScreenNativeRenderer = MyAdmobFullScreenNativeAdRenderer()
gamFullScreenNativeRenderer = MyGamFullScreenNativeAdRenderer()
pangleFullScreenNativeRenderer = MyPangleFullScreenNativeAdRenderer()
toponFullScreenNativeRenderer = MyToponFullScreenNativeAdRenderer()
// 以 AdMob 为例,其余使用对应平台的样式类型。
admob.nativeStyleStandard = com.android.common.bill.ui.NativeAdStyle(
R.layout.my_native_ad, "normal"
)
adLoadingDialogRenderer = MyAdLoadingDialogRenderer()接口在 com.android.common.bill.ads.renderer 包。原生展示缺少对应 Renderer 会失败;Loading Renderer 未配置时跳过加载弹框。
STEP 04注册点击、收益回调与统一上报
将下面两个回调合并到第 3 步的同一个初始化配置块中;无需再次初始化。每个属性只有一个回调,重复赋值会覆盖。
import com.android.common.bill.ads.bidding.AppOpenBiddingInitializer
import net.corekit.core.ads.RevenueAdData
import org.json.JSONObject
import java.math.BigDecimal
// 合并到第 3 步的初始化调用中,保留广告源配置。
AppOpenBiddingInitializer.initialize(application, R.mipmap.ic_launcher) {
onAdRevenue = { data ->
val args = data.toCallbackJson()
// 将 args 交给宿主的收益处理逻辑。
}
onAdClick = { data ->
val args = data.toCallbackJson()
// 将 args 交给宿主的点击处理逻辑。
}
}
// 定义在文件顶层或宿主类中。
private fun RevenueAdData.toCallbackJson(): JSONObject =
JSONObject().apply {
put("revenue", BigDecimal.valueOf(revenue.value))
put("currency", revenue.currencyCode)
put("adType", adFormat)
put("platform", platform)
put("adUnitId", adRevenueUnit)
put("adSource", adRevenueNetwork)
put("adSourceId", adSourceId)
}toCallbackJson() 是宿主侧扩展函数,点击和收益共用上述 7 个 JSON 字段。revenue 为单次收益的主货币单位,不要再次除以 1000。
| 回调字段(两者相同) | 含义 |
|---|---|
revenue.value / currencyCode | 单次收益 / 币种;按实际币种处理,SDK 不做汇率换算。 |
platform / adFormat | 聚合平台 / 广告类型。 |
adRevenueUnit | 聚合广告位 ID。 |
adRevenueNetwork / adSourceId | 广告源名称 / 底层源 ID;源 ID 无法获取时回退到聚合广告位 ID。 |
adRevenuePlacement | 平台的广告位置 / placement 信息,保留各平台语义。 |
回调在平台原线程同步执行,耗时操作自行切线程。点击回调不表示新增收益;广告位置参数 position 会进入事件链路的 ad_position,不要假定它总与平台 placement 相同。
统一事件 / 收益上报
在首次请求广告前,注册宿主的事件与收益上报器。
import net.corekit.core.ads.RevenueAdManager
import net.corekit.core.report.ReportDataManager
// My… 为宿主实现的上报器。
RevenueAdManager.setReporter(MyRevenueReporter()) // 实现 RevenueAdReporter
ReportDataManager.setReporters(listOf(MyEventReporter())) // 实现 ReporterData库负责产出数据,上报平台由宿主接入。收益 Reporter 与 onAdRevenue 独立触发,同一目的地只上报一次。若接 ThinkingData,对应 ReporterData.getName() 返回 "ThinkingData",供 SDK 定向事件使用。
STEP 05收集授权,按需预加载
下面在 FragmentActivity 的协程中执行;gatherConsent 挂起版本返回是否放行广告请求。它会判断地区,在非 GDPR 地区跳过弹窗。
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import com.android.common.bill.ads.util.GoogleMobileAdsConsentManager
import com.android.common.bill.ads.PreloadController
lifecycleScope.launch {
val consent = GoogleMobileAdsConsentManager.getInstance(applicationContext)
val allowed = consent.gatherConsent(this@MainActivity)
if (!allowed) return@launch
// 确保第 3 步初始化已结束,再按需要预加载。
PreloadController.preloadAll(applicationContext) // 插页 + 普通原生
// 可选,按实际使用的类型开启:
// PreloadController.preloadAllAppOpen(applicationContext)
// PreloadController.preloadAllRewarded(applicationContext)
// PreloadController.preloadAllFullScreenNative(applicationContext)
}预加载异步执行,调用返回不表示缓存已就绪;展示入口可在无缓存时尝试加载。只需要插页时,可改用 preloadAdmobInterstitial、preloadGamInterstitial、preloadPangleInterstitial、preloadTopOnInterstitial。
此授权辅助方法包含失败降级,返回值不等于用户必然点击了“同意”。隐私设置入口可结合 isPrivacyOptionsRequired 和 showPrivacyOptionsForm(activity) { error -> … } 使用。
STEP 06调用广告展示
在已初始化、已处理授权的有效 Activity 中调用。以下为独立片段,按需选择一个放入 lifecycleScope.launch { … },不要连续弹出。activity 为 FragmentActivity,container 为已挂入页面的 ViewGroup。
import com.android.common.bill.ads.ext.AdShowExt
import com.android.common.bill.ui.NativeAdStyleType
// 1. 开屏
AdShowExt.showAppOpenAd(
activity = activity,
onLoaded = { loaded -> /* 可更新加载进度 */ },
countdown = null,
showLoading = false,
competeWithInterstitial = false,
position = "APP_OPEN",
)
// 2. 插页
AdShowExt.showInterstitialAd(
activity = activity,
ignoreFullNative = true, // 本次不改道全屏原生
position = "INTERSTITIAL",
)
// 3. 激励
AdShowExt.showRewardedAd(
activity = activity,
onRewardEarned = { /* 在这里处理奖励,并自行保证幂等 */ },
competeWithInterstitial = false, // 本次只展示激励
position = "REWARDED",
)
// 4. 普通原生:需先注册对应 Renderer
val filled = AdShowExt.showNativeAdInContainer(
context = activity,
container = container,
styleType = NativeAdStyleType.STANDARD,
position = "NATIVE",
)
// 5. 全屏原生:需先注册对应全屏 Renderer
AdShowExt.showFullScreenNativeAdInContainer(
activity = activity,
showInterstitial = false, // 本次不衔接插页
position = "FULL_NATIVE",
)
// 6. Banner
AdShowExt.showBannerAd(
activity = activity,
container = container,
position = "BANNER",
)position 是宿主自定义的位置标识,不是平台广告位 ID。普通原生返回 Boolean,其他入口返回 AdResult;激励是否获得奖励以 onRewardEarned 为准。
import com.android.common.bill.ads.AdResult
val result = AdShowExt.showInterstitialAd(
activity, ignoreFullNative = true, position = "INTERSTITIAL"
)
when (result) {
is AdResult.Success -> { /* 展示流程成功结束 */ }
is AdResult.Failure -> {
val code = result.error.code
val message = result.error.message
// 记录失败并继续宿主流程;无需无间隔重试。
}
}开屏 / 激励省略 competeWithInterstitial 时会跟随 SDK 配置,可能与插页竞价;以上示例显式关闭。插页默认允许按策略改道全屏原生,以上示例用 ignoreFullNative=true 固定为插页。
REFERENCE 07广告配置 JSON 参考
以下均为 Firebase Remote Config 的字符串参数:参数名使用标题中的 Key,值粘贴对应 JSON 对象文本。字段大小写保持一致;示例额度仅用于说明,可按接入需要调整。
adRuntimeIdConfigJson · 平台 ID / Key
覆盖初始化注入的广告源配置;非空字段生效,省略或空字符串保留已有配置。先应用缓存再读取在线值;BillConfig.skipRuntimeAdIdConfig=true 时跳过动态 ID。
展开完整广告源配置参考
{
"googleMobileAds": {
"applicationId": "<GOOGLEMOBILEADS_APPLICATION_ID>"
},
"admob": {
"splashId": "<ADMOB_SPLASH_ID>",
"bannerId": "<ADMOB_BANNER_ID>",
"interstitialId": "<ADMOB_INTERSTITIAL_ID>",
"nativeId": "<ADMOB_NATIVE_ID>",
"fullNativeId": "<ADMOB_FULL_NATIVE_ID>",
"rewardedId": "<ADMOB_REWARDED_ID>"
},
"gam": {
"splashId": "<GAM_SPLASH_ID>",
"bannerId": "<GAM_BANNER_ID>",
"interstitialId": "<GAM_INTERSTITIAL_ID>",
"nativeId": "<GAM_NATIVE_ID>",
"fullNativeId": "<GAM_FULL_NATIVE_ID>",
"rewardedId": "<GAM_REWARDED_ID>"
},
"pangle": {
"applicationId": "<PANGLE_APPLICATION_ID>",
"splashId": "<PANGLE_SPLASH_ID>",
"bannerId": "<PANGLE_BANNER_ID>",
"interstitialId": "<PANGLE_INTERSTITIAL_ID>",
"nativeId": "<PANGLE_NATIVE_ID>",
"fullNativeId": "<PANGLE_FULL_NATIVE_ID>",
"rewardedId": "<PANGLE_REWARDED_ID>"
},
"topon": {
"applicationId": "<TOPON_APPLICATION_ID>",
"appKey": "<TOPON_APP_KEY>",
"splashId": "<TOPON_SPLASH_ID>",
"bannerId": "<TOPON_BANNER_ID>",
"interstitialId": "<TOPON_INTERSTITIAL_ID>",
"nativeId": "<TOPON_NATIVE_ID>",
"fullNativeId": "<TOPON_FULL_NATIVE_ID>",
"rewardedId": "<TOPON_REWARDED_ID>"
}
}adConfigNaturalJson / adConfigPaidJson · 渠道广告策略
两份参数结构相同,分别用于 natural / paid 用户,各自存一个完整配置对象,不套 natural / paid 外层。示例均开启四个平台,禁用 Banner;未接入的平台请显式改成 false。
| 字段 | 配置参考与含义 |
|---|---|
app_open / interstitial / native / rewarded / banner | 开屏 / 插页 / 原生 / 激励 / Banner。全屏原生也读取 native 节点的配置,但按自己的广告类型独立计数。 |
bidding_platforms | admob、gam、pangle、topon:布尔值。关闭类型可将该类型四个平台都设 false。省略平台字段会使用代码默认 true。 |
total_frequency_limits | 跨平台的本广告类型每日展示 / 点击总上限;不检查 min_interval。 |
bidding_frequency_limits | 各平台独立的 max_daily_show、max_daily_click、min_interval;min_interval 单位为秒。 |
max_daily_show / max_daily_click | 达到上限即阻断;0 表示没有额度,不表示无限制。代码字段缺省值为 20 / 10。 |
min_interval | 平台两次展示的最小间隔,0 表示不限制间隔;代码缺省为 0。 |
compete_with_interstitial | 只用于 app_open / rewarded;省略默认 true。show 方法显式传 competeWithInterstitial 时以调用参数为准。 |
ad_strategies.fullscreen_native_after_interstitial | 按插页累计次数判断是否改道全屏原生,需已有对应缓存且调用允许;0 关闭。 |
ad_strategies.app_open_after_interstitial | 插页累计展示次数达到正整数 N 的倍数后,尝试衔接开屏;0 关闭。大于 0 时优先此策略,不走改道全屏原生。 |
下面显式把两项 ad_strategies 设为 0,以保持基础展示流程。代码数据类省略字段时的默认值是 3 / 2,不应通过删字段来关闭策略。线上策略更新会替换该渠道配置;不要把局部 JSON 当成补丁合并。
adConfigNaturalJson · 完整示例(每日总展示 20、单平台 10)
{
"app_open": {
"compete_with_interstitial": false,
"bidding_platforms": {"admob": true, "gam": true, "pangle": true, "topon": true},
"total_frequency_limits": {"max_daily_show": 20, "max_daily_click": 5},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60},
"gam": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60},
"pangle": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60},
"topon": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60}
}
},
"interstitial": {
"bidding_platforms": {"admob": true, "gam": true, "pangle": true, "topon": true},
"total_frequency_limits": {"max_daily_show": 20, "max_daily_click": 5},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60},
"gam": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60},
"pangle": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60},
"topon": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60}
}
},
"native": {
"bidding_platforms": {"admob": true, "gam": true, "pangle": true, "topon": true},
"total_frequency_limits": {"max_daily_show": 20, "max_daily_click": 5},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 30},
"gam": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 30},
"pangle": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 30},
"topon": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 30}
}
},
"rewarded": {
"compete_with_interstitial": false,
"bidding_platforms": {"admob": true, "gam": true, "pangle": true, "topon": true},
"total_frequency_limits": {"max_daily_show": 20, "max_daily_click": 5},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60},
"gam": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60},
"pangle": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60},
"topon": {"max_daily_show": 10, "max_daily_click": 3, "min_interval": 60}
}
},
"banner": {
"bidding_platforms": {"admob": false, "gam": false, "pangle": false, "topon": false},
"total_frequency_limits": {"max_daily_show": 0, "max_daily_click": 5},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 0, "max_daily_click": 3, "min_interval": 0},
"gam": {"max_daily_show": 0, "max_daily_click": 3, "min_interval": 0},
"pangle": {"max_daily_show": 0, "max_daily_click": 3, "min_interval": 0},
"topon": {"max_daily_show": 0, "max_daily_click": 3, "min_interval": 0}
}
},
"ad_strategies": {"fullscreen_native_after_interstitial": 0, "app_open_after_interstitial": 0}
}adConfigPaidJson · 完整示例(每日总展示 40、单平台 20)
{
"app_open": {
"compete_with_interstitial": false,
"bidding_platforms": {"admob": true, "gam": true, "pangle": true, "topon": true},
"total_frequency_limits": {"max_daily_show": 40, "max_daily_click": 10},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"gam": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"pangle": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"topon": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30}
}
},
"interstitial": {
"bidding_platforms": {"admob": true, "gam": true, "pangle": true, "topon": true},
"total_frequency_limits": {"max_daily_show": 40, "max_daily_click": 10},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"gam": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"pangle": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"topon": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30}
}
},
"native": {
"bidding_platforms": {"admob": true, "gam": true, "pangle": true, "topon": true},
"total_frequency_limits": {"max_daily_show": 40, "max_daily_click": 10},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"gam": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"pangle": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"topon": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30}
}
},
"rewarded": {
"compete_with_interstitial": false,
"bidding_platforms": {"admob": true, "gam": true, "pangle": true, "topon": true},
"total_frequency_limits": {"max_daily_show": 40, "max_daily_click": 10},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"gam": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"pangle": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30},
"topon": {"max_daily_show": 20, "max_daily_click": 5, "min_interval": 30}
}
},
"banner": {
"bidding_platforms": {"admob": false, "gam": false, "pangle": false, "topon": false},
"total_frequency_limits": {"max_daily_show": 0, "max_daily_click": 10},
"bidding_frequency_limits": {
"admob": {"max_daily_show": 0, "max_daily_click": 5, "min_interval": 0},
"gam": {"max_daily_show": 0, "max_daily_click": 5, "min_interval": 0},
"pangle": {"max_daily_show": 0, "max_daily_click": 5, "min_interval": 0},
"topon": {"max_daily_show": 0, "max_daily_click": 5, "min_interval": 0}
}
},
"ad_strategies": {"fullscreen_native_after_interstitial": 0, "app_open_after_interstitial": 0}
}Admob_Preloading_Config · Google 加载模式
只控制 AdMob / GAM 的三种格式:IV 插页、RV 激励、SP 开屏。*_Preloading_Enable 为 1 时开启 GMA Preloading,0 走普通 Loading。*_Buffer_Size 是该格式的目标缓存数量,使用正整数;源码对非正数回退为 1,实际容量还受底层 SDK 额度约束。
示例:开启 AdMob 插页 / 激励 Preloading,其余保持普通 Loading
{
"Admob_IV_Preloading_Enable": 1,
"Admob_IV_Buffer_Size": 1,
"Admob_RV_Preloading_Enable": 1,
"Admob_RV_Buffer_Size": 1,
"Admob_SP_Preloading_Enable": 0,
"Admob_SP_Buffer_Size": 1,
"GAM_IV_Preloading_Enable": 0,
"GAM_IV_Buffer_Size": 1,
"GAM_RV_Preloading_Enable": 0,
"GAM_RV_Buffer_Size": 1,
"GAM_SP_Preloading_Enable": 0,
"GAM_SP_Buffer_Size": 1
}随包默认是所有 Enable 为 0、Buffer Size 为 1。该配置在平台初始化前读取,并在本进程内固定;调整后重新启动进程验证。关闭此模式不会禁止 PreloadController 提前加载,只是切换 Google 的具体加载方式。
远程参数为空或解析失败时使用本地 assets;读取返回 null 时保留缓存 / 已有本地配置。这里的模式开关与广告平台开关、展示频控分别生效。
补充:宿主广告位开关 ad_slot_switch
宿主主动调用 AdSlotSwitchController.isEnabled(position) 查询;AdShowExt 不自动检查此开关。自然分组名是 organic;未配置、未声明或解析失败默认关闭。
{
"organic": {
"APP_OPEN": true,
"INTERSTITIAL": true
},
"paid": {
"APP_OPEN": true,
"INTERSTITIAL": true
}
}投放目标事件仍可通过 BillConfig.enableAdTargetEvents 显式开启,默认 false。
REFERENCE 08PreloadController · 预加载
四个控制类的示例共用下列类型:
import com.android.common.bill.ads.PreloadController
import com.android.common.bill.ads.frequency.AdFrequencyController
import com.android.common.bill.ads.bidding.AdCacheStatusController
import com.android.common.bill.ads.bidding.AdSourceController
import com.android.common.bill.ads.config.AdType
import com.android.common.bill.ads.config.AdPlatform
// AdType: APP_OPEN / INTERSTITIAL / REWARDED / NATIVE / FULL_SCREEN_NATIVE / BANNER
// AdPlatform: ADMOB / GAM / PANGLE / TOPON包名:com.android.common.bill.ads.PreloadController。以下 24 个函数参数均为 context: Context、返回 Unit,内部异步执行。请在初始化及授权处理后按需调用,返回不代表加载完成。
| 公开函数 | 返回值 / 用途 |
|---|---|
preloadAll(context: Context): Unit | 所有可用平台:普通原生 + 插页。 |
preloadAllFullScreenNative(context: Context): Unit | 所有可用平台:全屏原生。 |
preloadAllAppOpen(context: Context): Unit | 所有可用平台:开屏。 |
preloadAllRewarded(context: Context): Unit | 所有可用平台:激励。 |
单平台入口(每行列出完整函数名)
| 公开函数 | 返回值 / 用途 |
|---|---|
preloadAdmob(context: Context): Unit | AdMob · 普通原生 + 插页 |
preloadAdmobInterstitial(context: Context): Unit | AdMob · 插页 |
preloadAdmobNative(context: Context): Unit | AdMob · 普通原生 |
preloadAdmobFullScreenNative(context: Context): Unit | AdMob · 全屏原生 |
preloadAdmobRewarded(context: Context): Unit | AdMob · 激励 |
preloadGam(context: Context): Unit | GAM · 普通原生 + 插页 |
preloadGamInterstitial(context: Context): Unit | GAM · 插页 |
preloadGamNative(context: Context): Unit | GAM · 普通原生 |
preloadGamFullScreenNative(context: Context): Unit | GAM · 全屏原生 |
preloadGamRewarded(context: Context): Unit | GAM · 激励 |
preloadPangle(context: Context): Unit | Pangle · 普通原生 + 插页 |
preloadPangleInterstitial(context: Context): Unit | Pangle · 插页 |
preloadPangleNative(context: Context): Unit | Pangle · 普通原生 |
preloadPangleFullScreenNative(context: Context): Unit | Pangle · 全屏原生 |
preloadPangleRewarded(context: Context): Unit | Pangle · 激励 |
preloadTopOn(context: Context): Unit | TopOn · 普通原生 + 插页 |
preloadTopOnInterstitial(context: Context): Unit | TopOn · 插页 |
preloadTopOnNative(context: Context): Unit | TopOn · 普通原生 |
preloadTopOnFullScreenNative(context: Context): Unit | TopOn · 全屏原生 |
preloadTopOnRewarded(context: Context): Unit | TopOn · 激励 |
这些入口按平台开关、运行时配置和初始化状态决定是否发起请求。该控制类没有单平台公开开屏函数,也没有 Banner 预加载函数;preloadAll 不包含开屏、激励、全屏原生。固定平台选择不会把 preloadAll 缩减为一个平台。
// 只预加载插页(按接入平台选择)
PreloadController.preloadAdmobInterstitial(application)
PreloadController.preloadTopOnInterstitial(application)
// 如使用激励:
PreloadController.preloadAllRewarded(application)REFERENCE 09AdFrequencyController · 频次查询
包名:com.android.common.bill.ads.frequency.AdFrequencyController。6 个公开函数均同步查询,不增加展示 / 点击计数,不上报竞价排除事件。
| 公开函数 | 返回值 / 用途 |
|---|---|
getPlatformFrequencyStatus(adType: AdType, platform: AdPlatform): AdFrequencyStatus | 查询单平台每日次数、剩余额度和最小间隔;不合并总控。 |
getTotalFrequencyStatus(adType: AdType): AdFrequencyStatus | 查询类型总控:每日展示 / 点击限制,不检查最小间隔。 |
getFrequencyStatus(adType: AdType): AdFrequencySnapshot | 同时返回 totalStatus 与所有平台的 platformStatuses。 |
isPlatformFrequencyAllowed(adType: AdType, platform: AdPlatform): Boolean | 单平台频次是否通过。 |
isTotalFrequencyAllowed(adType: AdType): Boolean | 总频次是否通过。 |
getFrequencyAllowedPlatforms(adType: AdType): List<AdPlatform> | 总控通过后,返回平台频次也通过的列表;总控不通过返回空列表。 |
查询只描述频次,不判断广告源是否启用、初始化是否成功或有无缓存;因此 isAllowed / canShow() 不代表此刻必然能展示。
| 返回对象 | 常用字段 / 方法 |
|---|---|
AdFrequencyStatus | isAllowed / blockReason / blockReasonKey;dailyShowCount / maxDailyShow / remainingShowCount;dailyClickCount / maxDailyClick / remainingClickCount;lastShowIntervalSeconds / minIntervalSeconds / remainingIntervalSeconds。canShow()、canBid() 均返回 isAllowed。 |
AdFrequencySnapshot | totalStatus / platformStatuses / isTotalAllowed / allowedPlatforms。 |
| 阻断原因 | none / config_unavailable / show_limit_exceeded / click_limit_exceeded / interval_not_met。 |
| 时间单位 | 均为秒;lastShowIntervalSeconds 为 -1 表示没有上次展示记录(总控查询也使用 -1)。 |
val snapshot = AdFrequencyController.getFrequencyStatus(AdType.INTERSTITIAL)
val admob = snapshot.platformStatuses[AdPlatform.ADMOB]
val frequencyAllowed = snapshot.isTotalAllowed && admob?.isAllowed == true
val waitSeconds = admob?.remainingIntervalSeconds
val reason = admob?.blockReasonKeyREFERENCE 10AdCacheStatusController · 缓存查询
包名:com.android.common.bill.ads.bidding.AdCacheStatusController。5 个公开入口(包含重载),查询已有缓存,不消费广告或触发加载。
| 公开函数 | 返回值 / 用途 |
|---|---|
hasAvailableCache(adType: AdType): Boolean | 按当前聚合源检查:固定源只查该平台,BIDDING 查所有候选平台。 |
hasAvailableCache(adType: AdType, platform: AdPlatform, adUnitId: String? = null): Boolean | 直接检查指定平台;adUnitId 省略时使用 BillConfig 对应类型的 ID。 |
getAvailableCachePlatforms(adType: AdType): List<AdPlatform> | 当前聚合源下,具有可用缓存的平台列表。 |
getPlatformCacheStatuses(adType: AdType): List<PlatformCacheStatus> | 当前聚合源下各候选平台的状态列表。 |
getPlatformCacheStatus(adType: AdType, platform: AdPlatform, adUnitId: String? = null): PlatformCacheStatus | 指定平台的完整缓存状态,显式传入的 ID 用于缓存查找。 |
PlatformCacheStatus 包含 adType / platform / platformAvailable / hasCache / blockReason;计算属性 hasAvailableCache = platformAvailable && hasCache。platformAvailable 检查平台配置、初始化和平台频控;缓存命中仍不等于通过总控或所有展示前置条件。
blockReason 可能为 platform_unavailable、no_cache,或带详情的频控原因。查询为即时快照,实际展示仍会再次判断。频控达到硬上限时,内部检查可能停止 Google 预加载。
val status = AdCacheStatusController.getPlatformCacheStatus(
AdType.INTERSTITIAL, AdPlatform.ADMOB
)
val ready = AdFrequencyController.isTotalFrequencyAllowed(AdType.INTERSTITIAL) &&
status.hasAvailableCache
val reason = status.blockReasonREFERENCE 11AdSourceController · 固定平台
包名:com.android.common.bill.ads.bidding.AdSourceController。选择会持久化,默认 AdSource.BIDDING;枚举还有 ADMOB / GAM / PANGLE / TOPON。
| 公开函数 | 返回值 / 用途 |
|---|---|
getCurrentSource(): AdSource | 读取当前选择,缺失或非法值回退 BIDDING。 |
setCurrentSource(source: AdSource): Unit | 保存选择;传 BIDDING 恢复竞价。 |
getSourceDisplayName(source: AdSource): String | 取得用于显示的名称。 |
getAllSources(): List<AdSource> | 返回全部 5 个选项,并非当前已初始化 / 可用的平台列表。 |
showAdSourceSelection(context: Context, onSourceChanged: () -> Unit = {}): Unit | 显示选择弹层;用户选择后自动保存并回调。context 使用可承载弹层的 Activity。 |
checkFixedSource(adType: AdType): FixedSourceCheckResult | 检查固定源的平台启用、初始化与平台频控;返回 UseFixedSource(winner) 或 UseBidding。 |
固定源不可用时,checkFixedSource 会返回 UseBidding,允许回退竞价;因此“固定平台”不是严格保证只使用该源。此检查不判断缓存,且频控失败可能上报排除事件;仅查询频次时使用 AdFrequencyController。
AdSourceController.setCurrentSource(AdSourceController.AdSource.TOPON)
val selected = AdSourceController.getCurrentSource()
AdSourceController.showAdSourceSelection(activity) {
val label = AdSourceController.getSourceDisplayName(
AdSourceController.getCurrentSource()
)
}
// 调试结束恢复竞价:
AdSourceController.setCurrentSource(AdSourceController.AdSource.BIDDING)