I have in-app purchases set up so that when a user clicks on the buy button, a "Please Wait" view appears and adds a payment to the payment queue. This always causes an immediate callback of the queue's observer saying that the transaction entered the "Purchasing" state.
My problem happens when the user returns to the main screen before the confirm to purchase dialog pops up, then cancels. If I wait around on the main screen awhile before switching back to the application, the application never gets any callback about the transaction switching state or being removed. If I examine the payment queue, I can see that the transaction is still in the queue, still in the "Purchasing" state. Is there anything I can do to make it call back and remove it from the queue after resuming the application?
If I understood your situation correctly, you've encountered this problem:
In App Purchase user cancels tx while app in background: tx state stays on purchasing
This appears to be a bug in Apple's Store kit. The issue can easily be reproduced if you send your app to background right after initiating a purchase and then pressing the cancel button when the buy confirmation popup is prompted. Your app will never receive the transaction failed(cancelled) notification and will enter a blocked state (if you disabled the UI trying to prevent the user from interacting with the app until the purchase has finished).
We have to wait for a fix from Apple. In the meantime, if your app is entering a blocked state because you disable UI while making a purchase; you should implement some mechanism to allow the user to leave that state.
Good luck!
I have the same problem, however, I have only managed to reproduce it when using a sandbox appstore account.
Has anyone managed to reproduce it using a real apple account?
I've not tried this yet, but I am thinking about removing my SKPaymentTransactionObserver the moment the app loses focus, and the adding it again when it next becomes active.
The weird thing about about this bug is that you get stuck with a transaction in the purchasing state, however when you properly shutdown the app and the restart it you would expect that transaction in the purchasing state to still be there, however it is not... As if the re-adding the SKPaymentTransactionObserver has triggered it to properly re-evaluate it's state.
Related
I make a fresh install of my App on my iOS device. (I had deleted it, signed off from the GC account).
After the App launch, 'paymentQueue: updatedTransactions:' gets called. It has one transaction with transactionState' == SKPaymentTransactionStatePurchased. (It's the only iAP my App has, in fact).
And then the GC Sandbox Login ViewController is presented.
Why does the iAP object get the Bought State, if I haven't logged in neither with an iTunes account or GC account?
I am not login on Game Center, that's for sure. But I'm not so sure about being being logged in with an iTunes Store Sandbox account. (Does that even exist?) If so, how do I log off?
I want to be able to test my App's 'Restore' button, but as the function already gets called, and the item is shown as bought, I can't... Why does even the function get called when I add the observer to the SKPaymentQueue? To check unfinished transactions? But it shouldn't do so as I'm not supposed to be logged into an iTunes Account...
Please, tell me any ideas you have, this is making me go crazy.
It sounds like you might be failing to call [SKPaymentQueue finishTransaction:] after your transaction is processed - the IAP system will keep attempting to deliver the transaction on every startup until you do that. So just add that call when you're done processing the transaction and you should be all set.
My iPhone app includes a subscription service for a web server, which Apple insists that I make available as an in-app purchase. However I not entirely happy about the way the user dialog pans out. Some time after the app submits the purchase to iTunes, the user gets a confirmation request from iTunes. But this could happen at any time after the purchase is submitted.
I am wondering whether my app should pop up an alert, after the submission is made. Is there a standard procedure for this? If the confirmation request comes back straight away, then the user would see two alerts one after the other, which could be confusing. On the other hand, if he is going to have to wait a while, it would be nice to let him know that this is the case.
Is there a standard procedure for this?
I think standard procedure would be to disable user interaction and show a spinner, or otherwise let the user know that the transaction is pending. You can then handle the purchase if it comes back, or implement a timeout and then show a pop-up notifying the user that the transaction could not be completed.
If you really don't want to make the user wait for completion before continuing in the app, I would put your notifying pop-up before you send the request. So when the user presses the button, you pop-up and say "This may take a while", and when they press "OK", THEN you send the request. Personally I don't think this is particularly good UX though, since in the majority of cases it will not take very long.
My question is basically how to reproduce the behavior I see in other apps in the app store with regards to in-app purchases:
Immediately following the user pressing "Buy" the button is hidden and a spinner is displayed (essentially de-bouncing the Buy action).
The user pressing cancel to the StoreKit dialog (in the app or outside of it) results in the spinner going away.
I'm attempting to show and hide the spinner based on observing the state of transactions in the SKPaymentQueue.
My problem is described by this poster:
In App Purchase user cancels tx while app in background: tx state stays on purchasing
I see the same behavior as the post above regardless of if the test user is logged in first or not. The transaction is basically "stuck" in the queue with a purchasing state forever (meaning my spinner is displayed forever). When the app is completely exited and restarted (not just multi-tasked away) the transaction is no longer in the payment queue so it's clearly not really still purchasing. It's like the SKPaymentQueue "missed" the state change.
Some more detail that I've noticed is that in the typical case, immediately after adding the payment, the transaction shows up in the queue with a purchasing state. If the user presses cancel, the state of the transaction goes to failed.
In the case of tasking away immediately after adding the payment, the transaction does not show up in the queue until tasking back to the app. Instead of seeing two calls to the updatedTransactions delegate (one with a state of purchasing and one with a state of failed) there is only one call to the updatedTransactions delegate with a state of purchasing. The transaction never goes to failed.
Very occasionally, when tasking back to the app I will get a transaction removed callback (after seeing the updatedTransaction with a state of purchasing). Even in this case I never see the expected update of the transaction to the failed state.
I am not able to reproduce this behavior in apps in the app store (they always correctly show/hide the spinner regardless of tasking away or not), but it's not clear to me if that's because they are doing something tricky, or if it's only a problem in the sandbox.
How to replicate this behavior if not by monitoring the state of the transaction? Is this not a problem in production?
Thanks!
I have used MKStoreKit for all my apps.
It has a block based interface that tells you when the transaction has started (To hide the button and start animating).
It will also tell you if the transaction fails or it was competed, so you can stop the animation and restore the button (if it failed) or show something else when it is completed.
Because it uses blocks, you can handle all this behavior without writing a lot of boilerplate code.
I am running into a problem here. I am able to receive, capture and save an APNS message just fine if I do it while my app is running or if I click "View" when it comes in if the app is closed.
The problem I am running into is.. If the app is NOT running and I receive a APNS message and chose to look at it later by selecting "Close"... the next time I open the app, the app is not opening "with options". Therefor, the APNS message is lost. The same thing happens if the screen lock comes on before "viewing" the APNS message.
How do I handle this?
Thanks in advance!
Don’t assume that push notifications will make it to your app—their delivery isn’t guaranteed, even if the user doesn’t “close” the alert a notification brings up. Your server should have the authoritative state of whatever notifications your app needs to display when it launches, and the app should check that state regardless of whether it’s launched from a notification or not; one reason for this is that if your app receives multiple notifications while in the background, only one of those notifications will get delivered to the app when the user chooses to view it.
I have to implement In App Purchase Auto-Renewal Model in my app. I have created a test user and getting the response from App Store for subscription. When I tap "Confirm" then sometimes its state becomes SKPaymentTransactionStatePurchased and sometimes it becomes SKPaymentTransactionStateRestored. My problem is that I want to prevent user to use the app if he has not subscribed the app. For that I am trying to track the state of "SKPaymentTransaction" so that I can allow or disallow the user to use the app. Such that, if the state is SKPaymentTransactionStatePurchased, only then he could be able to use the app, but I don't understand how its state changes.
One more thing, When I tap on the "Settings" to manage my Auto-Renewal, it shows me that my app will be expired on the current date i.e., today itself, but when I tapped on the "Confirm" button to subscribe my app for one month then expiry date should be after one month. I don't understand how this whole process is working.
I have read whole documentation of Auto Renewal, but didn't get any help from that.
Please help!
Not sure about your first problem. In my case, I can never get SKPaymentTransactionStateRestored called at all. I am debugging why.
Meanwhile, I was facing the second problem you described. When I decoded the receipt, it looks like they keep the subscription valid for 5 mins. Sounds like a feature for testing in sandbox. At least that's what I am assuming.