- 示例工程
【免费下载链接】quickstart-android
Firebase Quickstart Samples for Android
导读
本文以 quickstart-android 仓库中的 admob 示例 为主体,系统讲解如何在 Android 应用中集成 Google Mobile Ads SDK,通过AdRequest+AdView展示横幅广告(Banner Ad)、通过InterstitialAd展示插屏广告(Interstitial Ad)的完整流程。读完本文,你将掌握 AdMob 应用 ID 与广告单元 ID 的配置方法、两类广告的加载与展示调用链、广告生命周期管理,以及 Java / Kotlin 双版本示例的工程结构。
以下截屏为该示例应用在设备上的实际运行效果:顶部为 Firebase 标识与 "SHOW INTERSTITIAL AD" 按钮,底部即为 320×50 的 AdMob 测试横幅广告。
一、示例项目要解决什么问题
admob/README.md 明确指出,该 quickstart 的核心目的是演示两类最常见的 AdMob 广告形式:
- 横幅广告(Banner Ad):通过
AdRequest与AdView组合实现,常驻于页面底部; - 插屏广告(Interstitial Ad):通过
InterstitialAd实现,以全屏形式在页面切换等时机弹出。
示例运行后,屏幕上会直接展示一条测试横幅广告和一条测试插屏广告——这意味着整个示例在未接入真实广告单元的情况下即可跑通完整的「加载 → 展示 → 关闭 → 重新加载」链路,非常适合作为接入 AdMob 的起点工程。
从源码结构看,项目对 Java 与 Kotlin 提供了完全对等的两份实现:入口 EntryChoiceActivity.kt 在启动时让用户二选一,分别跳转到 java 版 MainActivity 与 kotlin 版 MainActivity,两者的页面导航逻辑(Navigation+nav_graph)完全一致,真正的广告业务代码则集中在两个版本的FirstFragment中。
二、接入前的准备工作
1. 添加 Firebase 到 Android 项目
按官方标准流程将 Firebase 接入 Android 工程(添加 google-services 插件、放置google-services.json),这是后续使用 AdMob 的前提。需要特别留意的一点:AdMob 广告单元 ID 并不存放在google-services.json中,这一点在 FirstFragment.java 的注释中有明确说明——开发者要么将其作为自定义值存入字符串资源,要么直接使用常量。
2. 配置 AdMob 应用 ID(关键步骤)
README 给出了最核心的配置操作:修改src/main/res/values/strings.xml中的admob_app_id字符串,替换为你自己的 AdMob 应用 ID。在仓库中对应文件为 admob/app/src/main/res/values/strings.xml:
<!-- TODO: Replace this with your own Admob App ID! This value is only a sample. --> <string name="admob_app_id">ca-app-pub-3940256099942544~3347511713</string>README 特别强调:这个 ID 会在两处被使用:
- AndroidManifest.xml中的
meta-data节点——它是 Google Mobile Ads SDK 初始化所必需的元数据,缺失或配置错误会导致应用直接崩溃(Manifest 注释明确写着 "This metadata is required or your app will crash!"):
<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="@string/admob_app_id" />- MainActivity / FirstFragment 中的校验逻辑:Java 版 FirstFragment.java 与 Kotlin 版 FirstFragment.kt 都实现了
checkIds()方法——若admob_app_id仍是内置测试 ID,会输出警告日志提示开发者参考 README 修改:
private void checkIds() { if (TEST_APP_ID.equals(getString(R.string.admob_app_id))) { Log.w(TAG, "Your admob_app_id is not configured correctly, please see the README"); } }这可以看作一个"配置未完成"的运行时提醒机制,避免开发者把测试 ID 带上生产环境而不自知。
3. Manifest 中的权限与 AdActivity 声明
AndroidManifest.xml 中还需要声明以下内容(示例均已包含):
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />INTERNET:广告请求依赖网络,必须声明;ACCESS_NETWORK_STATE:SDK 用于感知网络状态以决定广告请求策略。
同时必须显式声明 SDK 内部的AdActivity,并为其配置configChanges与透明主题,否则广告展示时可能因配置变更问题出现异常:
<activity android:name="com.google.android.gms.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:theme="@android:style/Theme.Translucent" />三、横幅广告(Banner Ad)实现
1. 在布局中声明 AdView
横幅广告的核心是com.google.android.gms.ads.AdView。在 fragment_first.xml 中,它被直接声明为布局的一部分,并通过两个自定义属性完成配置:
<com.google.android.gms.ads.AdView android:id="@+id/adView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" ads:adSize="BANNER" ads:adUnitId="@string/banner_ad_unit_id" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" />ads:adSize="BANNER":指定广告尺寸为标准横幅(320×50 dp);ads:adUnitId="@string/banner_ad_unit_id":指定横幅广告单元 ID。
对应的广告单元 ID 同样定义在 strings.xml:
<string name="banner_ad_unit_id">ca-app-pub-3940256099942544/6300978111</string> <string name="interstitial_ad_unit_id">ca-app-pub-3940256099942544/1033173712</string>这两个 ID 均为 Google 提供的专用测试广告单元(ca-app-pub-3940256099942544前缀),与测试应用 ID 配套使用,保证返回的一定是测试广告,不会产生真实计费。
2. 初始化 SDK 并加载横幅
在 FirstFragment.java(Kotlin 版见 FirstFragment.kt)中,onViewCreated完成了三件事:
// Initialize the Google Mobile Ads SDK MobileAds.initialize(getContext()); mAdView = binding.adView; requestNewInterstitial();MobileAds.initialize(context):SDK 初始化入口,应在应用早期调用;- 拿到
binding.adView引用:对应布局中的AdView; - 调用
requestNewInterstitial():该方法内同时完成横幅与插屏的加载。
横幅的加载逻辑封装在同方法的开头:
private void requestNewInterstitial() { AdRequest adRequest = new AdRequest.Builder().build(); mAdView.loadAd(adRequest); ... }调用链非常清晰:AdRequest.Builder().build()构造一个空的(无定向参数的)广告请求对象,随后AdView.loadAd(adRequest)异步发起横幅广告请求。从源码结构看,示例刻意保持了最简单的请求构造方式,便于开发者先跑通全链路,再按业务需要为AdRequest.Builder()追加年龄、性别、关键词等定向参数。
四、插屏广告(Interstitial Ad)实现
1. 异步加载与回调
插屏广告与横幅的关键区别在于:插屏是一个独立的全屏对象,需要先异步加载、再在合适的时机手动展示。示例在requestNewInterstitial()中完成加载(见 FirstFragment.java):
InterstitialAd.load(getContext(), getString(R.string.interstitial_ad_unit_id), adRequest, new InterstitialAdLoadCallback() { @Override public void onAdLoaded(@NonNull InterstitialAd interstitialAd) { super.onAdLoaded(interstitialAd); mInterstitialAd = interstitialAd; // Ad received, ready to display if (mLoadInterstitialButton != null) { mLoadInterstitialButton.setEnabled(true); } ... } @Override public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { super.onAdFailedToLoad(loadAdError); mInterstitialAd = null; Log.w(TAG, "onAdFailedToLoad:" + loadAdError.getMessage()); } });值得学习的工程实践:
onAdLoaded:将加载成功的InterstitialAd实例暂存,同时启用"显示插屏"按钮——按钮初始是禁用的(mLoadInterstitialButton.setEnabled(mInterstitialAd != null)),只有广告真正就绪用户才能点击,避免空白插屏;onAdFailedToLoad:将实例置空并记录LoadAdError的报错信息,便于排查填充失败原因(如网络问题、广告单元配置错误、政策违规等)。
2. 展示插屏与关闭后处理
按钮点击时判断广告是否可用(FirstFragment.java):
mLoadInterstitialButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mInterstitialAd != null) { mInterstitialAd.show(getActivity()); } else { beginSecondActivity(); } } });即:广告已加载 → 全屏展示插屏;未加载 → 直接跳过广告跳转下一页面。这种"优雅降级"策略保证用户操作永远有响应。
展示期间通过FullScreenContentCallback感知全屏内容的生命周期(FirstFragment.java):
mInterstitialAd.setFullScreenContentCallback(new FullScreenContentCallback() { @Override public void onAdDismissedFullScreenContent() { super.onAdDismissedFullScreenContent(); requestNewInterstitial(); // 立即预加载下一条插屏 beginSecondActivity(); // 继续原本的页面跳转 } });这里体现了一个关键最佳实践:插屏广告是一次性资源,展示并关闭后即失效。因此在onAdDismissedFullScreenContent(用户关闭插屏)回调中,示例同时做了两件事:调用requestNewInterstitial()为下一次展示预加载新广告,并调用beginSecondActivity()继续被插屏打断的导航流程(通过 Navigation 组件跳转到SecondFragment)。Kotlin 版在 FirstFragment.kt 中的写法完全对应。
3. 生命周期兜底:onResume 重新加载
在 FirstFragment.java 的onResume中还有一层保障:
@Override public void onResume() { super.onResume(); if (mAdView != null) { mAdView.resume(); } if (mInterstitialAd == null) { requestNewInterstitial(); } }当mInterstitialAd为空(例如加载失败、已展示完毕)时,页面恢复可见即自动发起重新加载,确保插屏随时可用。
五、广告生命周期管理与内存释放
横幅广告AdView与 Activity/Fragment 的生命周期强相关,示例在三个回调点做了对称处理(Java 版见 FirstFragment.java,Kotlin 版见 FirstFragment.kt):
| 生命周期回调 | 必须执行的操作 | 作用 |
|---|---|---|
onPause() | adView.pause() | 暂停广告刷新,节省资源 |
onResume() | adView.resume() | 恢复广告刷新 |
onDestroy() | adView.destroy() | 释放广告资源,防止内存泄漏 |
@Override public void onPause() { if (mAdView != null) { mAdView.pause(); } super.onPause(); } @Override public void onDestroy() { if (mAdView != null) { mAdView.destroy(); } super.onDestroy(); }这是 AdMob 接入中极易被遗漏但官方强制的规范:不随生命周期正确暂停/恢复/销毁AdView,轻则浪费流量与电量,重则引发内存问题。Kotlin 版额外在onDestroyView中将_binding置空以解除 ViewBinding 引用,属于 Kotlin 侧的配套清理。
六、运行验证与预期结果
完成配置后,在 Android 设备或模拟器上运行(仓库提供gradlew与gradlew.bat,settings.gradle.kts已通过include(":internal:lintchecks")等声明依赖仓库内置的 lint 检查模块)。运行后即可看到 README 所述的预期结果:
- 测试横幅广告:页面底部显示 320×50 的 AdMob 测试横幅(文案为 "Nice job! You're displaying a 320 x 50 test ad from AdMob.");
- 测试插屏广告:点击 "SHOW INTERSTITIAL AD" 按钮后全屏展示测试插屏,关闭后自动导航到第二页面,并同步预加载下一条插屏。
若在onAdFailedToLoad的日志中看到失败原因,可优先核对:应用 ID 是否已替换、网络是否可用、广告单元 ID 格式是否正确。
七、注意事项与最佳实践小结
- 测试 ID 与生产 ID 分离:示例内置的
ca-app-pub-3940256099942544系列 ID 仅用于测试(且不可用于其他用途),上线前必须替换为 AdMob 后台创建的真实应用 ID 与广告单元 ID,并移除checkIds()的测试 ID 告警路径。 - 插屏"预加载 + 用完即弃":插屏广告应提前加载、展示一次即失效、关闭后立即重新加载,示例的
requestNewInterstitial()复用设计就是这一模式的范本。 - 广告与用户流程解耦:示例在广告未就绪时直接放行用户操作(跳过插屏继续导航),避免广告加载阻塞业务,这是插屏接入的通用兜底策略。
- 严格跟随生命周期:
AdView的pause() / resume() / destroy()必须与 Fragment/Activity 生命周期对齐,Manifest 中的AdActivity与APPLICATION_ID元数据也缺一不可。
八、进一步探索仓库
想继续深入,可在仓库中对照阅读以下文件:
- Java 版广告实现:FirstFragment.java、MainActivity.java
- Kotlin 版广告实现:FirstFragment.kt、MainActivity.kt
- 资源配置与导航:strings.xml、fragment_first.xml、nav_graph_kotlin.xml
- 构建入口:settings.gradle.kts、gradle.properties
这些文件共同构成了一个"配置 → 加载 → 展示 → 生命周期管理"完整的 AdMob 接入参考实现,可直接作为业务项目中横幅与插屏广告集成的蓝本。
- 示例工程
【免费下载链接】quickstart-android
Firebase Quickstart Samples for Android
相关推荐
开源中国社区Android客户端:10分钟快速上手指南
开源中国社区Android客户端:10分钟快速上手指南 开源中国社区Android客户端是一款专为开源爱好者打造的移动应用,让你随时随地参与开源社区讨论、获取最
移动开发社交猫抓资源嗅探扩展:从打开页面到拿到文件
猫抓资源嗅探扩展:从打开页面到拿到文件 打开某个课程页,右键菜单里只有"复制",下载按钮根本不存在。想保存那个 MP4,只能打开 Network 面板一条条翻请
音视频Upstash Ratelimit 最佳配置指南:如何根据业务需求调整限流参数
Upstash Ratelimit 最佳配置指南:如何根据业务需求调整限流参数 Upstash Ratelimit 是一款专为无服务器运行时设计的限流库,能够帮
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考