ReMaxDeveloper Docs
DOCUMENTATION / GET STARTED

广告库接入 SOP

添加依赖 → 配置日志与渠道 → 初始化广告源 → 注册回调 → 授权与预加载 → 展示广告。

Core 1.0.15Bill 1.0.51_preloading.3外部接入用法

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.attachBaseContextsuper 调用后设置,早于广告初始化。

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 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_platformsadmob、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): UnitAdMob · 普通原生 + 插页
preloadAdmobInterstitial(context: Context): UnitAdMob · 插页
preloadAdmobNative(context: Context): UnitAdMob · 普通原生
preloadAdmobFullScreenNative(context: Context): UnitAdMob · 全屏原生
preloadAdmobRewarded(context: Context): UnitAdMob · 激励
preloadGam(context: Context): UnitGAM · 普通原生 + 插页
preloadGamInterstitial(context: Context): UnitGAM · 插页
preloadGamNative(context: Context): UnitGAM · 普通原生
preloadGamFullScreenNative(context: Context): UnitGAM · 全屏原生
preloadGamRewarded(context: Context): UnitGAM · 激励
preloadPangle(context: Context): UnitPangle · 普通原生 + 插页
preloadPangleInterstitial(context: Context): UnitPangle · 插页
preloadPangleNative(context: Context): UnitPangle · 普通原生
preloadPangleFullScreenNative(context: Context): UnitPangle · 全屏原生
preloadPangleRewarded(context: Context): UnitPangle · 激励
preloadTopOn(context: Context): UnitTopOn · 普通原生 + 插页
preloadTopOnInterstitial(context: Context): UnitTopOn · 插页
preloadTopOnNative(context: Context): UnitTopOn · 普通原生
preloadTopOnFullScreenNative(context: Context): UnitTopOn · 全屏原生
preloadTopOnRewarded(context: Context): UnitTopOn · 激励

这些入口按平台开关、运行时配置和初始化状态决定是否发起请求。该控制类没有单平台公开开屏函数,也没有 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() 不代表此刻必然能展示。

返回对象常用字段 / 方法
AdFrequencyStatusisAllowed / blockReason / blockReasonKeydailyShowCount / maxDailyShow / remainingShowCountdailyClickCount / maxDailyClick / remainingClickCountlastShowIntervalSeconds / minIntervalSeconds / remainingIntervalSecondscanShow()canBid() 均返回 isAllowed。
AdFrequencySnapshottotalStatus / 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?.blockReasonKey

REFERENCE 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.blockReason

REFERENCE 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)