App 广告 SDK 深挖 那篇讲清了”广告 SDK 是什么、在端上的生命周期、瀑布 vs In-App Bidding 的机制”。这篇换一个视角——开发者视角,把四个最常被问、却很少被一次讲透的问题落到地上:
- 一个 App 到底怎么把广告 SDK 接进来?(依赖、初始化、广告位、adapter、同意、测试)
- SDK 内部是怎么实现的?(它在你进程里到底跑着哪几层)
- Mediation 怎么对这些 SDK 做决策?(瀑布、In-App Bidding、混合统一竞价、自动调价)
- 到底是哪些公司在做这些 SDK?(聚合平台 vs 广告源,厂商全景)
范围说明:本篇是 App 广告 SDK 深挖 的实战 / 实现侧续篇。概念与机制(生命周期、瀑布 vs bidding 的”为什么”)那篇已讲,这里聚焦”怎么接、怎么实现、谁在做”,重叠处只给指针。
TL;DR
- 接入是一条固定流水线:加依赖(聚合 SDK + 各广告源 adapter)→ 配权限与合规 → App 启动时异步 init → 用后台配的**广告位 ID(ad unit)**请求 → 监听回调 → 择时
show。其余都是这条线的细节。 - SDK 内部 ≈ 七层:对外 API → 异步状态机 → 配置中心(远程拉取广告位↔广告源映射)→ Mediation 决策 → adapter 适配层 → 网络 / 缓存 → 渲染 + 上报。难点全在”它跑在宿主进程里”。
- Mediation 决策 = 把所有候选拉到同一把尺子上比 eCPM:传统瀑布按预设 eCPM 串行问、命中即停;In-App Bidding 让支持竞价的源并行实时出价;现实是混合统一竞价——bidding 实时价和瀑布各档预设价一起排序、价高者得。
- 厂商分两类:聚合平台(Google AdMob、AppLovin MAX、Unity LevelPlay、国内 TopOn / GroMore)负责”决策”;广告源 / 网络(Meta、Mintegral、Pangle、Vungle/Liftoff、InMobi、Unity Ads…)以 adapter 形式被聚合平台挂载调度。
- 接入的真正难度不在调 API:而在 init 时序、预加载、多 adapter 冲突、超时收口、合规同意、奖励防作弊——这些都是端上工程题(详见 App 广告 SDK 深挖 §5)。
Table of contents
Open Table of contents
1. APP 怎么接入广告 SDK:一条固定流水线
不管接的是 AdMob、MAX 还是 LevelPlay,接入步骤几乎是同一条流水线。下面以”聚合 SDK + 几家广告源 adapter”的典型组合走一遍。
1.1 第一步:加依赖(聚合 SDK + adapter)
接入从来不是”加一个包”,而是一个聚合 SDK + N 个广告源 adapter。聚合 SDK 提供统一接口与决策,每个 adapter 把统一接口翻译成某家广告源的私有协议。
Android(Gradle):
dependencies {
// 聚合 SDK(这里以 AppLovin MAX 为例)
implementation 'com.applovin:applovin-sdk:13.0.0'
// 广告源 adapter:每接一家就多一个
implementation 'com.applovin.mediation:google-adapter:24.0.0.0'
implementation 'com.applovin.mediation:facebook-adapter:6.18.0.0'
implementation 'com.applovin.mediation:mintegral-adapter:16.9.51.0'
implementation 'com.applovin.mediation:unityads-adapter:4.12.5.0'
}
iOS(CocoaPods):
pod 'AppLovinSDK'
pod 'AppLovinMediationGoogleAdapter'
pod 'AppLovinMediationFacebookAdapter'
pod 'AppLovinMediationMintegralAdapter'
pod 'AppLovinMediationUnityAdsAdapter'
每多一家 adapter,就多一截二进制(包体)、一份依赖、一组 ProGuard / SO 库——这是 §1 末尾”多 SDK 冲突”的根源,也是”该接几家”要权衡的第一笔账。
1.2 第二步:权限与合规前置
- Android:
AD_ID权限(Android 13+ 访问 GAID 必需)、网络权限;广告源 adapter 常各带一串<meta-data>/queries声明,要合并。 - iOS:
Info.plist里的SKAdNetworkItems(每家广告源一个SKAdNetworkIdentifier,归因用)、NSUserTrackingUsageDescription(ATT 弹窗文案)。 - 合规同意:进任何广告请求之前,得先有 TCF / ATT / 各地法规的同意状态。聚合 SDK 一般提供 CMP 接入点或
setHasUserConsent之类的 API——同意拿不到,就只能跑无个性化广告或不跑。
1.3 第三步:App 启动时异步初始化
init 是整条链路里最容易踩坑的一步:它异步、有耗时、且没就绪就请求广告会失败。正确姿势是”init 完成回调里再请求 / 或请求排队”。
// Android / Kotlin —— 启动时初始化,回调里再请求
AppLovinSdk.getInstance(this).mediationProvider = "max"
AppLovinSdk.initializeSdk(this) { config ->
// 各 adapter 已就绪,这里再安全地预加载首个广告
preloadInterstitial()
}
init 在拉远程配置 + 初始化每个 adapter,不能阻塞冷启主线程。开屏 / 冷启场景要给一个硬超时(业内常设 ~3s),到点就放行进 App,绝不能白屏等 SDK(详见 App 广告 SDK 深挖 §5)。
1.4 第四步:用广告位 ID 请求 + 监听回调
广告位(ad unit ID)是你在聚合平台后台建的一个逻辑位,背后挂着”接哪几家广告源、各家什么参数、走瀑布还是 bidding”——这些都在服务端配置,端上只认一个 ID。这是关键解耦:调整广告源不用发版。
val interstitial = MaxInterstitialAd("YOUR_AD_UNIT_ID", this)
interstitial.setListener(object : MaxAdListener {
override fun onAdLoaded(ad: MaxAd) { /* 就绪,可择时 show */ }
override fun onAdLoadFailed(unitId: String, error: MaxError) { /* 退避重试 */ }
override fun onAdDisplayed(ad: MaxAd) {}
override fun onAdHidden(ad: MaxAd) { interstitial.loadAd() } // 关闭后预加载下一个
override fun onAdClicked(ad: MaxAd) {}
override fun onAdDisplayFailed(ad: MaxAd, error: MaxError) {}
})
interstitial.loadAd()
SDK 对外就是一组异步回调 + 状态机:loadAd() 与 showAd() 解耦——先在后台备好(预加载),等到合适时机(关卡结束、页面切换)再 show,把网络延迟挪出用户等待路径。
1.5 第五步:渲染、上报、关闭 / 奖励
show() 之后 SDK 接管渲染(banner 内嵌、插屏 / 激励全屏)、上报 impression / click(计费对账依据)、回调关闭;激励视频额外回调奖励发放——奖励必须以服务端回传(S2S)为准,端上回调只做 UI(防作弊,见 App 广告 SDK 深挖 §6)。
1.6 第六步:测试与上线前自检
- 测试广告 / test device:每家广告源都有测试模式,上线前必须用,否则真量误点会被风控判作弊。
- Mediation Debugger:AdMob / MAX 都带一个端上调试面板,列出”哪些 adapter 集成成功、版本、是否缺配置”——接多家时这是排”为什么这家不出广告”的第一站。
- 填充与时延体检:盯填充率、各 adapter 的 latency、init 耗时;弱网下尤其要看超时收口是否正常。
2. SDK 内部是怎么实现的:你进程里跑着的七层
把”一个广告 SDK”从对外 API 一路拆到端上执行,大体是这七层。理解这张分层图,是排查”广告不出 / 不计费 / 崩溃归谁”的前提。
广告 SDK 的内部七层:对外 API → 状态机 → 配置中心 → Mediation 决策 → adapter 适配 → 网络 / 缓存 → 渲染 / 上报。整套都寄生在宿主 App 进程里。
逐层拆:
- 对外 API 层:开发者唯一接触的层——
load/show/ 一组回调。设计目标是”朴素到一句话能说清”,把全部复杂度藏在下面六层。 - 异步状态机:
IDLE → LOADING → READY → SHOWING → CLOSED,外加FAILED分支。load 与 show 解耦、预加载与展示解耦就由这台状态机维护;“show 在 Activity 已销毁后调用”这类崩溃,本质是状态机没和宿主生命周期对齐。 - 配置中心(remote config):App 启动时从服务端拉一份”广告位 → 广告源映射 / 瀑布顺序 / bidding 开关 / 超时预算 / A/B 分组”,端上缓存。这是”调整广告源不用发版”的工程基础——后台改配置,端上下次刷新即生效。
- Mediation 决策层:按配置把候选广告源组织成瀑布(串行)或 In-App Bidding(并行询价),按 eCPM 排序选胜者,带全局超时收口。这一层是第 3 节的主角。
- adapter 适配层:每家广告源一个 adapter,把聚合 SDK 的统一接口翻译成该网络的私有 SDK 调用。故障隔离就发生在这层——调用边界
try/catch、超时即弃权、崩溃打面包屑归因(详见 App 广告 SDK 深挖 §5 深挖二处)。 - 网络与缓存层:询价 / 取素材的 HTTP、素材预下载与缓存(含 TTL)、重试退避。“预加载素材过期导致计费异常”就出在这层的缓存治理。
- 渲染与上报层:把素材渲染到屏幕(涉及 MRAID / VAST 协议)、上报 impression / click、激励视频走 S2S 奖励回传。
一句话:广告 SDK 的实现难度不在任何单层,而在”七层全跑在别人进程里”——它的内存、线程、崩溃、包体都和宿主 App 共享。这把它从”前端活儿”变成了严肃的客户端组件工程(App 广告 SDK 深挖 §5 专讲这块)。
深挖:配置中心为什么是 SDK 实现的”隐藏主角”
接入时你只填一个 ad unit ID,但这个 ID 背后的”接哪几家、什么顺序、走不走 bidding、超时多少、流量怎么分 A/B”全在服务端。配置中心让这套与端上版本解耦:
- 热更广告源:今天加一家 Mintegral、明天关掉一家表现差的,后台改完端上下次拉配置即生效,不用发版、不用等用户升级。
- A/B 与灰度:同一个广告位可以把 5% 流量切到”新瀑布顺序”或”开 bidding”,对比 eCPM 再全量。
- 风险熔断:某 adapter 线上崩溃率飙升,后台直接在配置里禁用它,端上熔断生效(呼应 §2 第 5 层的故障隔离)。
这也是为什么”广告 SDK”从来不是一个纯客户端库,而是端上 SDK + 服务端配置 / 决策的合体。
3. Mediation 怎么对这些 SDK 做决策
接进来好几家广告源(AdMob、Meta、Mintegral、Unity Ads…),“这次该问谁、谁的价高”就是 Mediation(聚合层) 的活。它的本质只有一句:把所有候选拉到同一把尺子(eCPM)上比,价高者得。难点在于这些候选有的报”实时价”、有的只有”预设价”。
Mediation 的混合统一竞价:瀑布的预设 eCPM 与 bidding 的实时价被拉进同一个有序列表,按 eCPM 排序、从高到低尝试填充。这就是移动端的 Header Bidding。
3.1 瀑布(Waterfall):按预设 eCPM 串行问
最老的机制:聚合层按后台配置 / 历史 eCPM 给广告源排序,从高到低串行问,“A 有没有?没有问 B……”命中即停。两个老毛病:价是『估』的不是实时的(排在后面的源这次也许愿出更高价,却没机会,钱漏了);串行 = 延迟高。
3.2 In-App Bidding:并行实时竞价
把”串行猜价”改成”并行真实竞价”:聚合层同时向所有支持竞价的源询价,各自回一个真实 bid,价高者得。这正是 Header Bidding 在 App 里的对应物。代价是端上要并行管理多路网络请求与全局超时预算——到点就用已收到的最高价收口,忽略还没回来的(这套超时收口的工程细节见 App 广告 SDK 深挖 §5 深挖一处)。
3.3 混合统一竞价:现实里两者并存
生产里 bidding 与瀑布几乎总是并存:bidding 拿到的实时价,和瀑布各档的预设 eCPM 一起丢进一个有序列表,按 eCPM 排序、从高到低尝试填充。用上图的数字:
| 机制 | 这次发生了什么 | 媒体到手 |
|---|---|---|
| 纯瀑布 | 配置最高的 A($10)先问 → A 这次无填充 → 问 B($6)→ B 填充,命中即停 | $6 |
| 混合统一竞价 | bidding 实时价(X $8 / Y $11 / Z $5)与瀑布预设价($10/$6/$3)同排序 → 最高 Y $11 先填 | $11 |
差距来自:纯瀑布的静态排序根本不知道”Y 这次实时值 $11”,命中 B 的 $6 档就停了;统一竞价让真实价同台,才把这块钱捞回来。这和 媒体 Ad Server 的 dynamic allocation / 统一竞价 是同一道题的端上版本。
3.4 决策之外:自动调价、实例与 A/B
聚合平台的”决策”不止单次竞价,还有几个持续优化的旋钮:
- Auto eCPM / 自动调价:对只报预设价的瀑布源,平台用历史表现自动估算并动态调整它在瀑布里的档位与排序,减少人工配价。
- 多实例(instances):同一家广告源可以在一个广告位里挂多个不同地板价的实例(如 Meta $10 / $5 / $1 三档),让它在瀑布里占多个位置、提高竞争力。
- A/B 测试:平台层直接支持把流量切成”开 bidding vs 纯瀑布""排序 A vs 排序 B”对比真实 eCPM,再全量——靠 §2 的配置中心落地。
一句话:Mediation 决策 = 候选归一到 eCPM 排序 + 超时收口 + 持续自动优化。In-App Bidding 决定”实时竞价里谁最高”,统一竞价决定”实时价 vs 瀑布预设价,整场谁最高”。
4. 哪些公司在做这些 SDK
市面上的广告 SDK 分两类角色,一个 App 通常同时集成一个聚合平台 + 多家广告源 adapter。
4.1 聚合平台(负责”决策”)
| 平台 | 母公司 | 特点 |
|---|---|---|
| AdMob / GAM | 装机量最大、广告源最广;与 Google 需求(AdX)深度打通 | |
| AppLovin MAX | AppLovin | 游戏变现霸主,In-App Bidding 接入广度领先 |
| Unity LevelPlay(原 ironSource) | Unity | 游戏引擎自带,与 Unity Ads 一体;ironSource 合并后整合 |
| Digital Turbine FairBid(原 Fyber) | Digital Turbine | 老牌聚合,欧洲背景 |
| TopOn | 江平智能 | 国内主流聚合,聚合海内外广告源,开发者侧透明度高 |
| GroMore | 字节跳动(穿山甲) | 国内聚合,与穿山甲 / Pangle 需求打通 |
4.2 广告源 / 网络(以 adapter 形式被挂载)
| 广告源 | 母公司 | 备注 |
|---|---|---|
| Google Ads / AdMob 需求 | 既是聚合平台也是最大需求源 | |
| Meta Audience Network | Meta | 社交流量需求,强 bidding 支持 |
| Mintegral | 汇量科技(Mobvista) | 国内出海主力广告源 |
| Pangle / 穿山甲 | 字节跳动 | 抖音 / TikTok 系流量,出海 + 国内 |
| Unity Ads | Unity | 游戏内激励 / 插屏强势 |
| Liftoff(含 Vungle) | Liftoff | 视频 / 激励见长(Vungle 已并入 Liftoff) |
| InMobi | InMobi | 老牌移动广告网络,亚洲背景 |
| Chartboost | Zynga / Take-Two | 游戏起家的网络 + 轻量聚合 |
| Moloco / Bigo / Kuaishou 等 | 各自 | 新兴或区域性 ML 驱动 / 短视频系需求 |
角色会重叠:Google、AppLovin、Unity 既是聚合平台、又是广告源——它们既做”决策的尺子”,又往这把尺子上放自己的需求。这正是 程序化广告生态全景 里”一家公司戴多顶帽子”在移动端的翻版,也是为什么聚合平台的中立性时常被质疑(裁判兼运动员,参见 last look 与拍卖透明度)。
5. 接入实战:几个绕不开的坑
- init 没完成就请求:广告必失败。必须在 init 回调里、或用请求排队兜底。
- 没预加载就
show:用户对着转圈等素材下载。插屏 / 激励一定提前loadAd()。 show在页面已销毁后触发:异步回调回来时 Activity 没了 → 崩溃。要校验宿主生命周期(呼应 §2 状态机层)。- 多 adapter 依赖 / 权限 / SO 库冲突:升级一家把另一家顶崩。要对齐依赖版本,并保证一家 adapter 崩溃不带崩聚合层(故障隔离)。
- 某家 adapter 拖慢整场:没有全局超时,一家慢源拖垮整条链路填充率。bidding 必须有超时收口。
- 奖励只信端上回调:会被 hook / 重放刷量。奖励发放以 S2S 服务端回传 为准。
- SKAdNetwork ID / 同意没配齐:iOS 漏配
SKAdNetworkItems直接影响归因;同意拿不到只能跑无个性化或不跑。
更系统的端上工程取舍(内存 / OOM / ANR / 故障隔离 / 超时收口)见 App 广告 SDK 深挖 §5–§6。
6. 常见误解 ↔ 正解
| 常见误解 | 正解 |
|---|---|
| 接广告 SDK 就是”加个包、调个 load” | 是”聚合 SDK + N 个 adapter + 服务端配置 + 异步状态机”的合体 |
| 调整广告源要发版 | 广告位映射在服务端配置中心,热更即生效,不用发版 |
| Mediation 在”竞价” | 瀑布只是按预设 eCPM 串行问;真正实时竞价是 In-App Bidding |
| bidding 和瀑布二选一 | 现实是混合统一竞价,实时价与预设价同排序 |
| 聚合平台是中立裁判 | Google / AppLovin / Unity 既当裁判又当运动员(自带需求) |
| 多接几家广告源只会涨收益 | 也会涨包体、内存、冲突与崩溃风险,要权衡 |
| 激励奖励看端上回调就行 | 必须以 S2S 服务端回传为准,防作弊 |
7. 速查表
- 接入流水线:加依赖(聚合 + adapter)→ 权限 / 合规 → 异步 init → 用 ad unit ID 请求 → 回调 → 择时 show → 上报 / 奖励。
- SDK 七层:API → 状态机 → 配置中心 → Mediation 决策 → adapter → 网络 / 缓存 → 渲染 / 上报;全在宿主进程里。
- 配置中心是”不发版换广告源 / A/B / 熔断”的工程基础。
- Mediation 决策:候选归一到 eCPM 排序 + 超时收口 + 自动调价;瀑布(预设、串行)+ bidding(实时、并行)= 混合统一竞价。
- 厂商两类:聚合平台(AdMob / MAX / LevelPlay / TopOn / GroMore)负责决策;广告源(Meta / Mintegral / Pangle / Unity Ads / Liftoff…)以 adapter 被挂载;三巨头两类都做。
- 钱相关信号别只信端上:奖励走 S2S,曝光 / 点击配服务端校验。
记成一句话:接广告 SDK = 把一个”端上状态机 + 服务端决策中心 + 一堆第三方 adapter”塞进你的进程里;接入是流水线,难度在端上工程,决策在 eCPM 排序,厂商分聚合与广告源两类。
延伸阅读
先看同系列里和本篇相邻的几篇:
- App 广告 SDK 深挖:本篇的概念 / 机制母篇——生命周期、瀑布 vs bidding 的”为什么”、端上工程内核。
- 程序化广告生态全景:SDK 在卖方侧端上的位置,以及”一家公司戴多顶帽子”。
- Header Bidding:Prebid.js vs Prebid Server:In-App Bidding 的网页同源物,超时预算同理。
- 媒体 Ad Server 深挖:统一竞价 / dynamic allocation 与 Mediation 决策同源。
- last look 与拍卖透明度:聚合平台”裁判兼运动员”的中立性问题。
- IAB TCF Explained:SDK 端上同意管理与 ATT / 合规的协议基础。
再是规范与一手资料:
- Google AdMob. Mediation overview:瀑布 + bidding 混合聚合、adapter 机制的官方实现参考。
- AppLovin. MAX Integration:主流聚合平台的接入文档(依赖 / init / 广告位 / 回调)。
- Unity LevelPlay(原 ironSource). Developer docs:另一套主流聚合 / bidding 实现。
- IAB Tech Lab. MRAID / OMID:素材渲染与曝光测量的端上协议。
- Apple Developer. SKAdNetwork / ATT:iOS 归因协议与追踪透明度,§1.2 合规前置的协议底座。
附录:术语表
- 聚合 SDK / 聚合平台(Mediation platform):提供统一接口与决策、挂载多家广告源的客户端 SDK(AdMob / MAX / LevelPlay / TopOn / GroMore)。
- adapter(适配器):把聚合 SDK 的统一接口翻译成某家广告源私有协议的适配层;接 N 家就有 N 个 adapter。
- 广告源 / Ad Network:提供需求(广告 + 出价)的一方(Meta / Mintegral / Pangle / Unity Ads / Liftoff…)。
- ad unit ID(广告位 ID):端上请求广告用的逻辑标识;背后的广告源映射 / 顺序 / bidding 开关在服务端配置。
- 配置中心 / remote config:App 启动时拉取的广告位↔广告源映射与策略;让”换广告源不发版”成为可能。
- Waterfall(瀑布):按预设 / 历史 eCPM 排序、串行询问、命中即停的旧机制。
- In-App Bidding:让支持竞价的广告源并行实时出价的机制,Header Bidding 的 App 对应物。
- 混合统一竞价:把 bidding 实时价与瀑布预设价拉到同一把 eCPM 尺子上排序、价高者得。
- eCPM:每千次曝光的等效收入,聚合层比价的核心指标。
- instance(实例):同一广告源在一个广告位里挂的多个不同地板价配置,用来占多个瀑布档位。
- 超时收口(timeout budget):并行询价时到点即用已收到的最高价决胜、忽略未返回者的机制。
- 故障隔离(fault isolation):用调用边界 / 超时 / 线程边界 / 崩溃归因把第三方 adapter 关进”笼子”,防一家崩溃带崩聚合层 / 宿主 App。
- S2S 服务端回传:广告平台从服务器直接通知 App 服务器”本次观看 / 转化有效”,激励奖励以它为准防作弊。
- SKAdNetwork / ATT:Apple 的隐私归因协议 / 追踪透明度框架;接入时需在
Info.plist配齐各广告源 ID 与同意文案。 - CMP:同意管理平台,采集并传递 TCF / ATT 同意状态给 SDK。
- Mediation Debugger:聚合平台自带的端上调试面板,检查各 adapter 集成状态与配置。