: https://developer.android.com/google/play/billing/index.html?hl=ko
대상 : 표준 인앱 상품(일회성 결제), 구독(반복 자동 결제)
- IAP를 사용하여 아이템 판매 시 Google Play가 모든 결제 정보를 처리하여 App은 결재 transaction 관련 처리가 필요 없음.
- Google Play에서 제공하는 결재 서비스를 사용하므로 모든 app들에 대해 일관적인 경험 제공
- Google Play를 통해 세기되는 App 대상
(개요)
[In-app Billing API]
[Google Play Developer Console]
: https://developer.android.com/google/play/billing/billing_overview.html?hl=ko#api
- Google Play 앱에 의해 노출 되는 API를 통해 결제 서비스 사용
- Google Play 앱이 App<->Google Play server 사이 결제 요청, 응답 전달
- App<->Google Play 앱은 IPC를 사용하여 결제 요청, 응답을 받음.
- 결재는 Google Play 서버를 통해서 진행하므로 Google Play app이 서버와 통신할 수 있어야 함.
- Android In-app billing version은 현재 v3가 최신 버전임.
. App은 google Play의 API를 통해 상품 세부 정보 요청, 상품 주문, 소유 상품 복원 가능.
. API는 구매 완료 시 주문 정보를 동기적으로 기기로 전파.
. 모든 구매가 Google Play를 통해 관리됨.
. 구매한 상품은 소비 가능하며 소비 시 소유하지 않은 상태로 변경됨.
. 구독 서비스를 지원함.
- IAP 사용 App을 게시하고 IAP로 판매할 상품을 관리(구매/구독, 상품 목록 생성)함.
- 제품에 대한 다음 정보들을 정의함.
. 상품 ID(SKU), 상품 유형, 가격, 설명, 구매에 대한 처리 및 추적?
https://developer.android.com/google/play/billing/billing_reference.html?hl=ko#getSkuDetails
키 | 설명 |
---|---|
productId | 상품의 ID입니다. |
type | 이 키의 값은 인앱 상품의 경우 “inapp” , 구독의 경우 "subs" 여야 합니다. |
price | 아이템의 형식 지정된 가격(통화 기호 포함)으로, 세금을 제외한 가격입니다. |
price_amount_micros | 마이크로 단위의 가격으로, 1,000,000 마이크로 단위가 1 통화 단위와 같습니다. 예를 들어, price 가 "€7.99" 이면 price_amount_micros 는 "7990000" 입니다. 이 값은 특정 통화에 대해 현지화된 반올림 가격을 나타냅니다. |
price_currency_code | price 에 대한 ISO 4217 통화 코드입니다. 예를 들어, price 가 영국 파운드 단위로 지정되어 있는 경우 price_currency_code 는 "GBP" 입니다. |
title | 상품의 제목입니다. |
description | 상품에 대한 설명입니다. |
[Google Play 구매 흐름]
1. App >- IAP 상품 결재 요청 -> Google Play
2. Google Play 결재 양식 요청, 유효성 검사, 구매 transaction 처리
3. Google Play >- 구매 세부 정보(주문 번호, 날짜, 시간, 가격 등) -> Google Play
(In-app Billing API)
: https://developer.android.com/google/play/billing/api.html?hl=ko#producttypes
: https://developer.android.com/google/play/billing/billing_integrate.html?hl=ko
* 구현방법이 좀 다름(확인 필요). https://developer.android.com/training/in-app-billing/preparing-iab-app.html?hl=ko
[아이템 구매]
구매 물품 확인
Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
int response = ownedItems.getInt("RESPONSE_CODE"); if (response == 0) { ArrayList<String> ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST"); ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); ArrayList<String> signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN"); for (int i = 0; i < purchaseDataList.size(); ++i) { String purchaseData = purchaseDataList.get(i); String signature = signatureList.get(i); String sku = ownedSkus.get(i); // do something with this purchase information // e.g. display the updated list of products owned by user } // if continuationToken != null, call getPurchases again // and pass in the token to retrieve more items }
인앱 상품 세부정보 확인
Bundle skuDetails = mService.getSkuDetails(3, getPackageName(), "inapp", querySkus);
int response = skuDetails.getInt("RESPONSE_CODE"); if (response == 0) { ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST"); for (String thisResponse : responseList) { JSONObject object = new JSONObject(thisResponse); String sku = object.getString("productId"); String price = object.getString("price"); if (sku.equals("premiumUpgrade")) mPremiumUpgradePrice = price; else if (sku.equals("gas")) mGasPrice = price; } }
인앱 상품 구매
(요청)
Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(), sku, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
startIntentSenderForResult(pendingIntent.getIntentSender(), 1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));(응답)
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 1001) { int responseCode = data.getIntExtra("RESPONSE_CODE", 0); String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA"); String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE"); if (resultCode == RESULT_OK) { try { JSONObject jo = new JSONObject(purchaseData); String sku = jo.getString("productId"); alert("You have bought the " + sku + ". Excellent choice, adventurer!"); } catch (JSONException e) { alert("Failed to parse purchase data."); e.printStackTrace(); } } } }(구매 정보)
'{ "orderId":"GPA.1234-5678-9012-34567", "packageName":"com.example.app", "productId":"exampleSku", "purchaseTime":1345678900000, "purchaseState":0, "developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ", "purchaseToken":"opaque-token-up-to-1000-characters" }'
* 구독에 대한 구매 흐름은 유사하지만 상품 유형이 subs로 설정해야 함.
(요청)
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)); }(구매 확인)
Bundle activeSubs = mService.getPurchases(3, "com.example.myapp", "subs", continueToken);
* Transaction 무결성을 보장하기 위해 Google Play는 구매 응답 데이터를 포함한 JSON 문자열에 서명함.
[인앱 상품 소비]
구매한 상품은 소유된 상태로 간주되고 소유된 상태는 Google Play에서 다시 구매할 수 없음. 하지만 소유한 상품을 소비 하면 구매 데이터가 삭제 되고 소유되지 않는 상태로 변경됨.
int response = mService.consumePurchase(3, getPackageName(), token);
[구독]
[홍보]
[보안 및 디자인]
[테스트]
[관리]
와...진짜 감사합니다... 제가 원하던 정보가 그대로 있었네요...
답글삭제초보개발하는데 엄청 도움되었습니다. 감사합니다