restore problem in in-app purchase

Hi, 

I have a non-consumable product, i purchased it in sandbox environment on iphone using store.purchase, its working fine, but when i try to restore using store.restore(), i dont get that callback called which i defined in store.init.

Please help.

Thanks,

Hi there,

Consumable products can’t be restored.  Only non-consumable products (and certain types of subscriptions) can be restored.

  • Andrew

I have edited my question, its actually a non-consumable product, please suggest why the listener is not called in this case.

OK, it would be helpful if you posted your code so we can take a look.

  • Andrew

To initialize, I  used , 

 if ( store.availableStores.apple ) then

            currentProductList = appleProductList

            store.init( “apple”, storeTransaction )

end

Then loaded products using, 
 store.loadProducts( appleProductList, loadProductsCallback )

got response, and in response I called, 
 store.purchase( validProducts )

all went fine, i got success in storeTransaction method

function storeTransaction( event )  … end 

then for testing Restore: i called store.restore()

but “storeTransaction”  method didn’t get called.

Could this be the issue?

If you take a look in the Corona supplied example code, the store.finishTransaction is extremely important. You will not

be able to restore the transaction until you have called this function.  

When re-initiating the store,  the previous transaction will be returned to you in the callback and demands to be completed with the function above.

Yes, if you don’t call store.finishTransaction() within the storeTransaction callback, you’ll have a problem.

@contact130, it would be much more helpful in debugging your issue if you actually copy/pasted your storeTransaction callback function.

Also, how do you know the callback isn’t called?  Do you have print statements within it that aren’t printing?  Or is it just not having the effect you expect it to?  If the print statements aren’t printing, then maybe it’s actually not being called.  If it’s not having the effect you expect, then perhaps the code is simply wrong.

  • Andrew

ok here is my code

first i created buttons and their event listeners

 local inAppHelper = require "inAppPurchase" inAppHelper.initialize() -- METHOD DEFINED IN SECNOD CODE BLOCK local purchasebutton=display.newImage("Purchase.png") purchasebutton.x=200 purchasebutton.y=330 purchasebutton:scale(0.5,0.5) screenGroup:insert(purchasebutton) purchasebutton:addEventListener("tap", onBuyNowButtonClick) local restoreButton=display.newImage("Restore.png") restoreButton.x=200 restoreButton.y=200 restoreButton:scale(0.5,0.5) screenGroup:insert(restoreButton) restoreButton:addEventListener("tap", onRestoreButtonClick) function onBuyNowButtonClick() inAppHelper.loadProducts(transactionCompletionListener) end function onRestoreButtonClick() inAppHelper.restorePurchase() end

I have created a method “log” that simply shows the native alert, because i can not see print statements while running the app on device, so i call this method to debug.

function log(message) native.showAlert("", message) end

then in inAppPurchase.lua, 

-- TO INITIALIZE THE STORE function initialize() if ( store.availableStores.apple ) then currentProductList = appleProductList store.init( "apple", storeTransaction ) elseif ( store.availableStores.google ) then currentProductList = googleProductList store.init( "google", storeTransaction ) else log( "In-app purchases are not supported on this system/device." ) end end -- TO LOAD PRODUCTS function loadProducts(completionListener) listener = completionListener alert.showLoader("Retrieving Products...") if (store.canLoadProducts) then if ( store.availableStores.apple ) then log("going to load apple products list") store.loadProducts( appleProductList, loadProductsCallback ) end else if ( store.availableStores.google ) then alert.showLoader("Loading...") store.purchase( googleProductList ) else log( "this store does not support an app fetching products" ) listener(true) end end end --- AND THE CALL BACK IS local function loadProductsCallback( event ) alert.hideLoader() local validProducts = event.products local invalidProducts = event.invalidProducts for i = 1,#validProducts do local currentItem = validProducts[i] -- log("Title = ".. currentItem.title.."Description = "..currentItem.description.."Price = "..currentItem.price.."Product Identifier = "..currentItem.productIdentifier ) alert.showLoader("Loading...") store.purchase( validProducts ) -- SINCE I HAVE ONLY ONE PRODUCT.. DIRECTLY CALLING PURCHASE end end -- AND FINALLY THE TRANSACTION CALLBACK IS function storeTransaction( event ) alert.hideLoader() local transaction = event.transaction if ( transaction.state == "purchased" ) then log( " Transaction successfully completed" ) elseif ( transaction.state == "cancelled" ) then log( " Transaction was cancelled" ) elseif ( transaction.state == "restored" ) then log( " Transaction RESTORED SUCCESSFULLY" ) elseif ( transaction.state == "failed" ) then log( " Transaction was failed because: "..transaction.errorString ) elseif ( transaction.state == "refunded" ) then log( " Transaction REFUNDED" ) log( "productIdentifier", transaction.productIdentifier ) else log( "transaction state is: "..transaction.state ) end store.finishTransaction( event.transaction ) end -- RESTORE METHOD function restorePurchase() alert.showLoader("Restoring Products...") store.restore() end

Working on iOS for now:

As mentioned in the code, First I call initialize store, then I click buy, it first loads products, and after loading calls store.purchase, after giving my account credentials, i get the callback called and it displays native alert saying " Transaction successfully completed".

Then I click on restore button, which calls the method inAppHelper.restorePurchase(), it asks for account credentials, i enter them, but i get no native alert.
 

may be store.finishTransaction is not working properly. I’m using the daily build 2013.1193

Please let me know if i’m doing anything wrong in the code.

also can you please share with me the sample IAP code, i couldn’t find it yet.

Thanks,

Hi again!

Hm, it looks like the store.finishTransaction would be called…

The sample code I was refering to is included in the installation of CoronaSDK. (On a mac: CoronaSDK/SampleCode/Store/InAppPurchase)

This code works, but I would comment out all code in the transactionCallback were it says:

descriptionArea.text = infoString

That is because, if you get the scenario I described above the descriptionArea is not created at first init and will give you a runtime error. (And the store.finishTransaction will not run.)

By the way, have you created a InAppPurchase test user in iTunesConnect? If you use the the developer provisioning profile, i don’t think you can make a valid purchase on a real appleID.

yes I have created a test id on itunesconnect, and with that im able to make successfull purchase in sandbox environment.

I’d suggest not using native alerts for debugging.  Instead, use print statements and look at the output in the Xcode console log.  Here’s a blog post with instructions how to see it: http://www.coronalabs.com/blog/2013/07/09/tutorial-basic-debugging/.

In fact, the fact that you’re using native alerts for debugging may actually *be* the cause of the problem.  I’ve occasionally run into some funky behavior on iOS when using native alerts in quick succession.  Since only one native alert can be displayed at a time, trying to display more than one, or trying to display one too soon after a previous one was dismissed, can cause unexpected behavior.  This is especially important in the IAP flow, since the IAP flow itself uses native alerts generated by the OS to prompt for the user’s password and confirm the transaction.  I also notice that in your transaction callback, you call your log function twice, which attempts to display two native alerts immediately, which again, may be the source of the issue.

  • Andrew

@aukStudios

Thanks, I figured out the problem by checking the Xcode device logs, there was a line of code i was printing on successful purchase event, that is, 

log("productIdentifier = ".. transaction.productIdentifier.."receipt = "..transaction.receipt.."signature = "..transaction.signature.."transactionIdentifier= "..transaction.identifier.."Date = "..transaction.date)

and for some reason transaction.signature was nil, app was crashed at this point and hence store.finishTransaction didn’t get called. 
after crash, UI was still responsive, and I was trying to restore.

removing this lead to the successful purchase, and successful restore.

Thanks Again,

In Google play,If it is possible to test IAP restore using android.test.purchased.because already i quested about this.but the answer is in Google play return restore state as a purchased state but i tried usingandroid.test.purchased but no wonder.so if restore only work in live product id means i am going to buy one product and check.so please help me to give some suggestion.

For Google Play, restored transactions are always returned as “purchased” events (take a look at the Restored Purchased Items section of the documentation here: http://docs.coronalabs.com/guide/monetization/IAP/index.html).  That’s just the way Google Play works – there’s no way to change it.  So your code needs to handle this case appropriately.

  • Andrew

Hi there,

Consumable products can’t be restored.  Only non-consumable products (and certain types of subscriptions) can be restored.

  • Andrew

I have edited my question, its actually a non-consumable product, please suggest why the listener is not called in this case.

OK, it would be helpful if you posted your code so we can take a look.

  • Andrew

To initialize, I  used , 

 if ( store.availableStores.apple ) then

            currentProductList = appleProductList

            store.init( “apple”, storeTransaction )

end

Then loaded products using, 
 store.loadProducts( appleProductList, loadProductsCallback )

got response, and in response I called, 
 store.purchase( validProducts )

all went fine, i got success in storeTransaction method

function storeTransaction( event )  … end 

then for testing Restore: i called store.restore()

but “storeTransaction”  method didn’t get called.

Could this be the issue?

If you take a look in the Corona supplied example code, the store.finishTransaction is extremely important. You will not

be able to restore the transaction until you have called this function.  

When re-initiating the store,  the previous transaction will be returned to you in the callback and demands to be completed with the function above.

Yes, if you don’t call store.finishTransaction() within the storeTransaction callback, you’ll have a problem.

@contact130, it would be much more helpful in debugging your issue if you actually copy/pasted your storeTransaction callback function.

Also, how do you know the callback isn’t called?  Do you have print statements within it that aren’t printing?  Or is it just not having the effect you expect it to?  If the print statements aren’t printing, then maybe it’s actually not being called.  If it’s not having the effect you expect, then perhaps the code is simply wrong.

  • Andrew