做 Android 变现的开发者,绕不开 AdMob。但你要是真把 AdMob 当成一个纯广告 SDK 去接入,那可能就错过了它最有价值的部分——聚合。所谓聚合变现体系,简单说就是你在 AdMob 后台创建一个中介组,组里同时挂着好几个广告源,让它们在同一个广告位上竞争,谁出价高、谁的填充率稳,广告就归谁。这就不单单是“接入广告”了,而是一整套流量调度、数据监控、收益优化的工作。
这篇文章我想把这个体系掰开揉碎讲一遍,从聚合思路到后台配置,再到 Android 端代码集成、数据报表怎么看、常见问题怎么排,全程按照我在真实项目里的操作经验来写。不管你是在做工具类 App、游戏,还是内容类应用,只要是想用 AdMob 聚合把广告收入提上去,这份内容应该能帮你少踩掉大半的坑。
1. 内容整体设计与思路拆解
1.1 为什么一定要做聚合,而不是只接一个广告源
很多新手做广告变现,第一反应是“接个 AdMob 就行了,官方文档全,后台报表也全”。这句话在 app 刚上线、流量极小的阶段没什么问题,但一旦你开始追求收入增长,单广告源的短板就会非常明显。
先说填充率。AdMob 在欧美地区的填充率表现确实好,但你的用户分布在印度、东南亚、拉美这类地区时,真实填充率和有效 eCPM 会掉得很厉害。单一广告源意味着你在这些地区可能大量请求拿不到任何可展示广告,页面下方空着一块白色区域,既难看又不挣钱。
再说 eCPM 波动。广告主预算不是恒定的,同一个广告位昨天的 eCPM 可能是 3 美元,今天可能掉到 1.2 美元。如果你只有一条广告源,等于把你所有的收入押在一家广告主的出价上,完全没有回旋余地。聚合的逻辑就是在这个广告位上引入多个广告源参与竞争,让市场定价决定谁能展示,这比你自己拍脑袋定优先级要靠谱得多。
还有一个很现实的问题:依赖单一广告网络是有风险的。后台政策调整、账号波动、SDK 异常,任何一个环节出问题都可能让你的广告收入直接归零。接入聚合之后,即使主力广告源出了状况,其他广告源会自动顶上,保证了基础收入不断流。
1.2 瀑布流、实时竞价、中介组这几个概念到底指什么
聊 AdMob 聚合,你一定会碰见几个关键词:中介组(Mediation Group)、瀑布流(Waterfall)、实时竞价(Bidding)。这三个概念是整个聚合体系的骨架,我尽量用大白话解释清楚。
先理解“广告位”和“广告源”的关系。你的 App 里有一个原生位置用来展示广告,这是广告位;给它提供广告内容的渠道叫广告源,可以是 AdMob、Meta、Mintegral、Unity 等等。中介组就是一个容器,你把多个广告源放进同一个容器里,然后往广告位上挂这个容器。
瀑布流是传统的聚合调度方式。逻辑很简单:广告位里的广告源按 eCPM 预估或历史表现排成从上到下的列表,请求广告时先从顶部第一个广告源开始,没填充就顺延到第二个,依此类推。它的问题在于排序靠经验和历史数据,而历史数据永远滞后于实时市场行情。
实时竞价(bidding)是广告源报价机制的一次升级。广告位发出请求时,加入竞价池的各个广告源同时出价,出价最高者得展示机会。这比瀑布流公平,eCPM 也能给你最优解,不会出现某家广告源明明愿意出高价,却在瀑布流里排在下层拿不到展示的情况。目前 AdMob 聚合里自家 banner、插屏、激励广告都支持 bidding,Meta、Unity、AppLovin 等主流广告源也都接入了。
1.3 AdMob 聚合和第三方聚合平台,我为什么锁定了 AdMob
市面上你不光可以在 AdMob 里做聚合,还可以用 TopOn、MAX、GroMore 这类独立聚合平台。它们做的事情目的一样:帮你管理广告源、调度流量、分析数据。区别在于广告交易发生的“场子”是哪一方。
我用 AdMob 聚合最核心的原因,是它的实时竞价生态最成熟,接入成本相对可控。你在 AdMob 后台做竞价接入时,很多广告源的 adapter 官方都有现成文档,SDK 版本更新也快,不像有些聚合平台需要自己维护一堆自定义 adapter。而且 AdMob 后台的报表天然统一,不必再单独写一套逻辑去汇总各广告源数据。
当然,TopOn 这类平台也有自己的优势,比如自定义瀑布流维度更细、支持服务端回调、定价策略更灵活。但如果你的主变现平台是 Google Play,用户基座也是全球分发,那 AdMob 聚合是启动成本最低、生态最完整的一条路。先把 AdMob 聚合跑顺,再考虑要不要多平台并行,这是我推荐的做法。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 后台配置流程
2.1 广告位基础配置:别小看这些“前置步骤”
一直觉得 AdMob 后台的引导做得已经足够友好了,但很多人还是会在一开始就遗漏一些细节。这里我按自己的配置顺序梳理一遍,每一步都顺手标出容易踩坑的地方。
第一步是注册 AdMob 账号,然后在“应用”页面里添加 App。如果你是 Google Play 上架的 App,直接关联商店链接,后台会自动读取包名;如果没有上架,也能手动填写应用名称和平台,先拿到一个 AdMob App ID 再说。
第二步是创建广告单元。AdMob 支持的广告格式有横幅(Banner)、插屏(Interstitial)、激励视频(Rewarded)、原生(Native)以及开屏(App Open)。创建广告单元时,后台会生成一个广告单元 ID,类似 ca-app-pub-942544/1234567890 这种格式。后面代码里要用的就是这个 ID,建议你在工程里建一个常量类统一管理,不要直接散落在各个 Activity 里,不然后期改 ID 的时候会很痛苦。
第三步是把 App ID 填进项目的 AndroidManifest.xml。这一步特别容易漏,漏掉之后会导致 SDK 初始化直接崩溃,报错还是 The Google Mobile Ads SDK was initialized incorrectly。我第一次接的时候就被这个错卡了半小时。正确的配置是在 manifest 的 <application> 里加一行 meta-data。
第四步是设置测试设备。用测试设备来加载广告,可以避免误点击真实广告被平台判定为无效流量。AdMob 后台提供了测试设备 ID 的添加入口,你也可以在接入时用 AdRequest 的测试模式来验证,具体代码下面会说。
2.2 创建中介组,接入你自己的第一个广告源
中介组的入口在 AdMob 后台的“中介”菜单里。点击“创建中介组”,接下来需要选择三样东西:广告格式、平台(Android/iOS)、目标广告单元(就是刚才创建的广告位 ID)。选好之后,你会进入广告源配置页面。
AdMob 聚合里有两个方式来添加广告源:实时竞价方式(Bidding)和传统的瀑布流方式(Waterfall)。对于已经支持 bidding 的广告源,比如 Meta、Unity、AppLovin、Mintegral、Pangle(海外版)等,直接点“添加实时竞价广告源”,后台会让你填对应广告平台的 app 信息,比如 App ID、广告位 ID、密钥等,这些信息都要去对应广告源的平台注册并创建一个应用之后才能拿到。
对于不支持竞价或不方便接入竞价的广告源,可以用瀑布流方式添加。后台会让你填一个“自定义事件 ID”或者“服务器端参数”,这种模式实际上是在你的代码里实现一个适配器,自己根据 ID 去调用对应广告源 SDK 的加载逻辑。做起来比竞价模式繁琐,但对某些特定广告源来说是绕不开的方案。
这里强调一个我在项目中反复验证过的结论:能用实时竞价就优先用实时竞价,只有在广告源不支持或者竞价填充率不够的时候才用瀑布流兜底。实时竞价顶在瀑布流最上面,能最大程度保证高变现能力广告源的曝光权。
2.3 瀑布流优先级与底价调整的实操心得
用瀑布流模式添加广告源之后,后台默认会让你排一个优先级顺序。从上到下,eCPM 期望值应该是递减的。一般是 AdMob 竞价组、Meta 竞价组、Unity 竞价组、历史 eCPM 较稳的长尾广告源。这个顺序不是一层不变的,我通常每两周根据后台报表调整一次。
调整的核心指标是两个:填充率和实际 eCPM。一个广告源在顶部赚不到足够高的 eCPM,或者底部的广告源填充率长期为 0,都应该考虑调整位置或者提高/降低底价。
底价(Floor Price)设置对瀑布流意义很大。AdMob 里对单个广告源是可以设置 eCPM 底价的,低于这个价就不展示。这个值不能拍脑袋定,我一般是先看该广告源最近 7 天的平均 eCPM,然后在这个平均值的 85% 左右设置底价。设置完之后观察一周,如果跌破底价导致填充率骤降,就往下调;如果还能稳定出量,就往上调一点,争取榨出更高收益。
实际操作中还有一个容易被忽略的细节:不同广告位的底价策略要分开,不要一套参数通吃所有广告单元。激励视频的 eCPM 通常比插屏高不少,单独设置能避免互相影响。
3. Android 端 SDK 集合实操
3.1 工程环境准备与依赖接入
环境方面,我默认你用的是 Android Studio。如果你是第一次接触 Android 开发,建议先装最新稳定版 Android Studio,新建一个空工程再继续;如果你已经有一定基础,直接打开自己现有的项目加依赖就行。注意一点,国内网络环境下访问某些依赖仓库可能不稳定,如果你在 Gradle 同步时卡住,试试切换集团仓库镜像。
在 build.gradle(Module 级)中加入 AdMob SDK 依赖:
gradle复制dependencies {
implementation 'com.google.android.gms:play-services-ads:23.5.0'
}
我这里写的是当前接入时的稳定版本号,你可以去官方版本页面查最新的,建议用大版本里比较新的稳定版,不要追太激进的 beta 版本,适配好了才不会出怪问题。
同时,Android 工程的 minSdkVersion 建议不低于 21。AdMob SDK 的某些功能在更低版本上已经不再维护,而且新版 Google Play 的发布政策也在收紧 minSdk 要求。如果你的老项目还在用 minSdk 19,建议趁这次升级一起调了。
除了 AdMob 主 SDK,聚合还需要为每个广告源引入对应的 adapter 依赖。比如你接了 Meta、Unity 这些,就要把它们各自的 SDK 和 adapter 一起加进去。adapter 的作用是让 AdMob 聚合层跟广告源 SDK 能互相通信。
gradle复制dependencies {
implementation 'com.google.android.gms:play-services-ads:23.5.0'
// Meta Audience Network
implementation 'com.facebook.android:audience-network-sdk:6.16.0'
implementation 'com.google.ads.mediation:facebook:6.16.0.0'
// Unity Ads
implementation 'com.unity3d.ads:unity-ads:4.10.0'
implementation 'com.google.ads.mediation:unity:4.10.0.0'
}
每个 adapter 的版本号都要跟广告源 SDK 的主版本保持一致,否则会在运行时抛版本不匹配的异常,非常坑。
3.2 初始化流程与三大核心广告格式的加载代码
初始化的时机要尽可能早。官方建议在 Application 的 onCreate 里做,我在工程里也是这么处理的。这样能保证 SDK 有足够长的时间拉取广告配置,等你真正需要展示广告的时候,它早就准备好了。
kotlin复制class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
MobileAds.initialize(this) { initStatus ->
// 初始化完成回调
}
}
}
注意,这个回调不一定能保证在你第一次展示广告之前触发,所以业务逻辑不要依赖这个回调,尤其是不要在回调里立即发广告请求。
横幅广告是最简单的格式。AdMob 的横幅有两种接入方式:拿 Banner 加载,或者在 XML 布局里直接声明 AdView。我推荐在代码里动态创建,原因是可以根据页面结构灵活调整位置,不需要为了一个广告视图改 XML 布局。
kotlin复制val adView = AdView(this)
adView.adUnitId = "ca-app-pub-942544/1234567890"
adView.adSize = AdSize.BANNER
// layoutParams省略,放入父容器中
adView.loadAd(AdRequest.Builder().build())
再说插屏广告。插屏的加载和展示是分离的,这跟横幅逻辑完全不同。加载是异步的,展示时 ays 可能已经加载好,也可能还没好,业务上要做好“当前没有可以展示的插屏”这个分支。
kotlin复制class InterstitialHelper {
private var interstitialAd: InterstitialAd? = null
fun load(context: Context) {
InterstitialAd.load(context, "ca-app-pub-942544/1234567890",
AdRequest.Builder().build(), object : InterstitialAdLoadCallback() {
override fun onAdLoaded(ad: InterstitialAd) {
interstitialAd = ad
}
override fun onAdFailedToLoad(error: LoadAdError) {
interstitialAd = null
}
})
}
fun show(activity: Activity): Boolean {
val ad = interstitialAd
if (ad == null) return false
ad.fullScreenContentCallback = object : FullScreenContentCallback() {
override fun onAdDismissedFullScreenContent() {
load(activity) // 展示完成后马上加载下一个
}
}
ad.show(activity)
return true
}
}
激励视频的逻辑跟插屏非常像,只是多了一个用户激励回调。用户看完激励视频,你需要在回调里给用户发放奖励,比如游戏金币、去广告卡、会员试用等。一旦回调触发,必须保证奖励发放成功,这是平台审核非常看重的一点。
3.3 加载策略与生命周期管理的几个细节
在实际业务里,广告加载数量要控制好。我见过不少团队每个页面加载好几条广告,页面切换时还重新加载,结果大量请求被 AdMob 判定为无效请求,影响账号信誉。
我一般遵循一个原则:按需预加载。插屏和激励视频各缓存一条,用户触发逻辑前提前几秒加载;横幅除非页面需要,否则不要常驻。什么时候加载比较合理?进入 App 主界面后、行为节点前 2 到 3 秒、上一条广告关闭之后。归根到底就是“不要提前太多,也不要正好赶不上”。
生命周期处理很容易忽略。插屏和激励视频的展示一定要绑定 Activity 的 session,不要在 Activity 已经被销毁时 show,会直接泄漏或崩溃。横幅广告在页面退出时也要调用 destroy(),否则会造成资源泄漏,尤其你有多个页面复用同一个 AdView 实例时,一定要在页面不可见时暂停或者销毁。
kotlin复制override fun onDestroy() {
adView?.destroy()
super.onDestroy()
}
另外,Google Play 政策对广告体验要求很高。插屏广告不能在用户交互前突然弹出,不能强制倒计时关闭,横幅广告不能遮挡操作区域。这些不是技术问题,是合规问题,一旦被 Google 平台抓到违规行为,轻则警告,重则下架。我的建议是每次版本迭代前,专门过一遍 Google Play 广告政策页面。
4. 常见问题与排查技巧实录
4.1 广告请求没填充,别急着怪 SDK
广告请求发出去,返回的 LoadAdError 千奇百怪,但归根到底就几个原因:地区没有广告主、广告单元配置不对、底层 SDK 没正确初始化。我的排查顺序一般是这样的。
先打开 SDK 的详细日志,用 MobileAds.setVerboseLogging(true) 强制输出调试日志,再结合实际设备打点看请求走没走到对应的广告源。很多时候问题不在 AdMob 本身,而是聚合里的某个广告源 adapter 配置错误,或者是广告源平台那边的 App ID 和广告位 ID 填反了。这一层层排查下来可以很快定位。
另一个很要命的情况是广告单元配置完全正确,但就是没填充。这种情况先检查一下你所在地区是不是广告主覆盖率太低。解决办法是加入更多长尾广告源,或者用瀑布流方式把多个中小广告源串联起来,确保每个地区都有碎片化填充机会。
4.2 广告素材加载失败与本地存储访问的坑
说一个相对冷门但实际发生频率不低的坑:广告 SDK 加载素材时的存储访问问题。Android 11 开始系统对应用访问 Android/data 目录做了严格限制,很多 SDK 老版本仍习惯读取这个目录来做缓存管理,结果静默失败了。现象是 SDK 初始化正常、请求也发出去,但广告素材迟迟加载不出来,或者某些功能(比如看广告换奖励)点了没反应。
如果你也遇到类似情况,第一选择是升级依赖库和广告源 adapter 到最新版,新版基本都适配了分区存储;第二选择是明确 SDK 的工作目录,让它使用 context.getExternalFilesDir(),这个目录不需要额外权限,也不会触发新系统的限制。我一开始接激励视频时遇到过一次广告一直 is loaded 但不展示,最后定位到就是缓存目录读取异常,改成外部文件目录后问题立刻消失。
这种问题没有统一的报错码,排查时多抓系统日志,搜索关键词 “Failed to read” “FileNotFound” “EACCES” 这类权限相关错误,基本就能对上。
4.3 后台数据一堆,但 eCPM 收入不见涨怎么办
聚合体系跑起来之后,你一定会天天盯后台。有人会陷入一个误区:只看总收入,不看明细。但实际上 AdMob 后台报表的维度非常丰富,我建议每周至少看一次三个维度:地区维度、广告源维度、广告格式维度。
地区维度是为了看哪些国家贡献了主要收入,针对高 eCPM 地区可以加强本地化运营;广告源维度是为了看哪些广告源拉低了整体 eCPM,及时调整瀑布流位置或底价;广告格式维度是为了评估各自广告位的承载上限,决定要不要增加新的广告位。只看总收入,你永远不知道钱丢在哪个环节。
还有一个常见问题是测试流量污染。如果你没有配测试设备,自己点了一遍广告,后台会出现异常的展示率和低 eCPM 数据,反而误导你的判断。所以上线前一定把测试设备配上,或者直接在代码里指定测试设备 ID。
4.4 独家优化建议:把聚合的收益再往上推一档
基础接入跑通之后,想提升整体收入,我实际操作中比较有效的两个技巧是“按时段调价”和“设置 A/B 竞价实验”。
AdMob 后台可以对瀑布流广告源开启“时段策略”,比如早高峰和晚高峰用户点击意愿高,可以适当提高底价;凌晨流量少,就放低底价保证填充。这样能把有限的优质流量卖出高价,又不至于在低峰期颗粒无收。这个功能比较冷门,但效果很显著。
A/B 实验则是一个需要耐心的技术活。同时在两个中介组里分别加不同的广告源组合,让两组流量各跑两周,然后对比报表里的 eCPM、填充率、收入数据,保留胜出的组合往下迭代。理论上这个操作是数据驱动的最优解,但需要你的流量达到一定规模才具备统计意义,小流量 App 做这个容易得出误导性结论,要谨慎。
最后说一个兜底方案:House Ads。如果你有自有广告投放需求或内部推广渠道建议,可以在 AdMob 聚合里配置内部广告源,在外部填充率不足时展示自己的广告,保护收入不跌破底线。这个功能能帮你在广告淡季维持稳定填充,也能给自家 App 导流,一举两得。
5. 最后老老实实补充一点我的个人经验
做 AdMob 聚合变现这些年,我最真实的感受是:这套体系的技术门槛并没有想象中高,真正拉开收益差距的其实是监控与迭代的耐心。SDK 接入一次人人都会,但持续看报表、调底价、换广告源、做实验,才是让 eCPM 稳步上涨的核心。踩了几次坑之后,我习惯每次改动都记录在案,为每次广告源调整留好备注,这样过一个月回头看,能清楚知道哪个决定带来了收益增长,哪个决定实际上是负优化。
另外有一个建议给准备上架 Google Play 的团队:广告 ID 一定要用 App 内部统一管理,不要散落在代码里,否则换个广告单元就要重新发版。顺便提一句,Android Studio 的基础问题(比如中文界面设置、工程模板选择这类)如果还不太熟,建议先花半小时把开发环境理顺,再来做接入,那样试错成本会低很多。广告变现这项长期运营的活,扎实的基础建设永远比临时补洞更划算。
