feat(mypage): 최하단에 배너 광고 추가
This commit is contained in:
@@ -15,6 +15,15 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.google.gson.Gson
|
||||
import com.orhanobut.logger.Logger
|
||||
import droom.daro.core.adunit.DaroBannerAdUnit
|
||||
import droom.daro.core.model.DaroAdInfo
|
||||
import droom.daro.core.model.DaroAdLoadError
|
||||
import droom.daro.core.model.DaroBannerSize
|
||||
import droom.daro.core.model.DaroViewAd
|
||||
import droom.daro.view.DaroAdViewListener
|
||||
import droom.daro.view.DaroBannerAdView
|
||||
import kr.co.vividnext.sodalive.BuildConfig
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.box.AudioContentBoxActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||
@@ -57,6 +66,9 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
||||
|
||||
companion object {
|
||||
private const val FUNCTION_BUTTON_SPAN_COUNT = 4
|
||||
|
||||
private const val DARO_BANNER_AD_UNIT_KEY = "43df2529-31d8-45f8-a17d-1a760f5bc777"
|
||||
private const val DARO_BANNER_PLACEMENT = "MyPage"
|
||||
}
|
||||
|
||||
private val viewModel: MyPageViewModel by inject()
|
||||
@@ -64,6 +76,7 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private val functionButtonAdapter = FunctionButtonAdapter()
|
||||
private var daroBannerAdView: DaroBannerAdView? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -73,6 +86,71 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
||||
bindData()
|
||||
setupRecentContentSection()
|
||||
setupLatestNotice()
|
||||
setupDaroBottomBanner()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
daroBannerAdView?.destroy()
|
||||
daroBannerAdView = null
|
||||
binding.flDaroBannerContainer.removeAllViews()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupDaroBottomBanner() {
|
||||
binding.flDaroBannerContainer.visibility = View.GONE
|
||||
binding.flDaroBannerContainer.removeAllViews()
|
||||
|
||||
val adUnit = DaroBannerAdUnit(
|
||||
key = DARO_BANNER_AD_UNIT_KEY,
|
||||
placement = DARO_BANNER_PLACEMENT,
|
||||
bannerSize = DaroBannerSize.Banner
|
||||
)
|
||||
|
||||
val adView = DaroBannerAdView(
|
||||
context = requireContext(),
|
||||
adUnit = adUnit
|
||||
).apply {
|
||||
setListener(object : DaroAdViewListener {
|
||||
override fun onAdImpression(adInfo: DaroAdInfo) = Unit
|
||||
|
||||
override fun onAdClicked(adInfo: DaroAdInfo) = Unit
|
||||
|
||||
override fun onAdLoadSuccess(ad: DaroViewAd, adInfo: DaroAdInfo) {
|
||||
binding.flDaroBannerContainer.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun onAdLoadFail(err: DaroAdLoadError) {
|
||||
handleDaroBannerLoadFail(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
daroBannerAdView = adView
|
||||
binding.flDaroBannerContainer.addView(adView)
|
||||
adView.loadAd()
|
||||
}
|
||||
|
||||
private fun handleDaroBannerLoadFail(err: DaroAdLoadError) {
|
||||
binding.flDaroBannerContainer.visibility = View.GONE
|
||||
|
||||
Logger.w(
|
||||
"Daro banner load failed. package=${BuildConfig.APPLICATION_ID}, placement=$DARO_BANNER_PLACEMENT"
|
||||
)
|
||||
Logger.w(
|
||||
"Daro banner load failed. code=${err.code}, message=${err.message}"
|
||||
)
|
||||
|
||||
if (err.message.contains("no fill", ignoreCase = true)) {
|
||||
Logger.w(
|
||||
"Daro no fill. Verify app-ads.txt, Live status, registered package=${BuildConfig.APPLICATION_ID}"
|
||||
)
|
||||
|
||||
if (BuildConfig.DEBUG && BuildConfig.APPLICATION_ID.endsWith(".debug")) {
|
||||
Logger.w(
|
||||
"Debug package differs from release. Register ${BuildConfig.APPLICATION_ID} in Daro or test release package."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupLatestNotice() {
|
||||
|
||||
@@ -346,6 +346,15 @@
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="24dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Daro bottom banner container -->
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_daro_banner_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
44
docs/20260420_마이페이지배너광고추가.md
Normal file
44
docs/20260420_마이페이지배너광고추가.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# 20260420 마이페이지 배너 광고 추가
|
||||
|
||||
## 작업 체크리스트
|
||||
- [x] Daro 공식 Android 배너 가이드와 현재 프로젝트의 광고 기본 세팅 상태를 확인한다.
|
||||
QA: 배너 뷰 타입, 필수 값, 기존 SDK 초기화/플러그인 상태를 근거 파일로 설명할 수 있어야 한다.
|
||||
- [x] `fragment_my.xml` 최하단에 배너 광고 영역을 추가한다.
|
||||
QA: 기존 MyPage 콘텐츠 하단에 배너 광고 뷰가 배치되고, 화면 레이아웃을 깨지 않아야 한다.
|
||||
- [x] `MyPageFragment.kt`에 배너 광고 로드/정리 로직과 임시 설정값 위치 안내를 추가한다.
|
||||
QA: 사용자가 교체해야 하는 값이 코드에서 명확히 드러나고, Fragment 생명주기에 맞는 정리 처리가 있어야 한다.
|
||||
- [x] 변경 사항을 진단하고 필요한 Gradle 검증을 수행한 뒤 결과를 기록한다.
|
||||
QA: 변경 파일 진단 결과와 실행한 검증 명령/결과가 문서 하단에 누적 기록되어야 한다.
|
||||
|
||||
## 임시 설정값 위치
|
||||
- `app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageFragment.kt`
|
||||
- `DARO_BANNER_AD_UNIT_KEY`
|
||||
- `DARO_BANNER_PLACEMENT`
|
||||
- 위 두 상수를 실제 Daro 배너 값으로 교체하면 된다.
|
||||
|
||||
## 검증 기록
|
||||
- 2026-04-20
|
||||
- 무엇: `fragment_my.xml` 최하단에 Daro 배너 컨테이너를 추가하고, `MyPageFragment`에서 `DaroBannerAdView`를 생성해 로드/정리하도록 구현했다.
|
||||
- 왜: 공식 Daro Android 배너 가이드가 XML 커스텀 태그 대신 컨테이너 뷰 + 코드 생성 방식의 `DaroBannerAdView` 사용을 요구했고, 요청 위치가 MyPage 최하단이었기 때문이다.
|
||||
- 어떻게:
|
||||
- 수정 파일: `app/src/main/res/layout/fragment_my.xml`, `app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageFragment.kt`, `docs/20260420_마이페이지배너광고추가.md`
|
||||
- 임시 값 위치: `MyPageFragment.kt`의 `DARO_BANNER_AD_UNIT_KEY`, `DARO_BANNER_PLACEMENT`
|
||||
- 진단 도구: Kotlin/XML LSP 서버 미구성으로 `lsp_diagnostics`는 실행 불가였다.
|
||||
- 실행 명령: `./gradlew :app:assembleDebug`
|
||||
- 결과: 성공. Daro 플러그인 설정과 앱 debug 빌드가 모두 완료됐다.
|
||||
- 실행 명령: `./gradlew :app:ktlintCheck`
|
||||
- 결과: 실패. 이번 변경 파일이 아니라 기존 파일들(`NicknameUpdateViewModel.kt`, `ProfileUpdateActivity.kt`, `RecentContentDao.kt` 등)의 스타일 오류 때문에 `:app:ktlintMainSourceSetCheck`가 실패했다.
|
||||
- 실행 명령: `adb devices`
|
||||
- 결과: 연결된 기기가 없어 실제 화면 수동 확인은 이 환경에서 진행하지 못했다.
|
||||
- 2026-04-20
|
||||
- 무엇: MyPage Daro 배너의 `No fill` 원인을 추가 조사하고, 배너 로드 실패 시 진단 로그가 남도록 `MyPageFragment`를 보강했다.
|
||||
- 왜: 공식 Daro 문서와 SDK 소스 기준으로 `No fill`은 코드 버그보다 `app-ads.txt`, 앱/광고 단위 Live 상태, 등록 패키지 불일치 같은 송출 조건 이슈 가능성이 더 높았고, 기존 코드는 실패를 조용히 숨기고 있었다.
|
||||
- 어떻게:
|
||||
- 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageFragment.kt`, `docs/20260420_마이페이지배너광고추가.md`
|
||||
- 조사 근거: Daro 공식 FAQ/배너 가이드, SDK `DaroAdLoader.kt`의 `no fill` 처리 메시지, debug merged manifest의 패키지 `kr.co.vividnext.sodalive.debug`, release merged manifest의 패키지 `kr.co.vividnext.sodalive`
|
||||
- 확인 사항: 저장소 내 `app-ads.txt` 파일은 없었고, debug 빌드는 `applicationIdSuffix '.debug'`로 인해 release 패키지와 다른 앱 ID를 사용한다.
|
||||
- 적용 내용: `No fill` 발생 시 현재 `APPLICATION_ID`, placement, 에러 코드/메시지와 함께 `app-ads.txt`, Live 상태, 등록 패키지 확인이 필요하다는 로그를 남기고, debug 패키지(`.debug`)면 별도 등록 또는 release 패키지 테스트 필요 로그를 추가했다.
|
||||
- 실행 명령: `./gradlew :app:assembleDebug`
|
||||
- 결과: 성공. 진단 로그 추가 후에도 debug 빌드는 정상 완료됐다.
|
||||
- 실행 명령: `./gradlew :app:ktlintCheck`
|
||||
- 결과: 성공. `MyPageFragment.kt`의 로그 문자열 줄 길이를 정리한 뒤 lint를 통과했다.
|
||||
Reference in New Issue
Block a user