Google In-App Billing V3 Unable to buy item, Error response: 7:Item Already Owned
Starting async operation: launchPurchaseFlow
Constructing buy intent for testinappitem1, item type: inapp
In-app billing error: Unable to buy item, Error response: 7:Item Already Owned
Purchase finished: IabResult: Unable to buy item (response: 7:Item Already Owned), purchase: null
InAppBuyItem_U testinappitem1
구글 인앱빌링 V3로 비관리 아이템 같은 것을 중복 구매시 위와 같은 오류가 발생합니다. 만약 onIabPurchaseFinished 부분에서 purchase != null 인지 체크하지 않고 샘플과 같게 개발하셨다면 NullPointerException 에러가 발생하게되니 주의하시기 바랍니다.
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
...
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_GAS)) {
// bought 1/4 tank of gas. So consume it.
Log.d(TAG, "Purchase is gas. Starting gas consumption.");
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}
...
}
};
해결방법은 소모성 아이템을 구매하고 바로 소비처리를 해야합니다. 위 소스는 trivialdrivesample의 구매 완료 처리 부분인데 바로 comsumeAsync를 통해서 소비를 하고 있죠.
public class Inventory {
Map<String,SkuDetails> mSkuMap = new HashMap<String,SkuDetails>();
Map<String,Purchase> mPurchaseMap = new HashMap<String,Purchase>();
그리고 Inventory 부분을 봐도 소모성 아이템이라도 오직 한개만 가지고 있을 수 있도록 자료구조가 처리되고 있더군요. 인앱빌링 V2만 해도 이런 이슈는 없었는데 구글에서 소모성 아이템을 구매 후 바로 소비하도록 강제하는 것 같습니다.
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(LOG_TAG, "Purchase finished: " + result + ", purchase: " + purchase);
if (purchase != null && !verifyDeveloperPayload(purchase)) {
Log.d(LOG_TAG, "Error purchasing. Authenticity verification failed.");
}
JSONObject iabJsonObj = new JSONObject();
try {
iabJsonObj.put("Result", result.getResponse());
if(purchase != null) {
iabJsonObj.put("OrderId", purchase.getOrderId());
iabJsonObj.put("ItemType", purchase.getItemType());
iabJsonObj.put("OriginalJson", purchase.getOriginalJson());
iabJsonObj.put("Signature", purchase.getSignature());
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
UnityPlayer.UnitySendMessage("GoogleInAppManager", "InAppBuyItemResult_J", iabJsonObj.toString());
}
};
처음에는 이같은 사실을 모르고 그냥 V2 개발할 때 처럼 위 소스와 같이 유니티3D 측에 정보를 넘겨서 가지고 있다가 나중에 마음데로 소비를 처리할 수 있게 했었는데 이 작업이 소용없게 되었네요.
Constructing buy intent for testinappitem1, item type: inapp
In-app billing error: Unable to buy item, Error response: 7:Item Already Owned
Purchase finished: IabResult: Unable to buy item (response: 7:Item Already Owned), purchase: null
InAppBuyItem_U testinappitem1
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
...
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_GAS)) {
// bought 1/4 tank of gas. So consume it.
Log.d(TAG, "Purchase is gas. Starting gas consumption.");
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}
...
}
};
해결방법은 소모성 아이템을 구매하고 바로 소비처리를 해야합니다. 위 소스는 trivialdrivesample의 구매 완료 처리 부분인데 바로 comsumeAsync를 통해서 소비를 하고 있죠.
public class Inventory {
Map<String,SkuDetails> mSkuMap = new HashMap<String,SkuDetails>();
Map<String,Purchase> mPurchaseMap = new HashMap<String,Purchase>();
그리고 Inventory 부분을 봐도 소모성 아이템이라도 오직 한개만 가지고 있을 수 있도록 자료구조가 처리되고 있더군요. 인앱빌링 V2만 해도 이런 이슈는 없었는데 구글에서 소모성 아이템을 구매 후 바로 소비하도록 강제하는 것 같습니다.
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(LOG_TAG, "Purchase finished: " + result + ", purchase: " + purchase);
if (purchase != null && !verifyDeveloperPayload(purchase)) {
Log.d(LOG_TAG, "Error purchasing. Authenticity verification failed.");
}
JSONObject iabJsonObj = new JSONObject();
try {
iabJsonObj.put("Result", result.getResponse());
if(purchase != null) {
iabJsonObj.put("OrderId", purchase.getOrderId());
iabJsonObj.put("ItemType", purchase.getItemType());
iabJsonObj.put("OriginalJson", purchase.getOriginalJson());
iabJsonObj.put("Signature", purchase.getSignature());
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
UnityPlayer.UnitySendMessage("GoogleInAppManager", "InAppBuyItemResult_J", iabJsonObj.toString());
}
};
처음에는 이같은 사실을 모르고 그냥 V2 개발할 때 처럼 위 소스와 같이 유니티3D 측에 정보를 넘겨서 가지고 있다가 나중에 마음데로 소비를 처리할 수 있게 했었는데 이 작업이 소용없게 되었네요.
댓글
댓글 쓰기