반응형
Android 인앱 결제(inapp billing) 순서
1. 구글 인앱 빌링 라이브러리 설치 및 임포트
2. aidl, util부분 가져온다.
3. 매니페트스트 수정
-<uses-permission android:name="com.android.vending.BILLING" />
-V2에 비해 AndroidManifest.xml이 쉬워졌습니다. 위와같이 빌링 관련된 권한만 추가해주면 됩니다.
4. 인앱 빌링 초기화 및 인벤토리 요청
static final int RC_REQUEST = 1001 //IabHelper용 콜백 결과를 구분하기 위한 상수
private IabHelper mHelper;
/*
strPublicKey는
구글 개발자 콘솔 -> 출시 앱 선택 -> 서비스 및 API ->
라이선스 및 인앱 결제
라이선스 키를 사용하여 앱의 무단 배포를 방지할 수 있습니다. 이 키를 사용하여 인앱 결제로 구매한 항목을 확인할 수도 있습니다. 라이선스에 대해 자세히 알아보기
이 애플리케이션용 라이선스 키
바이너리에 포함하려는 Base64 인코딩 RSA 공개 키입니다. 공백을 삭제해 주세요.
**BASE64 키
*/
public void InAppInit_U(String strPublicKey, boolean bDebug)
{
mHelper = new IabHelper(this, strPublicKey);
}
if(bDebug == true)
{
mHelper.enableDebugLogging(true, "IAB");
}
5.초기화 성공 후 onIabSetupFinished에서 구매 후 소비되지 않은 아이템들이 있는지 확인을 위해 queryInventoryAsync를 실행
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener()
{
@Override
public void onIabSetupFinished(IabResult result)
{
boolean bInit = result.isSuccess();
if(bInit == true)
{
mHelper.queryInventoryAsync(mGotInventoryListener);
}
}
}
6. 구매목록 쿼리 요청 후 콜백된 onQueryInventoryFinished에서 결과에 따라 처리하면 되는데 일단 인벤토리에 있는 것중
아이템 타입이 인앱인 것 즉, 소모성 아이템인 것을 모두 가져와 consumeAsync를 통해 구글에 소비 요청을 합니다.
이때 바로 위처럼 하면
List<String> inappList = inventory.getAllOwnedSkus(IabHelper.ITEM_TYPE_INAPP);
위 부분에서 에러가 발생하는데요, getAllOwnedSkus가 public가 아니라서 그렇습니다. Inventory.java 의 71라인에 있는 부분에 public를 추가해줍니다.
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener()
{
public void onQueryInventoryFinished(IabResult result, Inventory inventory)
{
if(result.isFailure())
{
}
List<String> inappList = inventory.getAllOwnedSkus(IabHelper.ITEM_TYPE_INAPP);
for(String inappSku : inappList)
{
Purchase purchase = inventory.getPurchase(inappSku);
mHelper.consumeAsync(putchase, mConsumeFinishedListener);
}
}
}
7. 아이템 구매 및 소비
//아이템 구매는 V2와 마찬가지로 아이템 id만 있으면 요청할 수 있습니다. RC_REQUEST는 위에서 추가했던 상수
public void inAppBuyItem(final String strItemnId)
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
String payload = "";
mHelper.launchPurchaseFlow(액티비티, strItemId, RC_REQUEST, mPurchaseFinishedListener, payload);
}
});
}
8.구매요청 완료
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener()
{
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
if(purchase != null)
{
if(!verifyDeveloperPayload(purchase))
{
//Error purchasing
}
//구매완료후 콜백처리부분
//V2에서는 구매완료후 소비를 바로 하지 않아도 되었는데 V3에서는 바로 소비를 하도록 강제해 중복구매를 방지
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}
else
{
//구매실패에대한 처리
}
}
}
9. 인증강화 부분인듯
boolean verifyDeveloperPayload(Purchase p)
{
String payload = p.getDeveloperPayload();
//인증 강화 부분인듯한데 샘플그대로 true
return true;
}
10. 소비 요청에 대한 콜백
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener()
{
public void onConsumeFinished(Purchase purchase, IabResult result)
{
SendConsumeResult(purchase, result);
}
};
protected void SendConsumeResult(Purchase purchase, IabResult result)
{
JSONObject jsonObj = new JSONObject();
try
{
jsonObj.put("Result", result.getResponse());
if(purchase !=null)
{
jsonObj.put("OrderId", purchase.getOrderId());
jsonObj.put("Sku", purchase.getSku());
jsonObj.put("purchaseData", purchase.getOriginalJson());
jsonObj.put("signature", purchase.getSignature());
}
}
catch(JSONException e)
{
e.printStackTrace();
}
}
11. 인앱 구매 처리 부분
//strPurchaseData와 strSignature를 서버에 보내 영수증 확인을 처리하도록 한다.
public void InAppButItem(String strItemId)
{
curActivity.Call("InAppBuyItem_U", strItemId);
}
// IAB Helper error codes
public static final int IABHELPER_ERROR_BASE = -1000;
public static final int IABHELPER_REMOTE_EXCEPTION = -1001;
public static final int IABHELPER_BAD_RESPONSE = -1002;
public static final int IABHELPER_VERIFICATION_FAILED = -1003;
public static final int IABHELPER_SEND_INTENT_FAILED = -1004;
public static final int IABHELPER_USER_CANCELLED = -1005;
public static final int IABHELPER_UNKNOWN_PURCHASE_RESPONSE = -1006;
public static final int IABHELPER_MISSING_TOKEN = -1007;
public static final int IABHELPER_UNKNOWN_ERROR = -1008;
public static final int IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE = -1009;
public static final int IABHELPER_INVALID_CONSUMPTION = -1010;
private void InAppBuyItemResult_J(String strResult)
{
int iResult = System.Conver.ToInt32(strResult);
switch(iResult)
{
case -1005:
//InAppBuyItem Cancel
break;
default:
//InAppBuyItem Failed
break;
}
}
// Billing response codes
public static final int BILLING_RESPONSE_RESULT_OK = 0;
public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1;
public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3;
public static final int BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE = 4;
public static final int BILLING_RESPONSE_RESULT_DEVELOPER_ERROR = 5;
public static final int BILLING_RESPONSE_RESULT_ERROR = 6;
public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7;
public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8;
private void InAppConsumeResult_J(String strResult)
{
JsonData jData = JSonMapper.ToObject(strResult);
int iREsult = System.Convert.ToInt32(jData["result"].ToString());
switch(iResult)
{
case 0:
String strOrderId = jData["OrderId"].ToString();
String strSku = jData["Sku"].ToString();
String strPurchaseData = jData["purchaseData"].ToString();
String strSignature = jData["signature"].ToString();
//성공
break;
default:
//실패
break;
}
}
12. 후처리
@Override
public void onDestroy() {
super.onDestroy();
// very important:
Log.d(LOG_TAG, "Destroying helper.");
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
//구매요청후 액티비티가 다시 돌아올 때 onActivityResult에서 RC_REQUEST를 가지고 인앱 빌링 처리 후인지 구분합니다.
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == RC_REQUEST) {
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else {
Log.d(LOG_TAG, "onActivityResult handled by IABUtil.");
}
}
}
13. 구글마켓에 apk파일 올리기
14. 인앱상품을 등록 (인앱상품을 등록하려면 구글 계정에 판매자계정이 등록 되어있어야한다.)
http://theeye.pe.kr/archives/2130
관리되는 제품, 구독
기본적으로 모든 관리되는 제품은 구매가 성공적으로 이루어졌을 때 보유(Owned) 상태가 됩니다. 이 상태에서는 Google Play를 통해 같은 상품을 중복 구매할 수 없게 됩니다.
이 보유상태의 제품을 consumePurchase() 를 호출하여 소진(Consume)하여 다시한번 비보유(Unowned) 상태로 되돌릴 수 있습니다.
이 소진행위는 Google Play로 하여금 다시 해당 상품을 구매 가능한 상태로 되돌리며 이전의 구매 정보를 파기하게 됩니다.
소진이 불가능한 상품이라는 의미는 똑같은 상품을 두번 이상 구매할 수 없는것을 의미합니다. 소진이 가능한 상품의 경우 똑같은 상품을 계속해서 반복 구매하는 것이 가능합니다.
구독의 경우에는 다음과 같이 한달 또는 일년 단위로 자동 연장되는 결제 방식을 의미합니다.
음원 서비스들에서 주로 볼 수 있는 상품의 모습이라고 생각됩니다.
구독의 취소는 [Google 월렛의 내 구독 정보]에서 취소할 수 있습니다.
14-1. 판매자계정 등록
세금정보
사업자유형
1.일반과세
2.간이과세
3.개인
사업자등록번호 :
대표자명 :
비지니스 법률 정보
도/시 :
시/구/군 :
주소 :
주소입력란 :
상호 :
전화번호 :
웹사이트 :
판매하는 제품 및 서비스 :
고객 서비스 이메일 :
신용카드 명세서 이름 : (영어로)
***입력후 제출
15. 사용할때 에러사항
구매버튼 눌러도 반응이없을때
- 1003: Purchase signature verification failed
: 이 경우에 base64키값이 달랐었다.
결제를 시도해도 에러 메시지뜸
Error: Error purchasing: labResult: Unable to buy item(response: 7:Item Already Owned)
: 이 경우에 m_app.m_iabHelper.consumeAsync(purchases, mConsumeMultiFinishedListener); 를 호출해주어 아이템을 소비한다.
요청하신 항목은 구매할 수 없습니다.
: 이 경우에는 구글에 올라간 버전이 테스트한 버전보다 낮았었다. 업데이트 시켜준다.
참조 :
http://westwoodforever.blogspot.kr/2013/10/unity3d-integration-google-in-app.html
반응형
'안드로이드' 카테고리의 다른 글
[Android] 문자 읽기(TTS) (0) | 2022.10.20 |
---|---|
[Android] 인앱 개발에 대해 알아보자 (실전) (0) | 2022.10.20 |
[Android] 문자 보내기 (SEND_SMS) (0) | 2022.10.20 |
[Android] 녹음 기능 RecMic to Mp3 (0) | 2022.10.20 |
[Android] 네비게이션(Navigation)에 대해 알아보자 (0) | 2022.09.22 |