Skip to main content

Jetpack Compose

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

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.

Getting Started

Rendering NAM SDK ads in a Jetpack Compose-based UI is primarily done using AndroidView. To prevent unnecessary or duplicate ad loading caused by recomposition, manage the AdParam object required for ad loading as a state or pass it as a parameter to the composable rendering the ad. When loading ads, ensure that the GfpAdLoader is not recreated due to recomposition by managing it as a state, and use appropriate lifecycle-aware APIs such as LaunchedEffect or DisposableEffect to load ads through GfpAdLoader. Once the ad is loaded, render the ad using an AdView or AdManager object depending on the ad type. When stopping ad display or leaving the screen, release resources using 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")
}
}
}