Skip to content

Commit 390ce5c

Browse files
authored
[FEAT/#730] 피드백 확인 전면 광고 구현 (#736)
1 parent 8839aee commit 390ce5c

File tree

17 files changed

+197
-38
lines changed

17 files changed

+197
-38
lines changed

build-logic/convention/src/main/kotlin/com/hilingual/buildlogic/BuildType.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ fun Project.configureBuildTypes(
4949
"ADMOB_NATIVE_UNIT_ID",
5050
properties.getQuotedProperty("admob.native.$prefix.id")
5151
)
52+
buildConfigField(
53+
"String",
54+
"ADMOB_INTERSTITIAL_UNIT_ID",
55+
properties.getQuotedProperty("admob.interstitial.$prefix.id")
56+
)
5257
}
5358

5459
commonExtension.apply {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.hilingual.core.ads.interstitial
2+
3+
import android.app.Activity
4+
import com.google.android.libraries.ads.mobile.sdk.common.AdLoadCallback
5+
import com.google.android.libraries.ads.mobile.sdk.common.AdRequest
6+
import com.google.android.libraries.ads.mobile.sdk.common.FullScreenContentError
7+
import com.google.android.libraries.ads.mobile.sdk.common.LoadAdError
8+
import com.google.android.libraries.ads.mobile.sdk.interstitial.InterstitialAd
9+
import com.google.android.libraries.ads.mobile.sdk.interstitial.InterstitialAdEventCallback
10+
import com.google.android.libraries.ads.mobile.sdk.interstitial.InterstitialAdPreloader
11+
import timber.log.Timber
12+
13+
fun showInterstitialAd(
14+
activity: Activity,
15+
adUnitId: String,
16+
onAdDismissed: () -> Unit,
17+
) {
18+
val preloadedAd = InterstitialAdPreloader.pollAd(adUnitId)
19+
20+
if (preloadedAd != null) {
21+
Timber.tag("GMA").d("프리로드된 전면 광고를 표시합니다.")
22+
preloadedAd.adEventCallback = createEventCallback(onAdDismissed)
23+
preloadedAd.show(activity)
24+
} else {
25+
Timber.tag("GMA").d("프리로드된 광고 없음, 새로 로드 후 표시합니다.")
26+
val adRequest = AdRequest.Builder(adUnitId).build()
27+
InterstitialAd.load(
28+
adRequest,
29+
object : AdLoadCallback<InterstitialAd> {
30+
override fun onAdLoaded(ad: InterstitialAd) {
31+
if (!activity.isFinishing && !activity.isDestroyed) {
32+
ad.adEventCallback = createEventCallback(onAdDismissed)
33+
ad.show(activity)
34+
} else {
35+
Timber.tag("GMA").w("Activity가 이미 종료 상태라 전면 광고를 표시하지 않습니다.")
36+
onAdDismissed()
37+
}
38+
}
39+
40+
override fun onAdFailedToLoad(adError: LoadAdError) {
41+
Timber.tag("GMA").e("전면 광고 로드 실패: %s", adError)
42+
onAdDismissed()
43+
}
44+
},
45+
)
46+
}
47+
}
48+
49+
private fun createEventCallback(onAdDismissed: () -> Unit) = object : InterstitialAdEventCallback {
50+
override fun onAdDismissedFullScreenContent() {
51+
Timber.tag("GMA").d("전면 광고 닫힘 → 피드백 화면으로 이동")
52+
onAdDismissed()
53+
}
54+
55+
override fun onAdFailedToShowFullScreenContent(fullScreenContentError: FullScreenContentError) {
56+
Timber.tag("GMA").e("전면 광고 표시 실패: %s", fullScreenContentError)
57+
onAdDismissed()
58+
}
59+
}

core/ads/src/main/java/com/hilingual/core/ads/manager/AdsPreloadManager.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ import com.hilingual.core.ads.banner.BannerAdType
44

55
interface AdsPreloadManager {
66
fun preloadBanner(type: BannerAdType)
7+
fun preloadInterstitial(adUnitId: String)
78
}

core/ads/src/main/java/com/hilingual/core/ads/manager/AdsPreloadManagerImpl.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import android.content.Context
44
import com.google.android.libraries.ads.mobile.sdk.banner.AdSize
55
import com.google.android.libraries.ads.mobile.sdk.banner.BannerAdPreloader
66
import com.google.android.libraries.ads.mobile.sdk.banner.BannerAdRequest
7+
import com.google.android.libraries.ads.mobile.sdk.common.AdRequest
78
import com.google.android.libraries.ads.mobile.sdk.common.PreloadConfiguration
9+
import com.google.android.libraries.ads.mobile.sdk.interstitial.InterstitialAdPreloader
810
import com.hilingual.core.ads.banner.BannerAdType
911
import com.hilingual.core.ads.utils.screenWidthDp
1012
import dagger.hilt.android.qualifiers.ApplicationContext
@@ -36,4 +38,16 @@ internal class AdsPreloadManagerImpl @Inject constructor(
3638
Timber.tag("GMA").e(e, "배너 프리로딩 시작 실패: %s", type.adUnitId)
3739
}
3840
}
41+
42+
override fun preloadInterstitial(adUnitId: String) {
43+
try {
44+
val adRequest = AdRequest.Builder(adUnitId).build()
45+
val preloadConfig = PreloadConfiguration(adRequest)
46+
47+
InterstitialAdPreloader.start(adUnitId, preloadConfig)
48+
Timber.tag("GMA").d("GMA Next Gen 전면 광고 프리로딩 시작: %s", adUnitId)
49+
} catch (e: Exception) {
50+
Timber.tag("GMA").e(e, "전면 광고 프리로딩 실패: %s", adUnitId)
51+
}
52+
}
3953
}

data/diary/src/main/java/com/hilingual/data/diary/datasource/DiaryRemoteDataSource.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,8 @@ interface DiaryRemoteDataSource {
5757
suspend fun deleteDiary(
5858
diaryId: Long,
5959
): BaseResponse<Unit>
60+
61+
suspend fun patchAdWatch(
62+
diaryId: Long,
63+
): BaseResponse<Unit>
6064
}

data/diary/src/main/java/com/hilingual/data/diary/datasourceimpl/DiaryRemoteDataSourceImpl.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,7 @@ internal class DiaryRemoteDataSourceImpl @Inject constructor(
8181

8282
override suspend fun deleteDiary(diaryId: Long): BaseResponse<Unit> =
8383
diaryService.deleteDiary(diaryId)
84+
85+
override suspend fun patchAdWatch(diaryId: Long): BaseResponse<Unit> =
86+
diaryService.patchAdWatch(diaryId)
8487
}

data/diary/src/main/java/com/hilingual/data/diary/dto/response/DiaryContentResponseDto.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ data class DiaryContentResponseDto(
3232
val imageUrl: String?,
3333
@SerialName("isPublished")
3434
val isPublished: Boolean,
35+
/*TODO:: isAdWatched — 서버 연결 시 추가*/
3536
)
3637

3738
@Serializable

data/diary/src/main/java/com/hilingual/data/diary/model/DiaryModel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ data class DiaryContentModel(
2424
val diffRanges: List<DiaryContentFeedback>,
2525
val imageUrl: String?,
2626
val isPublished: Boolean,
27+
val isAdWatched: Boolean,
2728
)
2829

2930
data class DiaryContentFeedback(
@@ -41,4 +42,5 @@ internal fun DiaryContentResponseDto.toModel() = DiaryContentModel(
4142
)
4243
},
4344
isPublished = this.isPublished,
45+
isAdWatched = false, // TODO:: 서버 연결 시 this.isAdWatched로 교체
4446
)

data/diary/src/main/java/com/hilingual/data/diary/repository/DiaryRepository.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,8 @@ interface DiaryRepository {
5454
suspend fun deleteDiary(
5555
diaryId: Long,
5656
): Result<Unit>
57+
58+
suspend fun patchAdWatch(
59+
diaryId: Long,
60+
): Result<Unit>
5761
}

data/diary/src/main/java/com/hilingual/data/diary/repositoryimpl/DiaryRepositoryImpl.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,9 @@ internal class DiaryRepositoryImpl @Inject constructor(
9999
suspendRunCatching {
100100
diaryRemoteDataSource.deleteDiary(diaryId)
101101
}
102+
103+
override suspend fun patchAdWatch(diaryId: Long): Result<Unit> =
104+
suspendRunCatching {
105+
diaryRemoteDataSource.patchAdWatch(diaryId)
106+
}
102107
}

0 commit comments

Comments
 (0)