My app only offers consumable in-app purchase products.
I can successfully purchase a product once but when I try to purchase it again, a popup "This In-App purchase has already been bought. It will be restored for free." appears and the first transaction is restored: the payment queue delegate is notified that a new transaction (with the same identifier as the successful transaction) is updated to the purchased state. I never get a purchased transaction with a new identifier and hence consider that the purchase failed.
Also, each time the app is put in foreground again or at startup, the payment queue delegate is notified that a transaction has been updated (as if it had never been finished). Even though the app properly finishes the transaction each time.
Side notes:
I guarantee that all purchased or failed transactions are finished (confirmed by the SKPaymentQueueDelegate removedTransactions method being called each time). I even tried to call finishTransaction from the main thread with no success.
Right before the subsequent purchase attempts, the transactions queue is empty.
I'm also pretty sure I was able to purchase several times the same product last week, with no change in code (same app version from Testflight).
I observe this behaviour when building the app with Xcode or when distributed via Testflight. It has not been published yet so I cannot check how it behaves in the Production environment.
Do you have any clue on what's going on? Could it be a side effect of using the Sandbox environment?
Thanks for your help,
The issue has disappeared yesterday, what other developers have confirmed.
It definitely was a Sandbox issue and it would have been nice if Apple engineers had confirmed it too...
Related
I'm getting a weird error with in-app purchases for a project.
The client’s reporting that when they purchase an auto-renewing subscription, nothing happens; logging indicates that the app is correctly adding the payment to the queue, but it never gets any state change notifications on that transaction (i.e. it stays in the Purchasing state forever).
When the app launches, it registers as a listener to the payment queue (as per Apple's guidelines), and it sees the transactions from earlier still there, and still in the Purchasing state. For example, in one log that I've received, it's found that there are six transactions in the queue, and all of them are in the Purchasing state.
What I suspect is happening is that a payment has gotten stuck somehow in the Purchasing state, and has never transitioned to Purchased or Failed. As a result, other transactions are piling up behind it. However, my searching hasn't found any other reports of this kind.
The end result here is that there's never any UI that appears when the user, on some (but not all) of their devices, begins an in-app purchase.
My background reading suggests that it's potentially related to the following questions:
Multitasking and SKPaymentQueue I get a "stuck" SKPaymentTransaction with a transactionState of SKPaymentTransactionStatePurchasing
SKPaymentTransactionObserver not getting a callback on app switch
However, when I attempted to reproduce their behaviour (of switching away from the app in the middle of a transaction) by pressing the Home button to switch away, the button press was ignored by the system; I tried to force the issue by killing the app from Xcode, but that actually just kept the UI on screen while the app was removed.
This issue isn’t being reported by all testers, and I’m not able to reproduce it myself, but the log is very clear about what the purchases are doing on the devices encountering this problem. My question: under what circumstances could a purchase be ‘stuck’ like this?
For context, this is all on the sandbox environment, and on iOS 11.2+.
I have a Xamarin app for iOS with in-app purchases. During testing I've purchased one consumable product but did not finished the transction (crashed on error). Now if I reinstall the app it allows to purchase this product but of course restores it instead and show message "the product was restored for free".
This behaviour is expected, but UpdatedTransactions of queue listener was not fired. I could check the queue directly via StoreKit.SKPaymentQueue.DefaultQueue.Transactions, but I need to know when user interaction finishes (user presses OK in that message dialog). But no listener methods are fired.
As I understand from Apple docs there must be transactions' update after this. Maybe it is fired BEFORE I try to purchase. But then, should I check the queue manually before the purchase?
I'm not using Xamarin, but StoreKit is underlaying iOS feature, therefore it cannot work otherwise in Xamarin. The event must be fired earlier. As soon as you add transaction observer ([[SKPaymentQueue defaultQueue] addTransactionObserver:self]), you will receive update callback with all pending transactions. If this is done when app is launched (and it should be), by the time you reach purchase screen you will have transactions updated. For me, this is the trickiest part of IAP development as you have to handle them on application start as well as in all of the screens where you have them and callbacks can happen anytime.
Please also note, that this pending transaction might appear multiple times on the transaction list (I was mainly using non-consumables, so new transaction is added every time you relaunch the app without closing all the pending transactions). For that purpose I had component that is being added as transaction observer as soon as app starts, listens for updated transactions and stores them in instance variable for later use. Before starting a new purchase, I would check if there's a pending transaction with same product id and act accordingly.
Hope this helps.
Here is my situation: in my app I have a set of consumable in-app purchases. All purchases sent to server to be validated and activated. But there is a possibility to encounter situation when user performed a purchase (paid money) but something happens during purchase activation (lost connection, server error, etc). In result both app and server do not know about purchase (lets take situation that app lost purchase data for some reason). So I need to get user's purchases/transaction from app store.
I've tried [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
but it does not return consumable purchases.
Is there any way to get a list of all purchases/transactions from app store?
Two possibilities:
1) If the interaction fails with your server, don't finish the transaction (ie, don't remove the transaction from the queue). That way your transaction observer will get it again and you can try your server again.
2) Finish the transaction, but store enough info on the app (eg, NSUserDefaults) to try again with the server later. You can start a timer that will try again later.
I have a couple questions regarding the process of detecting that a subscription has been auto-renewed.
Currently I have my sandbox test environment all set up, I am able to purchase a 1 month subscription and all of that works nice and dandy.
My questions are as follows:
Do I need to verify the initial receipt (or really any subsequent receipts) of the in app purchases? If so, for what reasons?
Does my app get notified via a paymentQueue:updatedTransactions: call when the auto-renew has happened? Both in the sandbox environment and in the production environment.
So far, I have not seen the StoreKit notify me of a renewed subscription (in the sandbox environment) but I have also read that it is finicky and might not.
Any general tips with Auto-Renewable subscriptions that I should take into account?
Thanks for your help and time!
1. Regarding Receipt Validation
Receipt validation is your means of performing extra security checks before you unlock the users content. Think of a receipt as a lotto ticket. A client comes to you with the "Winning Ticket". Depending on how valuable you consider the reward to your Lottery you can either give said individual their winnings, or you can contact Apple and check whether the user actually purchased this ticket through them.
The client could have got this lotto ticket through some malicious means be it a jail broken device etc and so its really up to you to decide whether you want to verify the receipt or not.
2. Regarding Renewal Notification
The official documentation states the following:
After a subscription is successfully renewed, Store Kit adds a
transaction for the renewal to the transaction queue. Your app checks
the transaction queue on launch and handles the renewal the same way
as any other transaction. Note that if your app is already running
when the subscription renews, the transaction observer is not called;
your app finds out about the renewal the next time it’s launched.
So you should definitely be getting receipt renewal notifications in your app. Don't forget that you should always add yourself as the observer of StoreKit's paymentQueue in order for this to work, something like this in your app delegates didFinishLaunching would work:
//where YourObserver is an object that is alive for the apps lifecycle
[[SKPaymentQueue defaultQueue] addTransactionObserver:YourObserver];
I have an app using the non-renewing subscription model. It works great when using in-app purchase test accounts. However, on Apple's production servers, sometimes the user gets taken away from my app to the app store for one reason or another (sometimes it's because of updated billing info, sometimes it's to answer security questions). This is after the payment has been added to the queue and in Apple's own payment flow. Once the user hits the alert view option to go into the app store, my transaction Observer gets a transaction with the SKPaymentTransactionStateFailed state. That's fine. However, after the user updates their billing info or confirms their security question, they're asked (still outside the app) if they still want to purchase the in-app purchase. When that goes through, they are taken back to my app (which has closed itself), and nothing comes back from the transaction observer. The queue only gets updated with the purchased product when the list of products is retrieved. The observer registers for notifications before
So my questions are:
How do I handle purchases made outside my app (in the app store app)?
If there are purchases made before the app opened (but not completed), at what point does the queue get updated? I know that I should have the observer going at all times, but I want to avoid having the user purchase the item twice, not knowing they had already purchased it.
Through some trial and error, I seemed to have solved my problem
It turns our that I wasn't initializing my transaction observer for SKPaymentQueue soon enough. It needs to be initialized and added as a transaction observer in the application:didFinishLaunchingWithOptions: method, and no later. As for when the transaction comes in, the paymentQueue:updatedTransactions method of your transaction observer will get called with a purchased transaction the next time your app is active. It's important to note that your app may or may not close once for one reason or another when you're taken to the App Store, and if it does end up closing, the method will get called the next time the app opens.