Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,56 @@

package com.google.android.gms.snippets

import android.content.Context
import android.app.Activity
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdLoader
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.admanager.AdManagerAdRequest
import com.google.android.gms.ads.nativead.MediaView
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdOptions
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import com.google.android.gms.example.apidemo.databinding.NativeAdBinding

/** Kotlin code snippets for the developer guide. */
internal class NativeAdSnippets {

private fun createAdLoader(context: Context) {
// [START create_ad_loader]
// It is recommended to call AdLoader.Builder on a background thread.
CoroutineScope(Dispatchers.IO).launch {
val adLoader =
AdLoader.Builder(context, AD_UNIT_ID)
.forNativeAd { nativeAd ->
// The native ad loaded successfully. You can show the ad.
}
.withAdListener(
object : AdListener() {
override fun onAdFailedToLoad(adError: LoadAdError) {
// The native ad load failed. Check the adError message for failure reasons.
}
}
)
// Use the NativeAdOptions.Builder class to specify individual options settings.
.withNativeAdOptions(NativeAdOptions.Builder().build())
.build()
}
// [END create_ad_loader]
}

private fun setAdLoaderListener(adLoaderBuilder: AdLoader.Builder) {
// [START set_ad_listener]
adLoaderBuilder.withAdListener(
// Override AdListener callbacks here.
object : AdListener() {}
object : AdListener() {
override fun onAdClosed() {
// Called when the ad is closed.
}

override fun onAdFailedToLoad(adError: LoadAdError) {
// Called when an ad fails to load.
}

override fun onAdOpened() {
// Called when an ad opens full screen.
}

override fun onAdLoaded() {
// Called when an ad has loaded.
}

override fun onAdClicked() {
// Called when a click is recorded for an ad.
}

override fun onAdImpression() {
// Called when an impression is recorded for an ad.
}

override fun onAdSwipeGestureClicked() {
// Called when a swipe gesture is recorded for an ad.
}
}
)
// [END set_ad_listener]
}
Expand Down Expand Up @@ -97,20 +104,162 @@ internal class NativeAdSnippets {
// [END handle_ad_loaded]
}

private fun addNativeAdView(
activity: Activity,
nativeAd: NativeAd,
layoutInflater: LayoutInflater,
frameLayout: FrameLayout,
) {
// [START add_ad_view]
activity.runOnUiThread {
// Inflate the native ad view and add it to the view hierarchy.
val nativeAdBinding = NativeAdBinding.inflate(layoutInflater)
val adView = nativeAdBinding.root

// Display and register the native ad asset views here.
displayAndRegisterNativeAd(nativeAd, nativeAdBinding)

// Remove all old ad views and add the new native.
frameLayout.removeAllViews()
// Add the new native ad view to the view hierarchy.
frameLayout.addView(adView)
}
// [END add_ad_view]
}

// [START display_native_ad]
private fun displayAndRegisterNativeAd(nativeAd: NativeAd, nativeAdBinding: NativeAdBinding) {
// [START populate_native_ad_view]
// Populate all native ad view assets with the native ad.
nativeAdBinding.adMedia.mediaContent = nativeAd.mediaContent
nativeAdBinding.adAdvertiser.text = nativeAd.advertiser
nativeAdBinding.adBody.text = nativeAd.body
nativeAdBinding.adCallToAction.text = nativeAd.callToAction
nativeAdBinding.adHeadline.text = nativeAd.headline
nativeAdBinding.adAppIcon.setImageDrawable(nativeAd.icon?.drawable)
nativeAdBinding.adPrice.text = nativeAd.price
nativeAd.starRating?.toFloat().also { value ->
if (value != null) {
nativeAdBinding.adStars.rating = value
}
}
nativeAdBinding.adStore.text = nativeAd.store
// [END populate_native_ad_view]

// Hide all native ad view assets that are not returned within the native ad.
if (nativeAd.body == null) {
nativeAdBinding.adBody.visibility = View.INVISIBLE
} else {
nativeAdBinding.adBody.visibility = View.VISIBLE
}

if (nativeAd.callToAction == null) {
nativeAdBinding.adCallToAction.visibility = View.INVISIBLE
} else {
nativeAdBinding.adCallToAction.visibility = View.VISIBLE
}

if (nativeAd.icon == null) {
nativeAdBinding.adAppIcon.visibility = View.GONE
} else {
nativeAdBinding.adAppIcon.visibility = View.VISIBLE
}

if (nativeAd.price == null) {
nativeAdBinding.adPrice.visibility = View.INVISIBLE
} else {
nativeAdBinding.adPrice.visibility = View.VISIBLE
}

if (nativeAd.store == null) {
nativeAdBinding.adStore.visibility = View.INVISIBLE
} else {
nativeAdBinding.adStore.visibility = View.VISIBLE
}

if (nativeAd.starRating == null) {
nativeAdBinding.adStars.visibility = View.INVISIBLE
} else {
nativeAdBinding.adStars.visibility = View.VISIBLE
}

if (nativeAd.advertiser == null) {
nativeAdBinding.adAdvertiser.visibility = View.INVISIBLE
} else {
nativeAdBinding.adAdvertiser.visibility = View.VISIBLE
}

// [START register_native_ad_assets]
// Register all native ad assets with the native ad view.
val nativeAdView = nativeAdBinding.root
nativeAdView.advertiserView = nativeAdBinding.adAdvertiser
nativeAdView.bodyView = nativeAdBinding.adBody
nativeAdView.callToActionView = nativeAdBinding.adCallToAction
nativeAdView.headlineView = nativeAdBinding.adHeadline
nativeAdView.iconView = nativeAdBinding.adAppIcon
nativeAdView.priceView = nativeAdBinding.adPrice
nativeAdView.starRatingView = nativeAdBinding.adStars
nativeAdView.storeView = nativeAdBinding.adStore
nativeAd.mediaContent?.let { nativeAdBinding.adMedia.setMediaContent(it) }
nativeAdView.mediaView = nativeAdBinding.adMedia
// [END register_native_ad_assets]

// [START set_native_ad]
// This method tells the Google Mobile Ads SDK that you have finished populating your
// native ad view with this native ad.
nativeAdView.setNativeAd(nativeAd)
// [END set_native_ad]
}

// [END display_native_ad]

private fun destroyAd(nativeAd: NativeAd) {
// [START destroy_ad]
nativeAd.destroy()
// [END destroy_ad]
}

private companion object {
// Test ad unit IDs.
// For more information,
// see https://developers.google.com/admob/android/test-ads.
// and https://developers.google.com/ad-manager/mobile-ads-sdk/android/test-ads.
const val AD_UNIT_ID = "ca-app-pub-3940256099942544/2247696110"
const val VIDEO_AD_UNIT_ID = "ca-app-pub-3940256099942544/1044960115"
const val ADMANAGER_AD_UNIT_ID = "/21775744923/example/native"
const val ADMANAGER_VIDEO_AD_UNIT_ID = "/21775744923/example/native-video"
private fun setEventCallback(adLoader: AdLoader.Builder) {
// [START set_event_callback]
adLoader
.withAdListener(
object : AdListener() {
override fun onAdClosed() {
// Called when the ad is closed.
}

override fun onAdFailedToLoad(adError: LoadAdError) {
// Called when an ad fails to load.
}

override fun onAdOpened() {
// Called when an ad opens full screen.
}

override fun onAdLoaded() {
// Called when an ad has loaded.
}

override fun onAdClicked() {
// Called when a click is recorded for an ad.
}

override fun onAdImpression() {
// Called when an impression is recorded for an ad.
}

override fun onAdSwipeGestureClicked() {
// Called when a swipe gesture is recorded for an ad.
}
}
)
.build()
// [END set_event_callback]
}

private fun setImageScaleType(mediaView: MediaView) {
// [START set_image_scale_type]
mediaView.setImageScaleType(ImageView.ScaleType.CENTER_CROP)
// [END set_image_scale_type]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright 2025 Google LLC
//
// 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
//
// https://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.jetpackcomposedemo.snippets

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import com.example.jetpackcomposedemo.R
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.compose_util.NativeAdAttribution
import com.google.android.gms.compose_util.NativeAdHeadlineView
import com.google.android.gms.compose_util.NativeAdMediaView
import com.google.android.gms.compose_util.NativeAdView

/** Kotlin code snippets for the developer guide. */
internal class NativeAdSnippets {

// [START define_native_ad_view]
@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. This is required.
NativeAdAttribution(text = context.getString(R.string.attribution))
// Display the headline asset. This is required.
nativeAd.headline?.let {
NativeAdHeadlineView { Text(text = it, style = MaterialTheme.typography.headlineLarge) }
}
// Display the media asset. This is required.
NativeAdMediaView(Modifier.fillMaxWidth().height(500.dp).fillMaxHeight())
}
}
}
}

// [END define_native_ad_view]

// [START display_native_ad_screen]
@Composable
fun DisplayNativeAdScreen(adunitId: String) {
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,
adunitId,
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()
}
},
)
// [START destroy_native_ad]
// Destroy the native ad to prevent memory leaks when we dispose of this screen.
onDispose {
isDisposed = true
nativeAd?.destroy()
nativeAd = null
}
// [END destroy_native_ad]
}

// Display the native ad view with a user defined template here.
nativeAd?.let { adValue -> DisplayNativeAdView(adValue) }
}

// [END display_native_ad_screen]

// [START load_native_ad_compose]
fun loadNativeAd(context: Context, adUnitId: String, onAdLoaded: (NativeAd) -> Unit) {
val adLoader =
AdLoader.Builder(context, adUnitId)
.forNativeAd { nativeAd -> onAdLoaded(nativeAd) }
.withAdListener(
object : AdListener() {
override fun onAdFailedToLoad(error: LoadAdError) {
// Native ad failed to load.
}

override fun onAdLoaded() {
// Native ad was loaded.
}

override fun onAdImpression() {
// Native ad recorded an impression.
}

override fun onAdClicked() {
// Native ad was clicked.
}
}
)
.build()
adLoader.loadAd(AdRequest.Builder().build())
}

// [END load_native_ad_compose]

@Composable
fun SetImageScaleType() {
// [START set_image_scale_type_compose]
NativeAdMediaView(Modifier.fillMaxWidth(), scaleType = ImageView.ScaleType.CENTER_CROP)
// [END set_image_scale_type_compose]
}
}