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
@@ -0,0 +1,16 @@
<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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<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>
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@

package com.google.android.gms.snippets

import android.app.Activity
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
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.NativeAd
import com.google.android.gms.ads.nativead.NativeAdOptions
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

/** Kotlin code snippets for the developer guide. */
internal class NativeAdSnippets {
Expand Down Expand Up @@ -97,6 +98,106 @@ internal class NativeAdSnippets {
// [END handle_ad_loaded]
}

private fun handleAdLoadedWithDisplay(
adLoaderBuilder: AdLoader.Builder,
activity: Activity,
layoutInflater: LayoutInflater,
layoutPlaceholder: FrameLayout,
) {
// [START handle_ad_loaded_with_display]
adLoaderBuilder
.forNativeAd { nativeAd ->
// This callback is invoked when a native ad is successfully loaded.
activity.runOnUiThread {
val nativeAdBinding = NativeAdBinding.inflate(layoutInflater)
val adView = nativeAdBinding.root

// Populate and register the native ad asset views.
displayNativeAdView(nativeAd, nativeAdBinding)

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

private fun displayNativeAdView(nativeAd: NativeAd, nativeAdBinding: NativeAdBinding) {
// [START display_native_ad]
val nativeAdView = nativeAdBinding.root

// Set the media view.
nativeAdView.mediaView = nativeAdBinding.adMedia

// Set other ad assets.
nativeAdView.headlineView = nativeAdBinding.adHeadline
nativeAdView.bodyView = nativeAdBinding.adBody
nativeAdView.callToActionView = nativeAdBinding.adCallToAction
nativeAdView.iconView = nativeAdBinding.adAppIcon
nativeAdView.priceView = nativeAdBinding.adPrice
nativeAdView.starRatingView = nativeAdBinding.adStars
nativeAdView.storeView = nativeAdBinding.adStore
nativeAdView.advertiserView = nativeAdBinding.adAdvertiser

nativeAdBinding.adHeadline.text = nativeAd.headline
nativeAd.mediaContent?.let { nativeAdBinding.adMedia.setMediaContent(it) }

if (nativeAd.body == null) {
nativeAdBinding.adBody.visibility = View.INVISIBLE
} else {
nativeAdBinding.adBody.text = nativeAd.body
nativeAdBinding.adBody.visibility = View.VISIBLE
}

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

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

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

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

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

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

nativeAdView.setNativeAd(nativeAd)
// [END display_native_ad]
}

private fun destroyAd(nativeAd: NativeAd) {
// [START destroy_ad]
nativeAd.destroy()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// 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 load_native_ad_for_display]
@Composable
fun loadAndDisplayNativeAd() {
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())
}

// [END load_native_ad_for_display]

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"
}
}
Loading