I\'m attempting to make a free app upgradable to the \"paid\" version using in-app billing. I used code from this tutorial to handle the billing as the one on the official d
I'm also developing a free app upgradable, but I used the oficial sample instead of Blundell's tutorial, because that tutorial does not save information and doesnt use Managed items
Just take a look on the restoreDatabase() method in the Dungeons sample, it does what you want, checks, using the SharedPreferences if it's the first run and if it is calls the restoreTransactions method.
To debug, just connect your device to eclipse and check the logcat, just dont forget to set the constant Debug (in Consts.java) to true and in the manifest set the debuggable tag to true also.
To understand the sample code better I just added a lot more debug and now its working.
So I finally managed to figure it out.
If you look at the Google Docs for the In App Billing Overview, it states that:
The RESTORE_TRANSACTIONS request type also triggers a PURCHASE_STATE_CHANGED broadcast intent, which contains the same type of transaction information that is sent during a purchase request, although you do not need to respond to this intent with a CONFIRM_NOTIFICATIONS message.
In a normal purchase-confirmTransaction cycle, when you request to purchase an In App Billing product, google sends back a JSON with a bunch of fields. One of these fields is 'notification_id'. When google sends a PURCHASE_STATE_CHANGED intent, it expects a CONFIRM_NOTIFICATIONS response from the app, with a bundle containing a bunch of info, including the notification_id's. All well and good here.
The problem starts when you get a PURCHASE_STATE_CHANGED from Google for a RESTORE_TRANSACTIONS request from the app. This JSON does not contain notificaion_id fields. The library still responds with a CONFIRM_NOTIFICATIONS, adding the notification_id array to the bundle, which, in this case, is null. That's what causes the NullPointerException.
Solution: I modified the BillingHelper.java class by adding a boolean to track when the user makes a normal purchase, and when he wants to restoreTransactions. If it's a restoreTransactions request, I send a message back to the handler and skip the confirmNotifications step.
EDIT: The code for the above fix is in BillingHelper.java I am using a boolean flag to track whether the user made a RESTORE_TRANSACTIONS call (isRestoreTransactions).
In BillingHelper.java's 'verifyPurchase' method, I changed the code as follows:
protected static void verifyPurchase(String signedData, String signature) {
ArrayList<VerifiedPurchase> purchases = BillingSecurity.verifyPurchase(signedData, signature);
if(isRestoreTransaction)
{
/*
*
*Add some logic to retrieve the restored purchase product ID's from the 'purchases' array
*
*/
//Set the boolean to false
isRestoreTranscation = false;
//Send a message to the handler, informing it that purchases were restored
if(mCompletedHandler != null){
mCompletedHandler.sendEmptyMessage(0);
} else {
Log.e(TAG, "verifyPurchase error. Handler not instantiated. Have you called setCompletedHandler()?");
}
}
else
{
/*
*......
*......
*......
*Original method body here
*......
*......
*......
*/
}
}
You can't really make a distinction between 'reinstalling' and 'cleared app data'. They are essentially the same: shared preferences are empty. Nor should you need to.
As for diagnosing the issue, put a 'restore transactions' button and simply click it in different states (just installed, flag(s) set, etc.). Then watch the logcat.
BTW, it might be better to stick with the original Google code at first, you would get more help that way. There also some projects on Google Code that wrap the IAB code to make it a bit easier to integrate.