Skip to content

[GMSS-343,346] Google Play 결제 연동 BillingClient 생성 및 단위 테스트 구축 - #79

Merged
soyeonLee126 merged 18 commits into
developfrom
feature/billing-client
Nov 11, 2026
Merged

soyeonLee126 merged 18 commits into
developfrom
feature/billing-client

Conversation

@seunghee17

@seunghee17 seunghee17 commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

작업 개요

Google Play 결제 연동(Billing Library 9.1.0)을 위한 core:billing 모듈을 추가했습니다. 이번 PR 범위는 BillingClient 생성(DI) + 단위 테스트 구축까지이며, 실제 구매 화면/서버 연동은 포함하지 않습니다.

작업 유형

  • feat: 새 기능
  • refactor: 리팩토링 (동작 변경 없음)
  • test: 테스트 추가/수정
  • build: 빌드/의존성 설정

변경 사항

  • core:billing 모듈 신규 추가 — BillingRepository(connect/endConnection/queryProductDetails/launchPurchaseFlow/queryUnfinishedPurchases/consumePurchase)
  • PlayBillingDataSource/PlayBillingDataSourceImpl로 BillingClient SDK 콜백 호출 계층을 분리 — Repository는 SDK를 몰라도 되고, 테스트에서 Fake로 교체 가능
  • BillingPurchaseOutcomeMapper — 응답코드(OK+PURCHASED/PENDING, USER_CANCELED, ITEM_ALREADY_OWNED 등)를 도메인 상태로 매핑
  • 단위 테스트 16개 추가 (PlayBillingRepositoryTest 10개, BillingPurchaseOutcomeMapperTest 6개) — FakeBillingDataSource 기반
  • 디버그 전용 BillingDebugActivity 추가 — 구글 정적 테스트 상품으로 연결/상품조회/구매/복구조회/consume을 수동 검증 (adb로만 실행, 프로덕션 미노출)
  • Billing Library 9.1.0 의존성 추가

관련 이슈

  • Closes #

관련 작업 (Notion)

스크린샷 / 동작 화면

체크리스트

  • base 브랜치가 develop으로 설정되어 있다
  • 로컬 빌드 및 실행을 확인했다 (:core:billing:testDebugUnitTest, :core:billing:detekt, :app:compileDebugKotlin 통과, 실기기에서 디버그 화면 실행 확인)
  • 커밋 메시지가 컨벤션(feat:, fix: 등)을 따른다
  • 불필요한 로그/주석/디버그 코드를 제거했다
  • 리뷰어가 이해할 수 있도록 설명을 작성했다

리뷰 요청 사항

  • PlayBillingRepository.endConnection() 호출 후에도 내부 Flow 구독 코루틴이 취소되지 않아, SDK가 뒤늦게 보내는 연결 콜백(onBillingServiceDisconnected)이 CLOSED 상태를 덮어쓸 수 있는 레이스가 있습니다. 현재는 endConnection()을 호출하는 생명주기 연동 코드가 없어 실질적 영향은 없지만, 실제 화면/앱 생명주기 연동 시점에 다시 다룰 예정입니다.
  • 구글 예약 테스트 상품(android.test.*)은 queryProductDetailsAsync(Billing Library v5+)로 조회되지 않아 디버그 화면에서 실제 구매창까지는 확인하지 못했습니다. Play Console 상품 등록 + License Testing이 필요한 별도 작업입니다.
  • 앱 생명주기(ActivityLifecycleCallbacks) 연동, 서버 검증·지급 API, 실제 구매 화면은 이번 PR 범위 밖입니다.

- BillingClient 연결 상태, 상품 조회, 구매 플로우 실행, 미처리 구매 복구, consume을 처리하는 BillingRepository/PlayBillingRepository 구현
- 구매 콜백과 미처리 구매 복구 조회 결과를 공통된 BillingPurchaseOutcome으로 매핑하는 BillingPurchaseOutcomeMapper 추가
- ForwardingPurchasesUpdatedListener로 BillingClient 생성 시점과 리스너 처리 주체(PlayBillingRepository)의 생성 순서 의존성을 해소하고 Hilt 모듈로 바인딩
- Google 정적 테스트 상품으로 BillingClient 연결·상품 조회·구매 플로우를 수동 검증하는 디버그 화면 추가
- 구매 콜백, 미처리 구매 복구 조회, consume 처리 결과를 로그로 확인 가능
- adb로만 실행 가능한 디버그 빌드 전용 액티비티로 매니페스트에 등록
- BillingPurchaseOutcomeMapper의 응답코드·구매상태별 매핑 결과(Purchased/Pending/UserCanceled/AlreadyOwned/Error)를 검증
- PlayBillingRepository의 연결 상태 전환, 미처리 구매 자동 재조회, 구매 콜백 및 ITEM_ALREADY_OWNED 복구 흐름을 검증
- queryProductDetails가 캐시 없이 매 호출마다 Play에 재조회함을 검증
- 실기기 user 빌드에서 shell UID로 액티비티를 실행할 수 있도록 exported를 활성화
- 런처 인텐트 필터가 없음을 명시해 디버그 전용 진입 경로를 유지
- BillingClient 콜백과 API 호출을 데이터소스로 캡슐화
- 리포지토리가 연결 상태와 구매 결과 도메인 처리만 담당하도록 개선
- 데이터소스 Fake를 도입하고 연결 종료 동작을 테스트에 반영
@seunghee17 seunghee17 changed the title feat: Google Play 결제 연동 BillingClient 생성 및 단위 테스트 구축 [GMSS-343,346] Google Play 결제 연동 BillingClient 생성 및 단위 테스트 구축 Nov 6, 2026
@seunghee17
seunghee17 marked this pull request as ready for review November 6, 2026 04:01

@soyeonLee126 soyeonLee126 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(P3) 작업 유형에서 refactor: 리팩토링 (동작 변경 없음)이 체크되어 있습니다. 이번 PR은 새 모듈과 디버그 화면을 추가한 것이라 기존 코드를 리팩터링한 부분은 없는 것 같습니다. 체크를 해제하면 좋을 것 같습니다!

Comment thread core/billing/build.gradle.kts Resolved
- android.test.* 상품이 queryProductDetailsAsync로 조회되지 않아 구매창·콜백·consume 흐름은 미검증임을 명시
- Google 공식 문서가 License Tester + 실제 등록 상품 방식만 안내한다는 배경 추가
- queryPurchases/consumePurchase 반환형을 Pair/BillingResult 대신 PurchasesResult/ConsumeResult로 변경하고 queryPurchasesAsync/consumePurchase KTX 확장 함수로 구현 단순화
- PlayBillingRepository의 consumePurchase는 ConsumeResult.billingResult를 반환하도록 수정
- BillingConnectionState.CLOSED 상태와 이를 사용하는 endConnection API를 Repository/DataSource 전 계층에서 제거
- ITEM_ALREADY_OWNED는 구매 정보가 없는 실패 코드이므로 AlreadyOwned를 data class에서 data object로 변경
- 매퍼와 테스트에서 불필요한 productIds = emptyList() 인자 제거
- BillingResult 노출을 제거하고 isSuccess/responseCode를 담은 BillingOperationResult로 대체
- BillingProduct의 ProductDetails를 internal로 숨기고 productId를 별도 필드로 공개
- 테스트와 디버그 화면을 새 필드(callResult, productId)에 맞춰 갱신
- consumePurchase가 서버 지급 검증 이후에만 호출되어야 함을 문서화
- _purchaseResults를 extraBufferCapacity 대신 replay + DROP_OLDEST로 구성해 늦은 구독자도 최근 구매 결과를 받을 수 있게 변경
Comment thread core/billing/build.gradle.kts Resolved
- BillingResult/ProductDetails가 공개 API로 노출되지 않도록 billing-ktx 의존성 범위를 축소
- 구매 결과가 여러 곳에서 collect될 경우 분산 전달될 수 있다는 점을 문서화
- MutableSharedFlow(replay) 대신 Channel + receiveAsFlow로 각 결과를 정확히 한 번만 전달하도록 변경
@soyeonLee126
soyeonLee126 merged commit 466ba9e into develop Nov 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants