Jetpack Compose
This guide explains how to integrate the GFP Android SDK into a UI built with Jetpack Compose.
Versions below androidx.compose:compose-bom:2024.09.03
may have a bug in Compose that could cause events like impressions or clicks to not fire correctly. To ensure proper ad integration, please use version 2024.09.03
or higher.
Getting Started
To render GFP SDK ads in a Jetpack Compose-based UI, we primarily use AndroidView. To prevent unnecessary or duplicate ad loading due to recomposition, manage the AdParam
object required for ad loading using remember
, or pass it as a parameter to the composable rendering the ad. When loading ads, use LaunchedEffect
or DisposableEffect
with AdParam
as the key to load ads via GfpAdLoader
, ensuring no duplicate requests with the same AdParam
. Once the ad is loaded, render it using either an AdView or AdManager, depending on the ad type. If you stop displaying the ad or move off-screen, release resources via AndroidView.onRelease
or DisposableEffect
.
Banner
For banners, there are two supported loading methods: one using GfpAdLoader
and one without. When using GfpAdLoader
, manage the loaded GfpBannerAdView
with State
to display the ad.
With 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(adParam) {
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()
}
)
}
}
Without GfpAdLoader
@Composable
fun BannerAdView(
adParam: AdParam,
modifier: Modifier = Modifier
) {
AndroidView(
modifier = modifier,
factory = { context ->
GfpBannerAdView(context, adParam).apply {
setAdListener(/* . . . */)
loadAd()
}
},
onRelease = { view ->
view.destroy()
}
)
}
Native Normal
The Native Normal ad in the GFP SDK currently only supports Android View rendering. In Compose environments, it is rendered using AndroidViewBinding. To integrate, you will need an xml
layout file for rendering the ad and include compose.ui:ui-viewbinding
as a dependency in your gradle setup.
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(adParam) {
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)
}
}
}
}
The layout_native_ad.xml
code is omitted.
Native Simple
Once loading is complete via GfpAdLoader
, manage the received GfpNativeSimpleAd
object using State
, and set it in the GfpNativeSimpleAdView
using AndroidView
's factory
or update
.
@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(adParam) {
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
For rewarded and interstitial ads, load the ad through AdManager
and manage the ad load completion status using State
by listening to AdEventListener
. Once loading is complete, display an ad button. The context
passed to the showAd
function needs to be cast to an Activity
. Since AndroidView
is not used for resource release, call destroy()
in DisposableEffect
's onDispose
.
Rewarded
@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(adParam) {
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
@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(adParam) {
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(contextas Activity) },
modifier = modifier
) {
Text(text = "Show Interstitial AD")
}
}
}
You can check the complete code sample in the sample app repository.