Jetpack Compose
본 가이드에서는 Jetpack Compose 기반으로 작성된 UI 에서의 GFP Android SDK 연동 방식을 설명합니다.
androidx.compose:compose-bom:2024.09.03
미만의 버전에서는 Compose 버그로 인해 impression 또는 click 등의 이벤트가 잘 발화되지 않을 수 있습니다. 정상적인 광고 연동을 위해 2024.09.03
이상의 버전을 사용해주세요.
Getting Started
Jetpack Compose 기반 UI에서의 GFP SDK 광고 렌더링은 기본적으로 AndroidView 를 사용하여 렌더링합니다. 이 때 리컴포지션으로 인한 불필요한 광고 로딩이나 중복 로딩을 방지하게 위해, 광고 로드에 필요한 AdParam
객체를 remember
로 관리하거나 광고를 렌더링 할 컴포저블의 매개 변수로 넘깁니다. 광고 로딩 시에는 GfpAdLoader
가 중복 생성되거나 동일한 AdParam
으로 중복 요청을 하지 않도록 AdParam
을 key 로 갖는 LaunchedEffect
또는 DisposiableEffect
안에서 GfpAdLoader
를 통해 광고를 로드합니다. 광고 로딩이 완료되면 광고 유형에 따라 AdView 또는 AdManager 객체를 이용해 광고를 렌더링합니다. 광고 표시를 종료하거나 화면을 벗어나는 경우에는 AndroidView.onRelease
또는 DisposableEffect
를 통해 자원을 해제합니다.
Banner
Banner 는 로드 방식에 따라 GfpAdLoader
를 사용하 는 방식과 사용하지 않는 방식을 지원합니다. GfpAdLoader
를 사용해 로딩할 경우, 로딩 완료 시에 GfpBannerAdView
를 전달받아 State
로 관리하여 광고를 표시합니다.
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
GFP SDK 의 Native Normal 광고는 아직 Android View 렌더링만을 지원하며, Compose 환경에서는 AndroidViewBinding 을 이용해 렌더링하게 됩니다. 연동 시에 광고를 렌더링 할 xml
형식의 layout 파일과 compose.ui:ui-viewbinding
의존성 및 gradle 설정이 필요합니다.
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)
}
}
}
}
layout_native_ad.xml
코드는 생략합니다.
Native Simple
GfpAdLoader
를 통해 로드가 완료되면 전달받은 GfpNativeSimpleAd
객체를 State
로 관리하고, AndroidView
의 factory
또는 update
를 통해 GfpNativeSimpleAdView
에 설정합니다.
@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
보상형과 전면형의 경우, AdManager
를 통해 광고를 로드하고 AdEventListener
로부터 전달받 은 광고 로드 완료 여부를 State
로 관리하여 로드 완료 시 광고 표시 버튼을 나타나게 합니다. 이 때 showAd
함수에 전달되는 context
는 Activity
로 캐스팅이 필요하며, 자원 해제 시에는 AndroidView
를 사용하지 않으므로 DisposableEffect
의 onDispose
를 통해 destroy()
를 호출해야 합니다.
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(context as Activity) },
modifier = modifier
) {
Text(text = "Show Interstitial AD")
}
}
}
전체 코드 샘플은 샘플앱 저장소에서 확인하실 수 있습니다.