2017년 10월 31일 화요일

Android IAP 대충 정리

안드로이드 IAP가 궁금해서 대충 요약함.

https://developer.android.com/google/play/billing/billing_subscriptions.html

[인앱구독]
인앱 결재를 사용하여 구독 서비스 판매 가능.

- 다양한 주기의 구독 결재 판매 가능
- 월간, 연간 구독을 위해 체험 기간 구성 가능
- Google Play Developer API나 Developer Console을 사용하여 구독 관리
- 사용자는 앱내에서 구독 구매
- 구독 갱신, 업그레이드, 다운그레이드 가능
- 구독 결재 연기 가능

구독은 개발자가 지정한 간격으로 자동 반복되는 결재
인앱 상품과 유사한 절차로 구독을 구성하고 게시함. 단 체험기간과 결재 주기 선택이 다름

[구독 아이템 구성]

  • 구매 유형: 항상 Subscription으로 설정
  • 구독 ID: 구독 식별자
  • 게시 상태: 게시 안 됨/게시됨
  • 언어: 구독을 표시하기 위한 기본 언어
  • 제목: 구독 상품의 제목
  • 설명: 사용자에게 구독에 대해 설명하는 세부정보
  • 가격: 반복 구매 시마다 적용되는 기본 구독 가격
  • 반복 구매: 반복 구매 결제 주기
  • 추가적인 통화 가격(자동 채우기 가능)

[구독 가격]
- 사용 가능 통화로 구독 가격 설정.
- 구독 가격은 0원 초과
- 구독 가격을 다르게 설정 가능(ex 월간 요금 vs 할인된 연간 요금)

[사용자 결제]
- 주간, 월간, 3개월 6개월, 연간, 시즌

[수동 갱신]
- 구독 중 추가 구독 시 만료일이 추가 구독 기간을 포함하여 연장 됨.

[구독 업그레이드/다운그레이드]
- 구독을 변경할 경우 기존 구독이 취소되고 새 구독이 생성됨.

[결제 유예]
- 유예기간 동안 컨텐트 구독 및 사용 권한을 가지지만 요금이 처구되지 않음.
- 단 유예할 수 있는 최장기간은 API 호출 당 1년 이고 1년 중 다시 호출하여 유예기간 연장 가능

[무료 평가판]
- 무료 체험 기간을 설정할 수 있음.
- 개발자가 지정한 기간 동안만 체험이 가능하고 기간이 지나면 구독 결재 주기와 가격에 따라 관리되는 구독으로 자동 전환됨.
- 일반적인 구매 절차를 따라 구매하지만 무료 체험기간 동안은 요금이 0.00 임.

[구독 취소]
- App이 아닌 Play Store의 앱의 My Apps 화면에서 구독에 대한 상태 확인, 취소 가능.
- 구독 취소 시 Google Play는 결재 주기에 대해서는 환불하지 않고 결제 주기 종료까지 구독에 액세스 할 수 있음.

[앱 제거]
- 사용자가 구매한 구독을 포함한 앱 제거시 구독 정보를 알려줌.
- App을 제거하여도 구독은 제거되지 않음.

[결제 처리 및 정책]
- Google Payments를 통해서만 판매 가능
- 구독 상품 구매 시 Transaction 요금은 구매와 같이 30%임.
- 매 구독 마다 구매 정보(판매자 주문 번호와 각각 반복 transaction 정보를 제공함)

[Google Play Developer API]
  • 언제든지 특정 구독의 유효성을 원격으로 쿼리
  • 구독 취소
  • 구독의 다음 결제일 유예
  • 구독을 취소하지 않고 구독 결제 대금 환불
  • 구독 환불 및 취소

https://developer.android.com/google/play/billing/billing_integrate.html#Subs

구독 구현

구독에 대한 구매 흐름을 시작하는 것은 상품에 대한 구매 흐름을 시작하는 것과 비슷하지만, 상품 유형을 "subs"로 설정해야 한다는 점이 다릅니다. 인앱 상품의 경우에서와 정확히 똑같이, 액티비티의 onActivityResult 메서드로 구매 결과가 전달됩니다.
Bundle bundle = mService.getBuyIntent(3, "com.example.myapp",
   MY_SKU, "subs", developerPayload);
PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT);
if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) {
   // Start purchase flow (this brings up the Google Play UI).
   // Result will be delivered through onActivityResult().
   startIntentSenderForResult(pendingIntent, RC_BUY, new Intent(),
       Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
}
활성 구독을 쿼리하려면 이때도 상품 유형 매개변수를 "subs"로 설정하여 getPurchases 메서드를 사용하세요.
Bundle activeSubs = mService.getPurchases(3, "com.example.myapp",
                   "subs", continueToken);
이렇게 호출하면 사용자가 소유한 모든 활성 구독을 포함한 Bundle이 반환됩니다. 구독이 만료되고 갱신하지 않으면 반환되는 Bundle에 더 이상 구독이 표시되지 않습니다.

[인앱 프로모션]
https://developer.android.com/google/play/billing/billing_promotions.html?hl=ko

- 모든 프로모션 코드는 특정한 상품ID(SKU)와 연결됨.
- 프로모션 코드를 입력하면 특정 아이템의 가격을 완불한 것과 같이 처리됨.

[프로모션 코드 생성 및 사용]
- 프로모션 코드는 Google Play Developer console에서 생성
- 각 프로모션 코드는 Developer console의 단일 상품과 연결
- 프로모션 코드는 일반 인앱 결제와 동일한 절차를 거치되 단 돈대신 프로모션 코드를 사용한다는 점이 다름.
- Google Play 스토어 앱에서 코드를 사용할 수 있음.


[앱에서 프로모션 코드 지원]
- 앱이 다시 시작(onResume())될 때마다 getPurchases() 메서드 호출 후 구매내역 확인
- 앱이 IAP를 지원한다면 구매와 유사하게 진행 되므로 별도 처리 필요 없음.
- 앱 실행 중에 Play 스토어 앱에서 프로모션 코드를 사용하는 경우 처리가 필요함.
: com.android.vending.billing.PURCHASES_UPDATED intent 수신을 위한 처리 필요.

(등록)
IntentFilter promoFilter =
    new IntentFilter("com.android.vending.billing.PURCHASES_UPDATED");
registerReceiver(myPromoReceiver, promoFilter);

(취소)
unRegisterReceiver(myPromoReceiver);

[보안 및 디자인]
https://developer.android.com/google/play/billing/billing_best_practices.html?hl=ko

- 잠금 해제된 콘텐츠를 apk 파일에 포함하여 재배포 할 수 있게 하지 말라.
- 코드 난독 처리 필요, proguard 실행, 아래 방법도 사용가능
 . 메서드를 다른 메서드로 인라인 처리합니다.
 . 문자열을 상수로 정의하는 대신 즉석에서 생성합니다.
 . Java 리플렉션(reflection)을 사용하여 메서드를 호출합니다.

- 보안 랜덤 Nonce를 사용하라.
- 잠금 해제된 콘텐츠를 사용할 때 마다 취소 여부를 확인하라.
- Google Play 공개키를 안전하게 보관하라.
 . 문자열로 삽입하지 말고 런타임에 문자열 생성이나 비트조작을 사용하여 숨겨라.

댓글 2개:

  1. 안녕하세요. 작성해주신 글 지금에도 도움받고 있습니다 :) 전 서버개발자구요 구독 관련 설계중에 있습니다. 작성해주신 글 중 한가지 궁금한 것이 있는데요, '앱이 다시 시작(onResume())될 때마다 getPurchases() 메서드 호출 후 구매내역 확인' 이런 문장이 있었는데 그럼 클라이언트(안드로이드)에서 호출할 때마다으로 구독 상태를 체크할 수 있는건가요?https://charlie0301.blogspot.com/logout?d=https://www.blogger.com/logout-redirect.g?blogID%3D7260596801258397336%26postID%3D4310457833642968891

    답글삭제
  2. 댓글을 지금봐서 너무 늦게 답변 드리네요. getPurchase는 구매 내역을 확인 하는 API라 언제든지 구매 내역을 제공할 수 있어야 할 것으로 보입니다. 해당 내역은 앱에서 프로모션이 적용 되었는지를 확인 하기 위한 방법 중 하나이며 아래 문서에서 예시로 보옂 고 있습니다.

    https://developer.android.com/google/play/billing/billing_promotions?hl=ko
    프로모션 코드를 지원하려면 앱이 시작되거나 다시 시작될 때마다 앱에서 getPurchases() 메서드를 호출해야 합니다. 이 메서드는 사용자가 프로모션 코드를 사용하여 구매한 모든 내역을 포함하여 현재 소비되지 않은 모든 구매를 번들로 반환합니다. 가장 간단한 방법은 활동의 onResume() 메서드에서 getPurchases()를 호출하는 것입니다.

    답글삭제