Reputation: 787
I am working on Google In-app purchase for an app. I have created a managed product item with id as "app.test.item". I followed all other steps specified in the google documentation. For a first time purchase app is working fine. But when i try to unistall the app and install it again. The app runs a restore transaction request. The onRestoreTransactionsResponse() method gets called where i make the purchase status true based on the RESULT_OK returned from the Market. My doubt is how does the app know that only the item named "app.test.item" is purchased and is hence restored. I am having some other items too for example "app.test.second.item" . How does the in app billing see the difference between the two. I have used the Google provided in-app billing code. just mentioned few sharedpreferences to store the purchase status. Am i doing anything wrong here. Please guide me.
Also i want to test this app in debug mode so that i can trace out the workflow. But the apps should be signed with a release version. Is there any way i can run this app completely(to test the restore transactions) in debug version. I understood the general workflow for a general purchase using the reserved productId as "android.test.purchased". But i need to test for restoreTransactions(). Any help is appreciated.
I am posting the PurchaseObserver sample code here.
Thanks,
private class DungeonsPurchaseObserver extends PurchaseObserver {
public DungeonsPurchaseObserver(Handler handler) {
super(Dungeons.this, handler);
}
@Override
public void onBillingSupported(boolean supported) {
if (Consts.DEBUG) {
Log.i(TAG, "supported: " + supported);
}
if (supported) {
restoreDatabase();
} else {
showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
}
}
@Override
public void onPurchaseStateChange(PurchaseState purchaseState, String itemId,
int quantity, long purchaseTime, String developerPayload) {
if (Consts.DEBUG) {
Log.i(TAG, "onPurchaseStateChange() itemId: " + itemId + " " + purchaseState);
}
if (developerPayload == null) {
logProductActivity(itemId, purchaseState.toString());
} else {
logProductActivity(itemId, purchaseState + "\n\t" + developerPayload);
}
if (purchaseState == PurchaseState.PURCHASED) {
mOwnedItems.add(itemId);
logProductActivity("APPLICATION", ": STATE PURCHASED");
SharedPreferences pref = getSharedPreferences(PREF_FILE, MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putString(PURCHASE_STATUS, "ITEM PURCHASED");
editor.commit();
}
if(purchaseState == PurchaseState.CANCELED)
{
logProductActivity("APPLICATION", ": STATE CANCELLED");
SharedPreferences pref = getSharedPreferences(PREF_FILE, MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putString(PURCHASE_STATUS, "ITEM CANCELLED");
editor.commit();
}
if(purchaseState == PurchaseState.REFUNDED)
{
logProductActivity("APPLICATION", ": STATE REFUNDED");
SharedPreferences pref = getSharedPreferences(PREF_FILE, MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putString(PURCHASE_STATUS, "ITEM REFUNDED");
editor.commit();
}
}
@Override
public void onRequestPurchaseResponse(RequestPurchase request,
ResponseCode responseCode) {
if (Consts.DEBUG) {
Log.d(TAG, request.mProductId + ": " + responseCode);
}
if (responseCode == ResponseCode.RESULT_OK) {
if (Consts.DEBUG) {
Log.i(TAG, "purchase was successfully sent to server");
}
logProductActivity(request.mProductId, "sending purchase request");
} else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
if (Consts.DEBUG) {
Log.i(TAG, "user canceled purchase");
}
logProductActivity(request.mProductId, "dismissed purchase dialog");
} else {
if (Consts.DEBUG) {
Log.i(TAG, "purchase failed");
}
logProductActivity(request.mProductId, "request purchase returned " + responseCode);
}
}
@Override
public void onRestoreTransactionsResponse(RestoreTransactions request,
ResponseCode responseCode) {
if (responseCode == ResponseCode.RESULT_OK) {
if (Consts.DEBUG) {
Log.d(TAG, "completed RestoreTransactions request");
}
// Update the shared preferences so that we don't perform
// a RestoreTransactions again.
SharedPreferences prefs = getSharedPreferences(PREF_FILE, MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(DB_INITIALIZED, true);
edit.putString(PURCHASE_STATUS, "ITEM PURCHASE RESTORED");
edit.commit();
logProductActivity("onRestoreTransactionsResponse() method in PurchaseObserver", "ITEM PURCHASE RESTORED");
} else {
if (Consts.DEBUG) {
Log.d(TAG, "RestoreTransactions error: " + responseCode);
}
}
logProductActivity("onRestoreTransactionsResponse() method in PurchaseObserver", responseCode.toString());
}
}
Upvotes: 1
Views: 2839
Reputation: 35661
Debugging managed products can be difficult as you cannot use them unless the app is signed with a release key. For this reason I sign my debug builds with my release key when testing IAB.
Regarding multiple products, you need to check the item id. onPurchaseStateChange
will be called for each product.
e.g
public void onPurchaseStateChange(PurchaseState purchaseState, String itemId, int quantity, long purchaseTime, String developerPayload) {
if (itemId.equals("app.test.item") {
switch (purchaseState) {
case PURCHASED:
Log.i("Billing","Purchased app.test.item");
break;
default:
Log.i("Billing","Something else");
break;
}
}
Upvotes: 4
Reputation: 52936
If you set the 'debuggable' flag to true in the AndroidManifest.xml you can attach a debugger to your app. The fact that it is signed with the release key has nothing to do with debugging. As for how the app knows if an item is purchased, if you use managed items, they are associated with your google account. When you request RESTORE_TRANSACTIONS, your account (GMail address) is sent to the Google Play/Market servers and it checks what items have been bought by this person/account. If you use unmanaged items, you need to keep track of items yourself, and RESTORE_TRANSACTIONS cannot be used.
Upvotes: 0