feat(live-room): 무료방 입장 전면 광고를 추가한다

This commit is contained in:
2026-04-21 14:11:24 +09:00
parent 30b3dcdce6
commit f6a94e0f7c
3 changed files with 104 additions and 0 deletions

View File

@@ -82,6 +82,15 @@ import io.agora.rtm.RtmEventListener
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers
import com.yandex.mobile.ads.common.AdError
import com.yandex.mobile.ads.common.AdRequestConfiguration
import com.yandex.mobile.ads.common.AdRequestError
import com.yandex.mobile.ads.common.ImpressionData
import com.yandex.mobile.ads.interstitial.InterstitialAd
import com.yandex.mobile.ads.interstitial.InterstitialAdEventListener
import com.yandex.mobile.ads.interstitial.InterstitialAdLoadListener
import com.yandex.mobile.ads.interstitial.InterstitialAdLoader
import kr.co.vividnext.sodalive.BuildConfig
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.agora.Agora
import kr.co.vividnext.sodalive.base.BaseActivity
@@ -172,6 +181,13 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
private var isSpeaker = false
private var hasKnownHostAbsence = false
private var isFreeRoomEntryInterstitialEligible = false
private var hasRequestedFreeRoomEntryInterstitialLoad = false
private var hasConsumedFreeRoomEntryInterstitialAttempt = false
private var isLiveRoomJoinCompleted = false
private var freeRoomEntryInterstitialAdLoader: InterstitialAdLoader? = null
private var freeRoomEntryInterstitialAd: InterstitialAd? = null
private var isCapturePrivacyMuted = false
private var isScreenRecordingActive = false
@@ -216,6 +232,35 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
val content: String
)
private val freeRoomEntryInterstitialAdLoadListener = object : InterstitialAdLoadListener {
override fun onAdLoaded(interstitialAd: InterstitialAd) {
clearFreeRoomEntryInterstitialAd()
freeRoomEntryInterstitialAd = interstitialAd
maybeShowFreeRoomEntryInterstitial()
}
override fun onAdFailedToLoad(error: AdRequestError) {
Logger.e("Free room interstitial failed to load: ${error.description}")
}
}
private val freeRoomEntryInterstitialAdEventListener = object : InterstitialAdEventListener {
override fun onAdShown() = Unit
override fun onAdFailedToShow(adError: AdError) {
Logger.e("Free room interstitial failed to show: ${adError.description}")
clearFreeRoomEntryInterstitialAd()
}
override fun onAdDismissed() {
clearFreeRoomEntryInterstitialAd()
}
override fun onAdClicked() = Unit
override fun onAdImpression(impressionData: ImpressionData?) = Unit
}
// region 채팅 금지
private var isNoChatting = false
private var isChatFrozen = false
@@ -454,6 +499,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
override fun onDestroy() {
// 액티비티 종료 전에 강제 음소거 상태를 원복한다.
clearCapturePrivacyMuteState()
releaseFreeRoomEntryInterstitial()
cropper.cleanup()
hideKeyboard {
viewModel.quitRoom(roomId) {
@@ -1141,6 +1187,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
}
viewModel.roomInfoLiveData.observe(this) { response ->
syncFreeRoomEntryInterstitial(response)
updateV2vAvailability(response)
binding.ivShield.visibility = if (response.isAdult) {
View.VISIBLE
@@ -1510,6 +1557,58 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
}
}
private fun syncFreeRoomEntryInterstitial(roomInfo: GetRoomInfoResponse) {
isFreeRoomEntryInterstitialEligible = roomInfo.isFreeRoom
if (!isFreeRoomEntryInterstitialEligible || hasRequestedFreeRoomEntryInterstitialLoad) {
return
}
val adUnitId = BuildConfig.YANDEX_INTERSTITIAL_LIVE_ROOM_AD_UNIT_ID
if (adUnitId.isBlank()) {
Logger.e("Free room interstitial blocked: ad unit id is blank.")
return
}
hasRequestedFreeRoomEntryInterstitialLoad = true
freeRoomEntryInterstitialAdLoader = InterstitialAdLoader(this).apply {
setAdLoadListener(freeRoomEntryInterstitialAdLoadListener)
}
freeRoomEntryInterstitialAdLoader?.loadAd(
AdRequestConfiguration.Builder(adUnitId).build()
)
}
private fun maybeShowFreeRoomEntryInterstitial() {
if (
!isFreeRoomEntryInterstitialEligible ||
!isLiveRoomJoinCompleted ||
hasConsumedFreeRoomEntryInterstitialAttempt ||
!isForeground ||
isFinishing ||
isDestroyed
) {
return
}
val interstitialAd = freeRoomEntryInterstitialAd ?: return
hasConsumedFreeRoomEntryInterstitialAttempt = true
interstitialAd.setAdEventListener(freeRoomEntryInterstitialAdEventListener)
interstitialAd.show(this)
}
private fun clearFreeRoomEntryInterstitialAd() {
freeRoomEntryInterstitialAd?.setAdEventListener(null)
freeRoomEntryInterstitialAd = null
}
private fun releaseFreeRoomEntryInterstitial() {
freeRoomEntryInterstitialAdLoader?.setAdLoadListener(null)
freeRoomEntryInterstitialAdLoader = null
clearFreeRoomEntryInterstitialAd()
}
private fun hideKeyboard(onAfterExecute: () -> Unit) {
handler.postDelayed({
imm.hideSoftInputFromWindow(
@@ -2908,6 +3007,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
channelName = roomInfo.channelName,
rtmChannelJoinSuccess = {
isRtmJoined = true
isLiveRoomJoinCompleted = true
// 두 채널 모두 연결 시 키보드 트릭 후 dismiss, 아니면 즉시 dismiss
if (!tryForceLayoutRefresh()) {
handler.post { loadingDialog.dismiss() }
@@ -2936,6 +3036,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
}
setHeartButtonPosition()
startPeriodicPlaybackValidation()
maybeShowFreeRoomEntryInterstitial()
},
rtmChannelJoinFail = {
agoraConnectFail()

View File

@@ -29,6 +29,7 @@ data class GetRoomInfoResponse(
@SerializedName("isActiveRoulette") val isActiveRoulette: Boolean,
@SerializedName("isCaptureRecordingAvailable") val isCaptureRecordingAvailable: Boolean = false,
@SerializedName("isChatFrozen") val isChatFrozen: Boolean = false,
@SerializedName("isFreeRoom") val isFreeRoom: Boolean,
@SerializedName("isPrivateRoom") val isPrivateRoom: Boolean,
@SerializedName("password") val password: String? = null
)