Apple states that all apps using in-app purchases have to put this
[[SKPaymentQueue defaultQueue] addTransactionObserver:self.observer];
at the beginning of the app to handle for any successful sale that for some reason the device has not received the confirmation to release the content.
I am trying to test this, trying to call the phone when it is about to finish the transaction, quitting the application or stopping Xcode before the transaction finish, but for some reason, even when I quit Xcode, iOS appears to continue handle the transaction and the app never receives the SKPaymentTransactionStateRestored. The app always receive the SKPaymentTransactionStatePurchased and appears to be fail proof (perhaps the new iOS 4 handles that better than the 3.2 when StoreKit was released).
My question is: do you guys know any situation I can create here to generate the failure and receive the SKPaymentTransactionStateRestored when the app starts? I need to test if the app is working well for this kind of situation.
thanks
SKPaymentTransactionStateRestored is only for when you call restoreCompletedTransactions (so a user can restore their in-app purchases on a new device). If you quit the app without calling finishTransaction:, the transaction stays in the queue and you will get SKPaymentTransactionStatePurchased again.
Related
When I first developed an inapp purchase solution for an iOS app, one of the annoying things was that calling [[SKPaymentQueue defaultQueue] restoreCompletedTransactions] would ask the user to verify their Apple ID every time, popping up the dreaded password dialog. I was testing this against iOS 8 & 9.
Skip forward a few years and now I have noticed that on iOS 12.1, calling [[SKPaymentQueue defaultQueue] restoreCompletedTransactions] doesn't show that dialog unless the user has signed out of their Apple account under Settings.
So I'm wondering, what version of iOS stopped showing this dialog on every call to that function?
I wish I had a pile of iOS test devices with all the old versions, but unfortunately I only have devices running iOS 12 so I can't test this out myself.
The reason I want to know is because being able to call that method without invoking the stupid dialog means I can potentially use it as a background method of checking what purchases a user has made on starting/resuming the app.
Once I know which iOS version stopped asking for Apple ID verification on every call to restore, I can add some conditional logic to only do this on or above that iOS version.
I have an app where non-consumable inapp purchases allow content packages to be downloaded to the device.
Users often use my app across their iOS devices and so currently they have to manually sync the purchased content between devices using the "Restore purchases" button.
However, if I can call restoreCompletedTransactions in the background to obtain a list of their owned non-consumable purchases, I can diff that against the content packages already downloaded to their device and therefore automatically restore content packages for purchases they've made on other devices.
This is something I've been able to do on Android for ages and users ask why the app can't do the same on iOS.
(BTW I know the way of doing this recommended by Apple is to store the receipt of purchase from Apple on my server and use this to verify re-downloading of content, but for various reasons this was not possible)
I'm adding In-App-Purchase (IAP) to my App. I've followed all the guidelines regarding setting up a test user for the Sandbox and logging OUT of the real App Store account. While testing I was buying and cancelling. At one point the device re-sync'd with iTunes and apparently restored and re-connected me to the production store. I didn't notice this until an attempt to buy didn't produce the normal login dialog, which I cancelled. Since that point I've been getting SKPaymentTransactionStateFailed in:
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
And the error SKError in the Error object indicates: SKErrorPaymentCancelled which was true but also happened days ago.
I get this regardless of if the device is connected to the internet or not (even if wifi is off). It appears to have cached the fact that the transaction was cancelled someplace and is stuck. Nothing clears it that I have tried including:
Creating a new test user and deleting the old one.
Deleting the App and re-installing.
Deleting the test products that generate this.
Clean and re-build the project including build folder.
Resetting the device and all the other voodoo.
Any ideas what is going on here? How does one clear what is cached? It doesn't appear that I am required to acknowledge that fact to the store in anyway. Furthermore, what I find really odd is that I get these SKPaymentTransaction notifications at launch, EVEN if the device is offline?!
SOLUTION: Well the App Store was caching something on the device and the only solution was to re-install iOS 9 and to NOT restore from a previous backup. Cleaning the project and the build folder did not help, neither did deleting the App from the device or any of the places that iTunes stores it and then re-installing the production App.
Transaction Suddenly /Unexpectedly/ Removed from SKPaymentQueue - any ideas why?
Intro
We experience a strange behaviour of SKPaymentQueue under iOS-9 and iOS-9.0.1. We suspect that this is an iOS issue.
This example is a minimal app-frame that demonstrates the SKPaymentQueue related issue. Download the example here.
Facts
Issue appears in sandbox environment (iOS 9.0.1).
Issue appears in TestFlight environment (iOS 9.0.1).
Never tested in production environemt.
Never tested on iOS 9.1 /beta/.
Issue never appears on iOS 8.4.1.
App
This app requires one non-consumable IAP product with content hosted on Apple.
App has only one button that starts the transaction/download process.
Issue
Download process is unexpectedly terminated when app is moved from the foreground to the background and then back to the foreground.
To reproduce the issue ...
Adapt this project to your dev. environment (set NON_CONSUMABLE_PRODUCT_WITH_HOSTED_CONTENT to your IAP product-id).
Create a test app (iTunes Connect).
Host a non-consumable IAP product (Application Loader).
Press the button "Get Product".
Wait until downloading starts.
Press Home button to resign the app.
(Re)Activate the app (touch the app icon).
SKPaymentQueue will eventually send one or two download update events.
!! SKPaymentQueue will send the paymentQueue(queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction])` message to the observer.
!! Downloading is now terminated (no events).
Known Workarounds
Keep the app in the foreground while downloading.
Don't activate the app until the downloading is completed (at the system level), then activate the app.
Are you adding the background keys for your app?
You can set them in the info.plist or in capabilities...
info.plist way - Add "fetch" for "UIBackgroundModes"
Go to Capabilities > Background Modes toggle this on. And select the fetch field.
https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/uid/TP40009252-SW22
Good news, anomaly suddenly disappeared, and as consequence - this question is closed /without any obvious conclusion/.
Github code is a side product of this question and can be used as a minimalistic example with non-consumable IAP and content hosted by Apple.
This question already has answers here:
restoreCompletedTransactions broken?
(7 answers)
Closed 8 years ago.
I have recently released my first app after 2.5 years of development (a roguelike) and I am now having difficulty restoring a nonconsumable purchase:
I have a "restore purchases" button that calls this method just fine:
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
Then a prompt pops up requesting my user name and password, so I enter my test account information.
However, that is all that happens. The app doesn't crash as xcode shows it still running fine, but this method never gets called:
-(void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;
I am able to make consumable purchases and even the non-consumable purchase can be made normally, but when I delete the app from my device, reinstall and try to restore, the paymentQueue: updatedTransactions: function above never gets called while everything else seems to be called normally.
Can anyone identify my error?
Are you calling [[SKPaymentQueue defaultQueue] addTransactionObserver:myObject] to tell the defaultQueue that you are to be notified of transaction updates/events? I just recently had a similar problem occur to me, and it took a couple of days and multiple tutorials to find the error. Hope this helps!
Note that Store Kit testing does not work in the Simulator. You don't say whether this is happening in the Simulator or on a device, but my experience is that testing in the Simulator won't cut it. (It's unclear to me whether this is a deliberate policy on Apple's part or a Simulator bug.)
i get a timeout error (-1001) when trying to make an in app purchase. this began happening suddenly after in-app-purchase had been working fine for a while. what happens now is that i see my inventory, complete with prices retreived from apple, but after i attempt a purchase and the following code is executed:
SKPayment *payment = [SKPayment
paymentWithProductIdentifier: product.productIdentifier];
[[SKPaymentQueue defaultQueue] addPayment: payment];
all i get is a timeout error.
i created a test project with nothing but the storefront supplied by a reliable third party (urban airship) which i'd been using successfully with some alterations in my app. i got the same in app purchase timeout error, which strongly suggests some kind of issue on apple's end (it seems that either my device or my app id have gotten blackballed somehow -- perhaps after i'd uninstalled the app a bunch of times to reset its state -- at least with the sandbox servers). so now the question is what to do about it. any help would be appreciated.
problem solved: it was after all an apple issue. apparently the new app store agreement had gummed up the works. i had to install something via the app store on the device, after which the in-app-purchase was a-okay again. thanks all for your help.