展示 NativeAd
加载原生广告时,Google 移动广告 SDK 会调用相应广告格式的监听器。然后,就由您的应用负责展示广告了,尽管不一定要立即展示广告。为了更轻松地展示系统定义的广告格式,该 SDK 提供了一些实用资源,如下所述。
定义 NativeAdView
类
定义 NativeAdView
类。此类是 ViewGroup
类,也是 NativeAdView
类的顶级容器。每个原生广告视图都包含原生广告素材资源,例如 MediaView
视图元素或 Title
视图元素,这些元素必须是 NativeAdView
对象的子对象。
XML 布局
向项目添加 XML NativeAdView
:
<com.google.android.gms.ads.nativead.NativeAdView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical">
<LinearLayout
android:orientation="horizontal">
<ImageView
android:id="@+id/ad_app_icon" />
<TextView
android:id="@+id/ad_headline" />
</LinearLayout>
<!--Add remaining assets such as the image and media view.-->
</LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
Jetpack Compose
添加 JetpackComposeDemo/compose-util 模块,其中包含用于组合 NativeAdView
及其资源的辅助程序。
使用 compose-util
模块,编写 NativeAdView
:
import com.google.android.gms.compose_util.NativeAdAttribution
import com.google.android.gms.compose_util.NativeAdView
@Composable
/** Display a native ad with a user defined template. */
fun DisplayNativeAdView(nativeAd: NativeAd) {
NativeAdView {
// Display the ad attribution.
NativeAdAttribution(text = context.getString("Ad"))
// Add remaining assets such as the image and media view.
}
}
处理已加载的原生广告
加载原生广告时,处理回调事件,扩充原生广告视图,并将其添加到视图层次结构中:
Java
AdLoader.Builder builder = new AdLoader.Builder(this, "ca-app-pub-3940256099942544/2247696110")
.forNativeAd(new NativeAd.OnNativeAdLoadedListener() {
@Override
public void onNativeAdLoaded(NativeAd nativeAd) {
// Assumes you have a placeholder FrameLayout in your View layout
// (with ID fl_adplaceholder) where the ad is to be placed.
FrameLayout frameLayout =
findViewById(R.id.fl_adplaceholder);
// Assumes that your ad layout is in a file call native_ad_layout.xml
// in the res/layout folder
NativeAdView adView = (NativeAdView) getLayoutInflater()
.inflate(R.layout.native_ad_layout, null);
// This method sets the assets into the ad view.
populateNativeAdView(nativeAd, adView);
frameLayout.removeAllViews();
frameLayout.addView(adView);
}
});
Kotlin
val builder = AdLoader.Builder(this, "ca-app-pub-3940256099942544/2247696110")
.forNativeAd { nativeAd ->
// Assumes you have a placeholder FrameLayout in your View layout
// (with ID fl_adplaceholder) where the ad is to be placed.
val frameLayout: FrameLayout = findViewById(R.id.fl_adplaceholder)
// Assumes that your ad layout is in a file call native_ad_layout.xml
// in the res/layout folder
val adView = layoutInflater
.inflate(R.layout.native_ad_layout, null) as NativeAdView
// This method sets the assets into the ad view.
populateNativeAdView(nativeAd, adView)
frameLayout.removeAllViews()
frameLayout.addView(adView)
}
Jetpack Compose
@Composable
/** Load and display a native ad. */
fun NativeScreen() {
var nativeAd by remember { mutableStateOf<NativeAd?>(null) }
val context = LocalContext.current
var isDisposed by remember { mutableStateOf(false) }
DisposableEffect(Unit) {
// Load the native ad when we launch this screen
loadNativeAd(
context = context,
onAdLoaded = { ad ->
// Handle the native ad being loaded.
if (!isDisposed) {
nativeAd = ad
} else {
// Destroy the native ad if loaded after the screen is disposed.
ad.destroy()
}
},
)
// Destroy the native ad to prevent memory leaks when we dispose of this screen.
onDispose {
isDisposed = true
nativeAd?.destroy()
nativeAd = null
}
}
// Display the native ad view with a user defined template.
nativeAd?.let { adValue -> DisplayNativeAdView(adValue) }
}
fun loadNativeAd(context: Context, onAdLoaded: (NativeAd) -> Unit) {
val adLoader =
AdLoader.Builder(context, NATIVE_AD_UNIT_ID)
.forNativeAd { nativeAd -> onAdLoaded(nativeAd) }
.withAdListener(
object : AdListener() {
override fun onAdFailedToLoad(error: LoadAdError) {
Log.e(TAG, "Native ad failed to load: ${error.message}")
}
override fun onAdLoaded() {
Log.d(TAG, "Native ad was loaded.")
}
override fun onAdImpression() {
Log.d(TAG, "Native ad recorded an impression.")
}
override fun onAdClicked() {
Log.d(TAG, "Native ad was clicked.")
}
}
)
.build()
adLoader.loadAd(AdRequest.Builder().build())
}
请注意,对于指定的原生广告,应在 NativeAdView
布局内呈现所有素材资源。当在原生广告视图布局外呈现原生广告素材资源时,Google 移动广告 SDK 就会尝试在日志中记录一条警告。
广告视图类还提供了注册每项素材资源所用视图时会用到的方法,并提供了一个用于注册 NativeAd
对象本身的方法。如果以这种方式注册视图,该 SDK 就可以自动处理诸如以下任务:
- 记录点击次数
- 当第一个像素出现在屏幕上时记录展示次数
- 显示“广告选项”叠加层
“广告选项”叠加层
该 SDK 会向每个广告视图中添加一个广告选择叠加层。请在原生广告视图中任选您喜欢的一角留出空间,用于展示自动插入的广告选择徽标。此外,广告选择叠加层一定要显眼易见,因此请选择适当的背景颜色和图片。如需详细了解此叠加层的外观和功能,请参阅原生广告字段说明。
广告标示
您必须展示广告标示,以指明相应视图是广告。请参阅我们的政策指南了解详情。
代码示例
以下是展示原生广告的步骤:
- 创建
NativeAdView
类的实例。 对于要展示的每个广告素材资源:
- 使用广告对象中的素材资源填充素材资源视图。
- 向
NativeAdView
类注册该素材资源视图。
如果您的原生广告布局包含大型媒体素材资源,请注册
MediaView
。向
NativeAdView
类注册广告对象。
以下是一个展示 NativeAd
的示例函数:
Java
private void displayNativeAd(ViewGroup parent, NativeAd ad) {
// Inflate a layout and add it to the parent ViewGroup.
LayoutInflater inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
NativeAdView adView = (NativeAdView) inflater
.inflate(R.layout.ad_layout_file, parent);
// Locate the view that will hold the headline, set its text, and call the
// NativeAdView's setHeadlineView method to register it.
TextView headlineView = adView.findViewById<TextView>(R.id.ad_headline);
headlineView.setText(ad.getHeadline());
adView.setHeadlineView(headlineView);
// Repeat the process for the other assets in the NativeAd
// using additional view objects (Buttons, ImageViews, etc).
// If the app is using a MediaView, it should be
// instantiated and passed to setMediaView. This view is a little different
// in that the asset is populated automatically, so there's one less step.
MediaView mediaView = (MediaView) adView.findViewById(R.id.ad_media);
adView.setMediaView(mediaView);
// Call the NativeAdView's setNativeAd method to register the
// NativeAdObject.
adView.setNativeAd(ad);
// Ensure that the parent view doesn't already contain an ad view.
parent.removeAllViews();
// Place the AdView into the parent.
parent.addView(adView);
}
Kotlin
fun displayNativeAd(parent: ViewGroup, ad: NativeAd) {
// Inflate a layout and add it to the parent ViewGroup.
val inflater = parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)
as LayoutInflater
val adView = inflater.inflate(R.layout.ad_layout_file, parent) as NativeAdView
// Locate the view that will hold the headline, set its text, and use the
// NativeAdView's headlineView property to register it.
val headlineView = adView.findViewById<TextView>(R.id.ad_headline)
headlineView.text = ad.headline
adView.headlineView = headlineView
// Repeat the process for the other assets in the NativeAd using
// additional view objects (Buttons, ImageViews, etc).
val mediaView = adView.findViewById<MediaView>(R.id.ad_media)
adView.mediaView = mediaView
// Call the NativeAdView's setNativeAd method to register the
// NativeAdObject.
adView.setNativeAd(ad)
// Ensure that the parent view doesn't already contain an ad view.
parent.removeAllViews()
// Place the AdView into the parent.
parent.addView(adView)
}
Jetpack Compose
@Composable
/** Display a native ad with a user defined template. */
fun DisplayNativeAdView(nativeAd: NativeAd) {
val context = LocalContext.current
Box(modifier = Modifier.padding(8.dp).wrapContentHeight(Alignment.Top)) {
// Call the NativeAdView composable to display the native ad.
NativeAdView {
// Inside the NativeAdView composable, display the native ad assets.
Column(Modifier.align(Alignment.TopStart).wrapContentHeight(Alignment.Top)) {
// Display the ad attribution.
NativeAdAttribution(text = context.getString(R.string.attribution))
Row {
// If available, display the icon asset.
nativeAd.icon?.let { icon ->
NativeAdIconView(Modifier.padding(5.dp)) {
icon.drawable?.toBitmap()?.let { bitmap ->
Image(bitmap = bitmap.asImageBitmap(), "Icon")
}
}
}
Column {
// If available, display the headline asset.
nativeAd.headline?.let {
NativeAdHeadlineView {
Text(text = it, style = MaterialTheme.typography.headlineLarge)
}
}
// If available, display the star rating asset.
nativeAd.starRating?.let {
NativeAdStarRatingView {
Text(text = "Rated $it", style = MaterialTheme.typography.labelMedium)
}
}
}
}
// If available, display the body asset.
nativeAd.body?.let { NativeAdBodyView { Text(text = it) } }
// Display the media asset.
NativeAdMediaView(Modifier.fillMaxWidth().height(500.dp).fillMaxHeight())
Row(Modifier.align(Alignment.End).padding(5.dp)) {
// If available, display the price asset.
nativeAd.price?.let {
NativeAdPriceView(Modifier.padding(5.dp).align(Alignment.CenterVertically)) {
Text(text = it)
}
}
// If available, display the store asset.
nativeAd.store?.let {
NativeAdStoreView(Modifier.padding(5.dp).align(Alignment.CenterVertically)) {
Text(text = it)
}
}
// If available, display the call to action asset.
// Note: The Jetpack Compose button implements a click handler which overrides the native
// ad click handler, causing issues. Use the NativeAdButton which does not implement a
// click handler. To handle native ad clicks, use the NativeAd AdListener onAdClicked
// callback.
nativeAd.callToAction?.let { callToAction ->
NativeAdCallToActionView(Modifier.padding(5.dp)) { NativeAdButton(text = callToAction) }
}
}
}
}
}
}
以下是各项具体任务:
扩充布局
Java
LayoutInflater inflater = (LayoutInflater) parent.getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); NativeAdView adView = (NativeAdView) inflater .inflate(R.layout.ad_layout_file, parent);
Kotlin
val inflater = parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater val adView = inflater.inflate(R.layout.ad_layout_file, parent) as NativeAdView
此代码用于填充一个 XML 布局(该布局包含的视图用于展示原生广告),然后找到对
NativeAdView
的引用。请注意,如果您的 fragment 或 activity 中有现成的NativeAdView
,也可以重复使用它;您甚至可以在不使用布局文件的情况下动态创建一个实例。填充和注册素材资源视图
下面的示例代码会找到用于显示标题的视图,使用广告对象所提供的字符串素材资源设置视图的文字,然后向
NativeAdView
对象注册该视图:Java
TextView headlineView = adView.findViewById<TextView>(R.id.ad_headline); headlineView.setText(ad.getHeadline()); adView.setHeadlineView(headlineView);
Kotlin
val headlineView = adView.findViewById<TextView>(R.id.ad_headline) headlineView.text = ad.headline adView.headlineView = headlineView
对于应用要展示的由原生广告对象所提供的每项素材资源,都应为其重复上述过程,即找到相应视图、设置其值并向广告视图类注册它。
处理点击
请勿在原生广告视图之上或内部的任何视图上实现任何自定义点击处理程序。只要您按上一部分所述正确填充和注册了素材资源视图,该 SDK 就会处理广告视图素材资源获得的点击。
如需监听点击,请实现 Google 移动广告 SDK 点击回调:
Java
AdLoader adLoader = new AdLoader.Builder(context, "ca-app-pub-3940256099942544/2247696110") // ... .withAdListener(new AdListener() { @Override public void onAdFailedToLoad(LoadAdError adError) { // Handle the failure by logging. } @Override public void onAdClicked() { // Log the click event or other custom behavior. } }) .build();
Kotlin
val adLoader = AdLoader.Builder(this, "ca-app-pub-3940256099942544/2247696110") // ... .withAdListener(object : AdListener() { override fun onAdFailedToLoad(adError: LoadAdError) { // Handle the failure. } override fun onAdClicked() { // Log the click event or other custom behavior. } }) .build()
注册 MediaView
如果您要在原生广告的布局中包含主图片素材资源,则必须使用
MediaView
素材资源,而不是ImageView
素材资源。MediaView
是一个专门用于展示主媒体素材资源(视频或图片)的View
。MediaView
可以在 XML 布局中定义,也可以动态构建。就像所有其他素材资源视图一样,它应该放在NativeAdView
的视图层次结构中。对于使用MediaView
的应用,必须向NativeAdView
注册它:Java
// Populate and register the media asset view. nativeAdView.setMediaView(nativeAdBinding.adMedia);
Kotlin
// Populate and register the media asset view. nativeAdView.mediaView = nativeAdBinding.adMedia
ImageScaleType
MediaView
类在显示图片时具有ImageScaleType
属性。如果您想在MediaView
中更改图片的缩放方式,请使用MediaView
的setImageScaleType()
方法设置相应的ImageView.ScaleType
:Java
mediaView.setImageScaleType(ImageView.ScaleType.CENTER_CROP);
Kotlin
mediaView.imageScaleType = ImageView.ScaleType.CENTER_CROP
MediaContent
MediaContent
类包含与原生广告的媒体内容相关的数据,媒体内容则通过MediaView
类展示。使用MediaContent
实例设置MediaView
mediaContent
属性时:如果有视频素材资源可用,则系统会对其进行缓冲,并开始在
MediaView
内播放。您可以通过检查hasVideoContent()
来判断是否有视频素材资源可用。如果广告不包含视频素材资源,则会改为下载
mainImage
素材资源,并将其放置在MediaView
内。
默认情况下,
mainImage
是第一个下载的图片素材资源。如果使用了setReturnUrlsForImageAssets(true)
,则mainImage
为null
,您必须将mainImage
属性设置为您手动下载的图片。请注意,仅在没有视频素材资源可用时,系统才会使用此图片。注册原生广告对象
这是最后一步,也就是向负责显示原生广告对象的视图注册该对象。
Java
adView.setNativeAd(ad);
Kotlin
adView.setNativeAd(ad)
销毁广告
展示原生广告后,销毁该广告。以下示例销毁了一个原生广告:
Java
nativeAd.destroy();
Kotlin
nativeAd.destroy()
GitHub 上的示例
原生广告的完整植入示例:
后续步骤
不妨探索以下主题: