I'm adding In-App purchase to my app.
I have some doubts in this.
How to handle SKPaymentTransactionStateDeferred?
Do we need to implement ourselves at this state or Apple will handle this?
If we should implement means how to handle here?
How to test with sandbox tester account?
Anybody tell me clearly. Thanks in advance.
According to Apple StoreKit document, deferred state is:
The transaction is in the queue, but its final status is pending external action such as Ask to Buy. Update your UI to show the deferred state, and wait for another callback that indicates the final status.
We get transaction deferred state, if user is part of Apple family sharing & family admin enabled ASK TO BUY.
As child user try to purchase in-app product, a request is sent to parent user for approval. Parent user has 24 hours to approve or cancel their child's purchase after the Ask to Buy process has begun. If the parent fails to respond within the 24 hours, the Ask to Buy request is deleted from iTunes Store servers and your app's observer does not receive any notifications.
You should update your UI to reflect this deferred state. Avoid blocking your UI or gameplay while waiting for the transaction to be updated.
In Sandbox environment, we can test deferred state by using SKMutablePayment like:-
let product = SKMutablePayment(product: productDetails)
product.simulatesAskToBuyInSandbox = true //Enable to test deferred state.
SKPaymentQueue.defaultQueue().addPayment(product)
For Information:
iOS 8 introduces Ask to Buy, which lets parents approve any purchases initiated by children, including apps or in-app purchases on the App Store. When a child requests to make a purchase, Ask to Buy will indicate that the app is awaiting the parent’s approval for this purchase by sending the Deferred state.
Related
I generally understand receipt validation on In App Purchases. Most libraries make this as simple as calling a method.
I'm not so clear on how subscriptions work though -- specifically, how can I detect if the subscription is cancelled?
Subscriptions are cancelled on Apple's iTunes interface only. How is my server supposed to know that a subscription was cancelled?
From the Apple docs:
The user can also cancel their subscription by disabling auto-renew and intentionally letting their subscription lapse. This action triggers the App Store to send your server a status update notification of type DID_CHANGE_RENEWAL_STATUS. Your server can parse the auto_renew_status and the auto_renew_status_change_date to determine the current renewal status of the subscription.
https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/handling_subscriptions_billing#3221914
The answer from Jacob is correct for the case that the user disables the auto-renewal of his subscription. If the user requested a refund from Apple and they cancel the subscription for him. Your server will receive a CANCEL notification and the receipt will contain a cancellation_date field.
You need to handle both of those cases, because when the user cancels (deactives the auto-renewal) his subscription, it is still valid (till it expires). When Apple customer support cancels the subscription, then it is from this point on invalid.
Note: the CANCEL notification is also triggered when a user up- or downgrades to a different subscription of the same subscription group. See this answer for more details on that.
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.
First off there seem to be many questions on SO regarding this topic but most seem outdated and not considering APIs that are available in iOS 9.
1) How are purchases restored?
When a user taps the Restore Purchase button for auto-renewable subscriptions on >=iOS 9, should a SKReceiptRefreshRequest or SKPaymentQueue.defaultQueue().restoreCompletedTransactions() be called? Currently I verify the receipt file to determine the active subscription and parse for the latest_receipt_info, is a receipt file also created on the device when restoreCompletedTransactions is called?
2) How can an auto-renewable subscription be verified?
To verify that an auto-renewable subscription on >= iOS 9 is still active and not cancelled I would call SKReceiptRefreshRequest every time the user launches the app. But the docs say:
Include some mechanism in your app to let the user restore their
purchases, such as a Restore Purchases button. Restoring purchases
prompts for the user’s App Store credentials, which interrupts the
flow of your app: because of this, don’t automatically restore
purchases, especially not every time your app is launched.
Should I call it only once a day or is there another way to verify the subscription?
Update:
For 2) just found this here:
Perform receipt validation immediately after your app is launched,
before displaying any user interface or spawning any child processes.
Implement this check in the main function, before the
NSApplicationMain function is called. For additional security, you may
repeat this check periodically while your application is running.
Apparently the receipt can be validated without user interaction. It is even recommended to do it on one's own server for security purpose. So as long as the receipt is validated by the App Store server there is no need for a receipt refresh request.
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.