插页式广告属于全屏广告,会覆盖宿主应用的整个界面,通常展示在应用流程的自然过渡点上,例如,活动之间的切换处或游戏关卡之间的暂停时段中。当应用展示插页式广告时,用户可以选择点按该广告,进而访问其目标网址,也可以将其关闭,并返回应用。 阅读我们的案例研究。
本指南介绍了如何将插页式广告植入到 Android 应用中。
前提条件
- Google 移动广告 SDK 19.7.0 或更高版本。
- 完成入门指南。
务必用测试广告进行测试
在构建和测试应用时,请确保使用的是测试广告,而不是实际投放的广告。否则,可能会导致您的账号被中止。
对于 Android 插页式广告,加载测试广告最简便的方法就是使用下面的专用测试广告单元 ID:
ca-app-pub-3940256099942544/1033173712
该测试广告单元 ID 已经过专门配置,可确保每个请求返回的都是测试广告。您可以在自己应用的编码、测试和调试过程中随意使用该测试广告单元 ID。只需确保您会在发布应用前用自己的广告单元 ID 替换该测试广告单元 ID 即可。
如需详细了解移动广告 SDK 的测试广告如何运作,请参阅测试广告。
加载广告
如需加载插页式广告,请调用 InterstitialAd
静态 load()
方法并传入 InterstitialAdLoadCallback
,以接收加载的广告或任何可能的错误。请注意,与其他广告格式加载回调一样,InterstitialAdLoadCallback
会利用 LoadAdError
提供较高保真度的错误详情。
import com.google.android.gms.ads.interstitial.InterstitialAd;
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback;
public class MainActivity extends Activity {
private InterstitialAd mInterstitialAd;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AdRequest adRequest = new AdRequest.Builder().build();
InterstitialAd.load(this,"ca-app-pub-3940256099942544/1033173712", adRequest,
new InterstitialAdLoadCallback() {
@Override
public void onAdLoaded(@NonNull InterstitialAd interstitialAd) {
// The mInterstitialAd reference will be null until
// an ad is loaded.
mInterstitialAd = interstitialAd;
Log.i(TAG, "onAdLoaded");
}
@Override
public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
// Handle the error
Log.d(TAG, loadAdError.toString());
mInterstitialAd = null;
}
});
}
}
import com.google.android.gms.ads.interstitial.InterstitialAd;
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback;
class MainActivity : AppCompatActivity() {
private var mInterstitialAd: InterstitialAd? = null
private final val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val adRequest = AdRequest.Builder().build()
InterstitialAd.load(this,"ca-app-pub-3940256099942544/1033173712", adRequest, object : InterstitialAdLoadCallback() {
override fun onAdFailedToLoad(adError: LoadAdError) {
Log.d(TAG, adError?.toString())
mInterstitialAd = null
}
override fun onAdLoaded(interstitialAd: InterstitialAd) {
Log.d(TAG, 'Ad was loaded.')
mInterstitialAd = interstitialAd
}
})
}
}
设置 FullScreenContentCallback
FullScreenContentCallback
处理与展示 InterstitialAd
相关的事件。在展示 InterstitialAd
之前,请务必按如下方式设置回调:
mInterstitialAd.setFullScreenContentCallback(new FullScreenContentCallback(){
@Override
public void onAdClicked() {
// Called when a click is recorded for an ad.
Log.d(TAG, "Ad was clicked.");
}
@Override
public void onAdDismissedFullScreenContent() {
// Called when ad is dismissed.
// Set the ad reference to null so you don't show the ad a second time.
Log.d(TAG, "Ad dismissed fullscreen content.");
mInterstitialAd = null;
}
@Override
public void onAdFailedToShowFullScreenContent(AdError adError) {
// Called when ad fails to show.
Log.e(TAG, "Ad failed to show fullscreen content.");
mInterstitialAd = null;
}
@Override
public void onAdImpression() {
// Called when an impression is recorded for an ad.
Log.d(TAG, "Ad recorded an impression.");
}
@Override
public void onAdShowedFullScreenContent() {
// Called when ad is shown.
Log.d(TAG, "Ad showed fullscreen content.");
}
});
mInterstitialAd?.fullScreenContentCallback = object: FullScreenContentCallback() {
override fun onAdClicked() {
// Called when a click is recorded for an ad.
Log.d(TAG, "Ad was clicked.")
}
override fun onAdDismissedFullScreenContent() {
// Called when ad is dismissed.
Log.d(TAG, "Ad dismissed fullscreen content.")
mInterstitialAd = null
}
override fun onAdFailedToShowFullScreenContent(adError: AdError?) {
// Called when ad fails to show.
Log.e(TAG, "Ad failed to show fullscreen content.")
mInterstitialAd = null
}
override fun onAdImpression() {
// Called when an impression is recorded for an ad.
Log.d(TAG, "Ad recorded an impression.")
}
override fun onAdShowedFullScreenContent() {
// Called when ad is shown.
Log.d(TAG, "Ad showed fullscreen content.")
}
}
展示广告
插页式广告应在应用流程的自然停顿期间进行展示,例如游戏的不同关卡之间或用户完成一项任务之后,都是非常不错的展示时机。如需展示插页式广告,请使用 show()
方法。
if (mInterstitialAd != null) {
mInterstitialAd.show(MyActivity.this);
} else {
Log.d("TAG", "The interstitial ad wasn't ready yet.");
}
if (mInterstitialAd != null) {
mInterstitialAd?.show(this)
} else {
Log.d("TAG", "The interstitial ad wasn't ready yet.")
}
一些最佳做法
- 考虑插页式广告这种广告类型是否适合您的应用。
- 在具有自然过渡点的应用中,插页式广告的效果最好。此类过渡点通常存在于应用内的任务结束时,例如分享完图片或完成一个游戏关卡时。请务必考虑在应用流程的哪些时间点展示插页式广告,以及用户可能会以什么方式响应。
- 务必在展示插页式广告时暂停操作。
- 插页式广告类型多样,包括文字广告、图片广告和视频广告等。确保应用在展示插页式广告时,也会暂停使用某些资源,以便供广告使用,这一点十分重要。例如,当您发出展示插页式广告的调用后,请务必暂停应用产生的所有音频输出。
- 留出充足的加载时间。
- 确保在恰当的时间展示插页式广告十分重要,同样,确保用户无需等待广告加载也十分重要。在您打算调用
show()
前,请事先通过调用load()
加载广告,这可确保应用在广告展示时间到来前完全加载插页式广告。 - 不要向用户展示太多广告。
- 虽然提高插页式广告在应用中的展示频次似乎是实现增收的好方法,但这么做也会影响用户体验并降低点击率。应确保用户不会频繁受到广告打扰,使他们可以充分享受到使用应用的乐趣。
源代码
MyActivity.java
/* * Copyright (C) 2013 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.android.gms.example.interstitialexample; import android.annotation.SuppressLint; import android.os.Bundle; import android.os.CountDownTimer; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import com.google.android.gms.ads.AdError; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.FullScreenContentCallback; import com.google.android.gms.ads.LoadAdError; import com.google.android.gms.ads.MobileAds; import com.google.android.gms.ads.RequestConfiguration; import com.google.android.gms.ads.interstitial.InterstitialAd; import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback; import java.util.Arrays; import java.util.concurrent.atomic.AtomicBoolean; /** Main Activity. Inflates main activity xml. */ @SuppressLint("SetTextI18n") public class MyActivity extends AppCompatActivity { // Check your logcat output for the test device hashed ID e.g. // "Use RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("ABCDEF012345")) // to get test ads on this device" or // "Use new ConsentDebugSettings.Builder().addTestDeviceHashedId("ABCDEF012345") to set this as // a debug device". public static final String TEST_DEVICE_HASHED_ID = "ABCDEF012345"; private static final long GAME_LENGTH_MILLISECONDS = 3000; private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/1033173712"; private static final String TAG = "MyActivity"; private final AtomicBoolean isMobileAdsInitializeCalled = new AtomicBoolean(false); private GoogleMobileAdsConsentManager googleMobileAdsConsentManager; private InterstitialAd interstitialAd; private CountDownTimer countDownTimer; private Button retryButton; private boolean gamePaused; private boolean gameOver; private boolean adIsLoading; private long timerMilliseconds; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); // Log the Mobile Ads SDK version. Log.d(TAG, "Google Mobile Ads SDK Version: " + MobileAds.getVersion()); googleMobileAdsConsentManager = GoogleMobileAdsConsentManager.getInstance(getApplicationContext()); googleMobileAdsConsentManager.gatherConsent( this, consentError -> { if (consentError != null) { // Consent not obtained in current session. Log.w( TAG, String.format("%s: %s", consentError.getErrorCode(), consentError.getMessage())); } startGame(); if (googleMobileAdsConsentManager.canRequestAds()) { initializeMobileAdsSdk(); } if (googleMobileAdsConsentManager.isPrivacyOptionsRequired()) { // Regenerate the options menu to include a privacy setting. invalidateOptionsMenu(); } }); // This sample attempts to load ads using consent obtained in the previous session. if (googleMobileAdsConsentManager.canRequestAds()) { initializeMobileAdsSdk(); } // Create the "retry" button, which tries to show an interstitial between game plays. retryButton = findViewById(R.id.retry_button); retryButton.setVisibility(View.INVISIBLE); retryButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { showInterstitial(); } }); } public void loadAd() { // Request a new ad if one isn't already loaded. if (adIsLoading || interstitialAd != null) { return; } adIsLoading = true; AdRequest adRequest = new AdRequest.Builder().build(); InterstitialAd.load( this, AD_UNIT_ID, adRequest, new InterstitialAdLoadCallback() { @Override public void onAdLoaded(@NonNull InterstitialAd interstitialAd) { // The mInterstitialAd reference will be null until // an ad is loaded. MyActivity.this.interstitialAd = interstitialAd; adIsLoading = false; Log.i(TAG, "onAdLoaded"); Toast.makeText(MyActivity.this, "onAdLoaded()", Toast.LENGTH_SHORT).show(); interstitialAd.setFullScreenContentCallback( new FullScreenContentCallback() { @Override public void onAdDismissedFullScreenContent() { // Called when fullscreen content is dismissed. // Make sure to set your reference to null so you don't // show it a second time. MyActivity.this.interstitialAd = null; Log.d("TAG", "The ad was dismissed."); } @Override public void onAdFailedToShowFullScreenContent(AdError adError) { // Called when fullscreen content failed to show. // Make sure to set your reference to null so you don't // show it a second time. MyActivity.this.interstitialAd = null; Log.d("TAG", "The ad failed to show."); } @Override public void onAdShowedFullScreenContent() { // Called when fullscreen content is shown. Log.d("TAG", "The ad was shown."); } }); } @Override public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { // Handle the error Log.i(TAG, loadAdError.getMessage()); interstitialAd = null; adIsLoading = false; String error = String.format( java.util.Locale.US, "domain: %s, code: %d, message: %s", loadAdError.getDomain(), loadAdError.getCode(), loadAdError.getMessage()); Toast.makeText( MyActivity.this, "onAdFailedToLoad() with error: " + error, Toast.LENGTH_SHORT) .show(); } }); } private void createTimer(final long milliseconds) { // Create the game timer, which counts down to the end of the level // and shows the "retry" button. if (countDownTimer != null) { countDownTimer.cancel(); } final TextView textView = findViewById(R.id.timer); countDownTimer = new CountDownTimer(milliseconds, 50) { @Override public void onTick(long millisUnitFinished) { timerMilliseconds = millisUnitFinished; textView.setText("seconds remaining: " + ((millisUnitFinished / 1000) + 1)); } @Override public void onFinish() { gameOver = true; textView.setText("done!"); retryButton.setVisibility(View.VISIBLE); } }; countDownTimer.start(); } @Override public void onResume() { // Start or resume the game. super.onResume(); resumeGame(); } @Override public void onPause() { super.onPause(); pauseGame(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.action_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { View menuItemView = findViewById(item.getItemId()); PopupMenu popup = new PopupMenu(this, menuItemView); popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu()); popup.show(); popup .getMenu() .findItem(R.id.privacy_settings) .setVisible(googleMobileAdsConsentManager.isPrivacyOptionsRequired()); popup.setOnMenuItemClickListener( popupMenuItem -> { if (popupMenuItem.getItemId() == R.id.privacy_settings) { pauseGame(); // Handle changes to user consent. googleMobileAdsConsentManager.showPrivacyOptionsForm( this, formError -> { if (formError != null) { Toast.makeText(this, formError.getMessage(), Toast.LENGTH_SHORT).show(); } resumeGame(); }); return true; } else if (popupMenuItem.getItemId() == R.id.ad_inspector) { MobileAds.openAdInspector( this, error -> { // Error will be non-null if ad inspector closed due to an error. if (error != null) { Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show(); } }); return true; } return false; }); return super.onOptionsItemSelected(item); } private void showInterstitial() { // Show the ad if it's ready. Otherwise restart the game. if (interstitialAd != null) { interstitialAd.show(this); } else { startGame(); if (googleMobileAdsConsentManager.canRequestAds()) { loadAd(); } } } private void startGame() { // Hide the button, and kick off the timer. retryButton.setVisibility(View.INVISIBLE); createTimer(GAME_LENGTH_MILLISECONDS); gamePaused = false; gameOver = false; } private void resumeGame() { if (gameOver || !gamePaused) { return; } // Create a new timer for the correct length. gamePaused = false; createTimer(timerMilliseconds); } private void pauseGame() { if (gameOver || gamePaused) { return; } countDownTimer.cancel(); gamePaused = true; } private void initializeMobileAdsSdk() { if (isMobileAdsInitializeCalled.getAndSet(true)) { return; } // Set your test devices. MobileAds.setRequestConfiguration( new RequestConfiguration.Builder() .setTestDeviceIds(Arrays.asList(TEST_DEVICE_HASHED_ID)) .build()); new Thread( () -> { // Initialize the Google Mobile Ads SDK on a background thread. MobileAds.initialize(this, initializationStatus -> {}); // Load an ad on the main thread. runOnUiThread(() -> loadAd()); }) .start(); } }
MainActivity.kt
package com.google.android.gms.example.interstitialexample import android.os.Bundle import android.os.CountDownTimer import android.util.Log import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.PopupMenu import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.google.android.gms.ads.* import com.google.android.gms.ads.interstitial.InterstitialAd import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback import com.google.android.gms.example.interstitialexample.databinding.ActivityMainBinding import java.util.concurrent.atomic.AtomicBoolean import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { private val isMobileAdsInitializeCalled = AtomicBoolean(false) private lateinit var binding: ActivityMainBinding private lateinit var googleMobileAdsConsentManager: GoogleMobileAdsConsentManager private var interstitialAd: InterstitialAd? = null private var countdownTimer: CountDownTimer? = null private var gamePaused = false private var gameOver = false private var adIsLoading: Boolean = false private var timerMilliseconds = 0L override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) // Log the Mobile Ads SDK version. Log.d(TAG, "Google Mobile Ads SDK Version: " + MobileAds.getVersion()) googleMobileAdsConsentManager = GoogleMobileAdsConsentManager.getInstance(this) googleMobileAdsConsentManager.gatherConsent(this) { consentError -> if (consentError != null) { // Consent not obtained in current session. Log.w(TAG, "${consentError.errorCode}: ${consentError.message}") } // Kick off the first play of the "game". startGame() if (googleMobileAdsConsentManager.canRequestAds) { initializeMobileAdsSdk() } if (googleMobileAdsConsentManager.isPrivacyOptionsRequired) { // Regenerate the options menu to include a privacy setting. invalidateOptionsMenu() } } // This sample attempts to load ads using consent obtained in the previous session. if (googleMobileAdsConsentManager.canRequestAds) { initializeMobileAdsSdk() } // Create the "retry" button, which triggers an interstitial between game plays. binding.retryButton.visibility = View.INVISIBLE binding.retryButton.setOnClickListener { showInterstitial() } } override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.action_menu, menu) return super.onCreateOptionsMenu(menu) } override fun onOptionsItemSelected(item: MenuItem): Boolean { val menuItemView = findViewById<View>(item.itemId) val activity = this PopupMenu(this, menuItemView).apply { menuInflater.inflate(R.menu.popup_menu, menu) menu .findItem(R.id.privacy_settings) .setVisible(googleMobileAdsConsentManager.isPrivacyOptionsRequired) show() setOnMenuItemClickListener { popupMenuItem -> when (popupMenuItem.itemId) { R.id.privacy_settings -> { pauseGame() // Handle changes to user consent. googleMobileAdsConsentManager.showPrivacyOptionsForm(activity) { formError -> if (formError != null) { Toast.makeText(activity, formError.message, Toast.LENGTH_SHORT).show() } resumeGame() } true } R.id.ad_inspector -> { MobileAds.openAdInspector(activity) { error -> // Error will be non-null if ad inspector closed due to an error. error?.let { Toast.makeText(activity, it.message, Toast.LENGTH_SHORT).show() } } true } // Handle other branches here. else -> false } } return super.onOptionsItemSelected(item) } } private fun loadAd() { // Request a new ad if one isn't already loaded. if (adIsLoading || interstitialAd != null) { return } adIsLoading = true val adRequest = AdRequest.Builder().build() InterstitialAd.load( this, AD_UNIT_ID, adRequest, object : InterstitialAdLoadCallback() { override fun onAdFailedToLoad(adError: LoadAdError) { Log.d(TAG, adError.message) interstitialAd = null adIsLoading = false val error = "domain: ${adError.domain}, code: ${adError.code}, " + "message: ${adError.message}" Toast.makeText( this@MainActivity, "onAdFailedToLoad() with error $error", Toast.LENGTH_SHORT, ) .show() } override fun onAdLoaded(ad: InterstitialAd) { Log.d(TAG, "Ad was loaded.") interstitialAd = ad adIsLoading = false Toast.makeText(this@MainActivity, "onAdLoaded()", Toast.LENGTH_SHORT).show() } }, ) } // Create the game timer, which counts down to the end of the level // and shows the "retry" button. private fun createTimer(milliseconds: Long) { countdownTimer?.cancel() countdownTimer = object : CountDownTimer(milliseconds, 50) { override fun onTick(millisUntilFinished: Long) { timerMilliseconds = millisUntilFinished binding.timer.text = "seconds remaining: ${ millisUntilFinished / 1000 + 1 }" } override fun onFinish() { gameOver = true binding.timer.text = "done!" binding.retryButton.visibility = View.VISIBLE } } countdownTimer?.start() } // Show the ad if it's ready. Otherwise restart the game. private fun showInterstitial() { if (interstitialAd != null) { interstitialAd?.fullScreenContentCallback = object : FullScreenContentCallback() { override fun onAdDismissedFullScreenContent() { Log.d(TAG, "Ad was dismissed.") // Don't forget to set the ad reference to null so you // don't show the ad a second time. interstitialAd = null } override fun onAdFailedToShowFullScreenContent(adError: AdError) { Log.d(TAG, "Ad failed to show.") // Don't forget to set the ad reference to null so you // don't show the ad a second time. interstitialAd = null } override fun onAdShowedFullScreenContent() { Log.d(TAG, "Ad showed fullscreen content.") // Called when ad is dismissed. } } interstitialAd?.show(this) } else { startGame() if (googleMobileAdsConsentManager.canRequestAds) { loadAd() } } } // Hide the button, and kick off the timer. private fun startGame() { binding.retryButton.visibility = View.INVISIBLE createTimer(GAME_LENGTH_MILLISECONDS) gamePaused = false gameOver = false } private fun pauseGame() { if (gameOver || gamePaused) { return } countdownTimer?.cancel() gamePaused = true } private fun resumeGame() { if (gameOver || !gamePaused) { return } createTimer(timerMilliseconds) gamePaused = true } private fun initializeMobileAdsSdk() { if (isMobileAdsInitializeCalled.getAndSet(true)) { return } // Set your test devices. MobileAds.setRequestConfiguration( RequestConfiguration.Builder().setTestDeviceIds(listOf(TEST_DEVICE_HASHED_ID)).build() ) CoroutineScope(Dispatchers.IO).launch { // Initialize the Google Mobile Ads SDK on a background thread. MobileAds.initialize(this@MainActivity) {} runOnUiThread { // Load an ad on the main thread. loadAd() } } } // Resume the game if it's in progress. public override fun onResume() { super.onResume() resumeGame() } public override fun onPause() { super.onPause() pauseGame() } companion object { // This is an ad unit ID for a test ad. Replace with your own interstitial ad unit ID. private const val AD_UNIT_ID = "ca-app-pub-3940256099942544/1033173712" private const val GAME_LENGTH_MILLISECONDS = 3000L private const val TAG = "MainActivity" // Check your logcat output for the test device hashed ID e.g. // "Use RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("ABCDEF012345")) // to get test ads on this device" or // "Use new ConsentDebugSettings.Builder().addTestDeviceHashedId("ABCDEF012345") to set this as // a debug device". const val TEST_DEVICE_HASHED_ID = "ABCDEF012345" } }
GitHub 上的示例
成功案例
后续步骤
- 如果您还没有创建自己的插页式广告单元,请在 AdMob 网站界面中创建。
- 详细了解广告定位和插页式广告指南。
- 不妨详细了解用户隐私权。
- 探索经过优化的 SDK 初始化和广告加载(Beta 版)。