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
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 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
*......
*......
*......
*/
}
}