hi, i'm a bit confused. i get everything working in test environment. for example, i have an entitlement sku. i purchase it and all's well. then in sdk Active Transactions, i cancel it (i understand that this sku is now revoked). so back to the app where i make another purchase for the same sku. the purchase is a success and everything works well. now if in PurchaseUpdatesAsyncTask i call getRevokedSkus(), the revoked sku will be listed. this is where my problem arises. it seems that each time it is called, this sku is displayed as revoked. so if i, at this point update my shared preference for this sku (as either locked or unlocked, revoked will mean it is locked and purchased means it's unlocked) it will be locked. but it should be unlocked as i re-purchased it! the way i understand it, is that there must be a way to distinguish between the revoked and purchased sku - the way i understand it is that, for example a record is kept of each revoked sku. so lets say i purchase the same sku 10 times and cancel it 10 times, then each time i call getRevokedSkus() (after the 10th cancellation) it will list the 10 items (of the same revoked sku). is this correct? so, i think my question is, what do i do to make sure my shared preferences for the purchased entitled item reflects the current state for this item (as the way i am approaching it, by trying to accommodate revoked items, each time i use getRevokedSkus() to update the current state of my entitled items, it ends up nullifying my entitlement) - obviously i'm doing something wrong. so how to deal with current purchased entitlement separate from previously purchased entitlements that were revoked? hope i'm making sense appreciate some help thanks regards 101apps
just thought that my question may be easier to understand if i say that i'm expecting the item (sku) to be either ON (a successful purchase) or OFF (it has been revoked. but i don't think that this is how it is handled. hope it makes sense thanks regards 101apps
Hi 101apps, I think your understanding is not fully correct. When you purchase an entitlement and come out from app and launch sdk tester to cancel the transaction and then again go back to your app, you would be notified about the sku revocation for only once. And to receive it, you are supposed to call initiatePurchaseUpdates() from onResume (to ensure when ever you are launching the app, you are getting the latest updates about your purchased items) and you would get a call back to the onPurchaseUpdatesResponse() of your observer class. So after the 10th cancellation when you are back to app (with onResume called), you should receive a single item in the revoked sku list. Once the revoked sku and receipts of purchased items are delivered to your app, the Que would be flushed and if you call initiatePurchaseUpdates again without any transaction, onPurchaseUpdatesResponse would return empty lists of receipts and revoked sku. So once you are notified about revoked sku, you need to update your items inventory status, so that the revoked item is made available for further purchase. Please note, if you find any sku in the receipt list of onPurchaseUpdatesResponse, that is not delivered to user, you are supposed to update the items inventory to credit the item to user (this way the fail over should happen for a transaction which was successful but unable to notify your app through onPurchaseResponse due to network disconnect, power loss, or similar). Hope this clears up your understanding. Thank you for writing to us.
hi thanks for the reply. i understand it better but i still have the problem: i can cancel an entitlement in the SDK tester. then in onPurchaseUpdatesResponse the SKU is listed as revoked. you say that once it this is delivered to the app, the queue is flushed and that the revoked list should be empty the next time initiatePurchaseUpdatesRequest is called. i am finding that this is not happening. each time initiatePurchaseUpdatesRequest is called, the list of revoked SKU's remains filled with the revoked SKU's. in other words it is not flushing. also, you say i should call initiatePurchaseUpdatesRequest from onResume() but the documentation says to call it from onStart() - is this a major issue? i've tried it from both but still have the problem. please help thanks 101apps
On a new initiatePurchaseUpdatesRequest the response pattern is shown below For example : com.amazon.amazonapidemos V/Amazon-IAP﹕ onPurchaseUpdatesRecived recieved: Response -(com.amazon.inapp.purchasing.PurchaseUpdatesResponse@41923028, requestId: "8xxxx2-9xd0-4xe9-aexa-2b8e33xx6dxx", purchaseUpdatesRequestStatus: "SUCCESSFUL", userId: "DefaultTestUser", receipts: , revokedSkus: , offset: "1381408569763", isMore: "false") secondly initiatePurchaseUpdatesRequest can be called from anywhere. You can use the sample application and check the flow by adding logs in different stages of the activity lifecycle and add logs in observer class also. wherever you go out and get back to the activity, on resume you can get the userId by calling initiateGetUserIdRequest and then Call initiatePurchaseUpdatesRequest for the returned user to sync purchases that are not yet fulfilled. The main benefit is that, you can play with multiple devices with same userID and have same context of the game in all the devices.
hi, thanks for the response, unfortunately i am still struggling with this. i have gone through my code over and over again, comparing it to the buttonclicker example but still cannot find a problem. my problem still remains, the revoked set in onPurchaseUpdatesResponse is never empty, it keeps all the revoked items. so i can make a purchase, i check the tester and the purchase is there. i cancel the purchase in the tester (which should register as revoked when onPurchaseUpdatesResponse is called, and it does). but now according to a reply to an earlier question (see above) the set should be empty on the next call and it is not. the revoked set shows this revoked item (and any other revoked items) and continues to do so no matter how many times i purchase/cancel an item. checking the documentation, i see that getRevokedSkus() "Returns revoked SKUs, or an empty set if (1) is not PurchaseUpdatesRequestStatus.SUCCESSFUL or (2) there are no revoked sku's" 1) so is it correct to show the revoked sku's in the set as i described above (i.e it will never be empty as long as one sku was revoked) ? 2) if not, then where should i look for the reason that it is not showing an empty set? i've literally spent days trying to fathom this one out but can't see where i'm going wrong as everything else seems to work perfectly! really would appreciate some help thanks regards 101apps
okay, found the problem: it was due to an incorrect OFFSET which resulted in the revoked set always containing the set of revoked sku's in the PurchaseUpdatesResponse object passed by the initiatePurchaseUpdatesRequest call. in PurchaseUpdatesAsyncTask i incorrectly placed the call to save the newOffset as a preference within the purchaseUpdatesResponse.isMore() if statement (so it was never saved as a preference) instead of before. so whenever initiatePurchaseUpdatesRequest was called, it used whatever was saved as the offset preference (which was incorrect) and therefore always returned a set of revoked sku's in the PurchaseUpdatesResponse object. took me a long time to work that out hope it helps someone cheers
newOffset is commited in SharedPreferences and then we check if there are more in purchaseUpdatesResponse to continue the loop till we update all the purchase. If there has been more purchases since the last time our application updated, another initiatePurchaseUpdatesRequest is called with the new offset.