You indicated that - "Two things happen at the same time: First is that I get the message that the payment was successful and at the same time (probably even a little earlier than the success message) I get an error that goes "Cannot connect to the iTunes Store".
Could it be that before you confirmed the payment that you had to update your credit card info? The symptoms you provided were - 1 the payment was successful, but the app got an error. When I hear this user level symptom, I think "Interrupted purchase flow". I've included a response on this issue below.
You then state that your app installs the transactionObserver in the didFinishLaunchingWithOptions delegate method - this is good. So what happens when you force quit the app and relaunch the app. Supposedly since the In-App Purchase has been charged for, the iTunes Store has created an incompleteTransaction which is pending completion. Relaunching the app means that the transactionObserver will be installed which should detect the incompleteTransaction. Note that the restoreCompletedTransactions method only restores "completed" transactions - those transaction notifications which the app has called finishTransaction on.
There may be a bug report here in that the app is only seeing the failed transaction notice here and not the following successful transaction. However, force quitting the app and re-launching it should get the purchase recognized, if the transactionObserver detects it.
Here's my interrupted purchase flow description
The interrupted purchase flow situation occurs whenever StoreKit determines that there is a problem with the user account making the purchase - the name stems from the fact that the application purchase process is interrupted and the application is backgrounded while the Settings app comes forward to either.
1. have the user fix / update their credit card info
2. agree to a new StoreKit Terms and Conditions.
Upon fixing the issue, the user is asked whether they want to continue with the purchase process. When they agree, StoreKit processes the purchase request, then will present a dialog that the purchase was successful.
While this is happening the iAP app is in the background, there is no notification to the app that the purchased was successful. So how is the app informed of the successful purchase. The notification process relies on the transactionObserver being and remaining active through the lifecycle of the app.
On the server side, when the interrupted transaction flow is detected, the server automatically queues a failed transaction event for the app and user. This occurs because the user might not fix the failure issue. When the user does fix the issue, then the successful transaction event is queued behind the failure event - again on the server - there is no notification to the app while it remains in the background.
In the normal situation, the user brings the app to the foreground. Assuming that the transactionObserver is active - it gets activated when the app is moved from the background to the foreground. The transactionObserver sends a query to StoreKit asking if there are any queued transactions to process - In the interrupted flow situation, the failed transaction is returned first. The updatedTransactions delegate method is called with the failed transaction indication. As per the StoreKit guide, the application must call finishTransaction on this failed transaction.
Next, the StoreKit returns the queued successful transaction to the app. The updatedTransactions delegate method is called with the successful transaction indication. After processing the successful transaction indication, the app calls finishTransaction. Until the finishTransaction is called, a transaction is considered “incomplete”.
Note that in the case of the interrupted purchase flow - a single call to addPayment can result in both a failed transaction event followed by a successful transaction event.
So what happens if after fixing the situation as described above, if the user does not return immediately to the app, and for some reason, iOS jettisons the app to make room for some other app. In this case, the failed and successful transaction remain incomplete on the StoreKit server. When the app is relaunched, and if the addTransactionObserver is not called in the didFinishLaunchingWithOptions delegate method as per the StoreKit Program Guide and the iAP Best Practices Tech Note 2387
<https://developer.apple.com/library/ios/technotes/tn2387/_index.html#//apple_ref/doc/uid/DTS40014795>
the incomplete transactions are not processed. As the transactions are incomplete, the restoreCompletedTransactions method will not restore them.
One could argue that the app could check the application receipt, but to my knowledge, the app receipt is updated when the transactionObserver processes a transaction or when the SKReceiptRefreshRequest is issued.
Of course, this is all a guess on my part. I’d check to see if your app calls addTransactionObserver in the didFinishLaunchingWithOptions delegate method.
As for the handling of the customer, if this is a non-consumable purchase type, he can attempt the purchase a second time - StoreKit will detect that he’s already purchased the item and that will be restored for free. The transaction will be process interruption free and should be completed.
Some additional notes
1. To replicate the interrupted purchase flow situation, install the production app, then enter the Settings app and clear out the credit card info for the current user. Now launch the in app purchase app and attempt a purchase
2. the interrupted purchase flow process cannot be replicated in the development environment - I’ve advised developers to submit an enhancement request using the Apple Developer Bug Report web page - http://bugreport.apple.com to request that iTunesConnect provide a means to simulate an interrupted purchase flow process to test in app purchase apps under in the development environment. However, the StoreKit programming guide, in the test procedures does present a means to replicate an incompleteTransaction in the sandbox by interrupting the application in the updatedTransactions delegate method in the Xcode debugger, then relaunching the app to see that the transactionObserver detects the incompleteTransaction on app relaunch.
rich kubota - rkubota@apple.com
developer technical support CoreOS/Hardware/MFI