Skip to main content

Jetpack Compose

This guide explains how to integrate the NAM Android SDK into a UI built with Jetpack Compose.

Getting Started

Ad rendering in Jetpack Compose-based UIs uses AndroidView. To prevent duplicate ads from being loaded due to recomposition, we recommend managing the ad loader and ad objects in the remember state. Also, when displaying an ad or leaving the screen, you should free resources using functions like AndroidView.onRelease or DisposableEffect.


Banner ads support both loading methods: using GfpAdLoader and not using it. When loading with GfpAdLoader, manage the loaded GfpBannerAdView as a state and display the ad.

Loading Banner Ads Using GfpBannerAdView

@Composable
fun BannerAdView(
adParam: AdParam,
modifier: Modifier = Modifier
) {
AndroidView(
modifier = modifier,
factory = { context ->
GfpBannerAdView(context, adParam).apply {
setAdListener(/* . . . */)
loadAd()
}
},
onRelease = { view ->
view.destroy()
}
)
}

Loading Banner Ads Using GfpAdLoader

@Composable
fun BannerAdView(
adParam: AdParam,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
var adLoader by remember { mutableStateOf<GfpAdLoader?>(null) }
var bannerAdView by remember { mutableStateOf<GfpBannerAdView?>(null) }

LaunchedEffect(Unit) {
adLoader = GfpAdLoader.Builder(context, adParam)
.withAdListener(/* . . . */)
.withBannerAd {
bannerAdView = it
}
.build()
.also { loadAd() }
}

bannerAdView?.let { adView ->
AndroidView(
modifier = modifier,
factory = { adView },
onRelease = { view ->
view.destroy()
adLoader?.cancel()
}
)
}
}

Native Ads

NAM SDK's native ads currently only support Android View rendering. In a Compose environment, they are rendered using AndroidViewBinding. For integration, you will need an xml layout file to render the ad, as well as the compose.ui:ui-viewbinding dependency and gradle configuration.

buildFeatures {
compose = true
viewBinding = true
}
dependencies {
// . . .
implementation("androidx.compose.ui:ui-viewbinding:<compose-version>")
}
@Composable
fun NativeAdView(
adParam: AdParam,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
var adLoader by remember { mutableStateOf<GfpAdLoader?>(null) }
var nativeAd by remember { mutableStateOf<GfpNativeAd?>(null) }

LaunchedEffect(Unit) {
adLoader = GfpAdLoader.Builder(context, adParam)
.withAdListener(/* . . . */)
.withNativeAd {
nativeAd = it
}
.build()
.also { loadAd() }
}

nativeAd?.let { ad ->
AndroidViewBinding(
factory = LayoutNativeAdBinding::inflate,
modifier = modifier,
onRelease = { adLoader?.cancel() }
) {
with(nativeAdView) {
assetsContainer = assetsContainerLayout
adChoicesView = adChoices
mediaView = media
titleView = title.apply { text = ad.title }
bodyView = body.apply { text = ad.body }
callToActionView = callToAction.apply { text = ad.callToAction }
advertiserView = advertiser.apply { text = ad.advertiserName }
iconView = icon.apply {
ad.icon?.let { setImageDrawable(it.drawable) } ?: run { visibility = GONE }
}
socialContextView = socialContext.apply {
ad.socialContext?.let { text = it } ?: run { visibility = GONE }
}
noticeView = notice.apply {
ad.notice?.let { text = it } ?: run { visibility = GONE }
}
setNativeAd(ad)
}
}
}
}
info

The layout_native_ad.xml code is omitted.


Native Simple Ads

Once loading is completed through GfpAdLoader, manage the received GfpNativeSimpleAd object as a state to ensure it is safe for recomposition. Then, set it to GfpNativeSimpleAdView using factory or update in AndroidView.

@Composable
fun NativeSimpleAdView(
adParam: AdParam,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
var adLoader by remember { mutableStateOf<GfpAdLoader?>(null) }
var nativeSimpleAd by remember { mutableStateOf<GfpNativeSimpleAd?>(null) }

LaunchedEffect(Unit) {
adLoader = GfpAdLoader.Builder(context, adParam)
.withAdListener(/* . . . */)
.withNativeSimpleAd {
nativeSimpleAd = it
}
.build()
.also { loadAd() }
}

nativeSimpleAd?.let { ad ->
AndroidView(
modifier = modifier,
factory = { context -> GfpNativeSimpleAdView(context) },
update = { view -> view.setNativeSimpleAd(ad) },
onRelease = { adLoader?.cancel() }
)
}
}

Rewarded & Interstitial Ads

For rewarded and interstitial ads, load ads using AdManager and manage the ad load completion status received from AdEventListener as a state. Once the ad is loaded, display the ad button. In this case, the context passed to the showAd() function needs to be cast to Activity. When releasing resources, ensure to call destroy() using DisposableEffect.onDispose() or similar methods.

Rewarded Ads

@Composable
fun RewardedAdView(
adParam: AdParam,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
var adManager by remember { mutableStateOf<GfpRewardedAdManager?>(null) }
var isAdLoaded by remember { mutableStateOf(false) }

DisposableEffect(Unit) {
adManager = GfpRewardedAdManager(context, adParam).apply {
setAdListener(object : RewardedAdListener() {
override fun onAdLoaded(ad: GfpRewardedAd) {
isAdLoaded = true
}
})
loadAd()
}

onDispose {
adManager?.destroy()
}
}

if (isAdLoaded) {
Button(
onClick = { adManager?.showAd(context as Activity) },
modifier = modifier
) {
Text(text = "Show Rewarded AD")
}
}
}

Interstitial Ads

@Composable
fun InterstitialAdView(
adParam: AdParam,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
var adManager by remember { mutableStateOf<GfpInterstitialAdManager?>(null) }
var isAdLoaded by remember { mutableStateOf(false) }

DisposableEffect(Unit) {
adManager = GfpInterstitialAdManager(context, adParam).apply {
setAdListener(object : InterstitialAdListener() {
override fun onAdLoaded(ad: GfpInterstitialAd) {
isAdLoaded = true
}
})
loadAd()
}

onDispose {
adManager?.destroy()
}
}

if (isAdLoaded) {
Button(
onClick = { adManager?.showAd(context as Activity) },
modifier = modifier
) {
Text(text = "Show Interstitial AD")
}
}
}
warning

In versions below androidx.compose:compose-bom:2024.09.03, events such as impression or click may not trigger properly due to a Compose bug. For proper ad integration, please use version 2024.09.03 or higher.