Is it necessary to validate / refresh an app store receipt on launch in iOS? - ios

The Apple docs on receipt validation say to perform receipt validation immediately after launch. This amounts to checking for data at the path returned by [[NSBundle mainBundle] appStoreRecieptURL], refreshing via SKReceiptRefreshRequest if it's not there, and validating it. The aforelinked docs reference both iOS and macOS.
Is it actually necessary on iOS? If so, why? Is it to prevent users from using my app on a jailbroken device, or without having bought it from the app store (in which case I probably don't care if my app is free)? Or does it have implications for other operations like restoring or validating in-app purchases? For example, does the receipt data have to be there already in order to validate a transaction for an in-app purchase?
Note: I am not using in-app subscriptions. I have in-app purchases, but I don't use the receipts from them after verifying them and recording the purchase server-side.

you don't need to do so, that is optional only and could be done on iOS7+, if you interested in doing that.
briefly, implementing the validation is purely a financial decision, and even if you validate recipes you are recommended not to disable the content in case of failure as the validation could fail in standard environment as well anytime (e.g. in case of no connection), and such overreaction may ruin your consumers' experience.
altogether, doing the validation'd rather make sense on OSX in practice when you are allowed to disable the content in case of failure, regardless the reason; but if you feel you have more consumers than your income suggests or the amount of the stolen content is way beyond your margin, it may be worth to do it on iOS as well.
NOTE: in general you can read more about the technical details of receipt validation in Apple's Documentation.

The simple answer to your question is NO, It is not necessary.
Here is the detailed explanation for you.
According to Apple Documentation here, apple has given two methods of validating the receipts, they are given it as guidance only to prevent unauthorized copies of your application from running. For more guidance apple has pointed towards the apple review guidelines.
In the review guidelines here, Apple does not mention anything related to the verification of receipts as mandatory.
If at all the receipt validation is mandatory, Apple would have provided a simple API to validate it.
Titbit: You can see a lot of rejections when it comes to app store receipt validations. But all those issues are because the receipt validation is not done properly.
But my personal recommendations will differ from the above answer. First thing for you to consider is "Never underestimate hackers". Validate the receipts several times apart from the start of the app. Read this article for more information.

You would generally only validate the receipt to prevent piracy by users who haven't bought your app or if you are using auto renewing subscriptions.
Whilst you can interrogate the receipt for IAP information, its actually easier (and required by app review) to give a button somewhere to "restore previous purchases" and call
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
It is also a better UX for the user to possibly be prompted for their Apple ID and password having pressed a "restore purchases" button rather than unexplained at app startup.

The reasons I would give are:
The user can change their product if you are using subscription groups from outside of your app.
An auto-renewing subscription can renew outside of your app.
The app does not receive transactions initiated outside of the app until the app restarts.
The user can make purchases on another device using the same appleID whilst outside of your app on the current device.
Within our appDelegate:application didFinishLaunchingWithOptions we initialise a class that calls
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
to monitor for purchases initiated from within the app.

It's not necessary, but beneficial for the following reasons:
You'll always get the definite set of purchased products and not require the user to manually restore the products.
You have (limited) fraud protection, especially if you combine local and remote validation.
It's way more simple to compute the expiration date for automatically renewing subscriptions using the recipe.

Related

Is it possible to implement conditional logic for in-app payments in iOS in Swift?

Is there any way to implement conditional logic for payments in Swift? For example:
Say the user has agreed to have 10$ withdrawn from his bank account he connected to his app account if, on a specific day, he has not fulfilled a condition that can be tracked with the app.
If he fulfills the condition until 23:59, no money will be withdrawn. If he doesn't, at 00:00 on the next day, the 10$ are automatically withdrawn from his bank account.
I don't know of any app that does this and I'm not even sure whether an app like this would be permitted on the app store. I'm not even sure whether that's technically possible.
Would be thankful for any helpful input!
Using the in-app payments system (a.k.a. iOS in-app purchases which utilise the StoreKit2 or StoreKit API) this not feasible.
Explaining how in-app purchases work would be a bit tedious.
However, to put it simply, you can basically initiate either a one-time payment request, or a recurring payment request.
In each of these scenarios, the user may obviously either make the payment or decline, about which you would get updated in code.
The closest the system comes to what you are asking for is recurring payments (technically called the auto-renewable subscriptions).
However there is no way to ask Apple to conditionally deduct money based on whether the user has performed some action or not.
I'm pretty sure you should not be looking at the iOS in-app purchase system as a way to do what your are looking for.
You could use 3rd-party payments.
However, whether Apple allows this, would depend on what kind of condition you expect the user to fulfil. If it relates to a real world service or material, then you may be able to justify it to Apple, however, if it is a digital service, lets say an app based activity, such as opening the app a given number or times, or viewing the app for a given amount of time, then I'm pretty sure this would be in violation of the Apple App Store Guidelines and they would reject your app when you submit it for review.
To be honest without understanding the use-case a little more clearly it is a bit difficult to advise you on the technical feasibility.

In-App Purchase Refund

I am wondering whether to implement in-app purchase refunds (in case a user refunds). None of the in-app purchase tutorials seem to show how to do it, so I am wondering if that is for a particular reason.
By the way, the in-app purchase is a non-consumable (PRO version).
A big problem I can see with refunds for example, is that you shouldn't remove the PRO features if they don't have connection, but then someone can just use no connection with the app to never get PRO revoke.
My question is: Is there a seamless way to integrate refunds for non-consumables, and do many other apps handle refunds or not?
Thanks.
I believe the only way for a user to get a refund is to request it from Apple. If granted, the onus is on you to determine this condition. You will have to check receipts actively.
https://developer.apple.com/library/archive/technotes/tn2413/_index.html#//apple_ref/doc/uid/DTS40016228-CH1-RECEIPT-HOW_DO_I_USE_THE_CANCELLATION_DATE_FIELD_
This states:
The Cancellation Date (cancellation_date) field is designed for use
with auto-renewable subscription, non-consumable and non-renewing
subscription products. This field is set when a customer contacts
Apple customer support for a refund and the transaction is canceled.
Depending on if your app has a backend or not will dictate a strategy to handle this. If you have a backend, a good method is to periodically check for receipt status (at some time interval of your liking). Note that if you have a large user base, you probably want to divide up the user pool piecewise to do this type of check.
If you don't have this as your option, then you need to make your app make this check.
Or ... you accept that this will happen. I've done work for a company that had a large subscription base and they never ran that check for cancellation/refund (I let them know about that weakness in the system).

Using undocumented fields in an App Store Receipt

OK I'm working on a app where the user purchases the app from the App Store, gets access to the app for a year, and then after the year has passed they are sent to an In-App Purchase screen where they can purchase a subscription for continued access.
(this is not the subscription model I'd implement if it were up to me, but the client insists that it follow this model)
In order for it to work, though, I need a reliable way to check when the app was purchased, in order to calculate when the first year of access ends. Following the suggestions in one of the answers in...
iOS App Purchase Date
...I've gotten the app receipt and I can find all the data fields that the documentation says there are, but there are also a few others including "original_purchase_date" (not the one in the IAP receipt array; the one for the app receipt itself). This would appear to be what I want. However this field is undocumented.
As far as I can tell, Apple security operates via a form of "Security Through Obscurity/Diversity", so it's been difficult to find further information about these undocumented data fields. My concern is that I might use the data from this field, and then discover that it was only there in sandbox mode and actual receipts don't have it. Worse, what if I reference that field and then Apple releases a new iOS update that completely discards that field from its implementation? Undocumented features are even less reliable than deprecated features, after all.
My question is this: is there a reliable source of information somewhere where I can find out what Apples intends regarding this field? Or better yet, is there another, safer way of achieving the system my client wants?
You have to implement it as a free app that requires a subscription IAP. Paying for an app cannot be its subscription cost.
Check rule 11.12 here: https://developer.apple.com/app-store/review/guidelines/#purchasing-currencies
Apps offering subscriptions must do so using IAP, Apple will share the
same 70/30 revenue split with developers for these purchases, as set
forth in the Program License Agreement
Implementing it the way your client wants will result in rejection.

iOS In-App Purchase No Back-end

I am investigating the use of in-app purchase for what essentially would be a "pro" version of my app.
The app itself would be free but once in the user has the option to purchase the pro content (only 1 thing). The "pro" content would already be on the app and there is no need to download it, it would simply "unlock" it.
Is this allowed from the Apple Guidelines?
As only 1 non-consumable would be purchased I think the use of a back-end server isn't required.
Again is that allowed from the guidelines?
And is it safe and simple to just store the result in NSUserDefaults and if installed on another device pull it from SKPayment restore purchased and such?
I've looked at several other questions.
In-App Purchasing?
Retrieve purchased information in In-App purchase
How do I add consumable In App Purchases using NSUserDefaults and not my own server?
And those seem to suggest that my approach is valid, but as I know those things have changed recently I want to make sure I'm taking the right approach.
Thanks!
No problem having the content built in.
Best practice is to perform receipt verification on a server with an authentication protocol between the app and server (this is also true for several other mobile app stores). If you perform the verification on the device, people can use existing tools to get around your IAP checking and steal content. Take a look at https://developer.apple.com/library/ios/#releasenotes/StoreKit/IAP_ReceiptValidation/ for some information.
So while a server is not required, it is recommended. Only you can say if protecting your content is worth the hassle of maintaining a server.
I agree with J. Freeman that straight storage in NSUserDefaults seems weak. I store things in a local file but the format is tied to the device and requires a server computed key to create it. Finally, yes you should use SKPaymentQueue restoreCompletedTransactions to get things purchased on another device. Realize that the restored transactions should also have their receipts verified on your server.
Yes that is fine. You do not need a backend to do in-app purchases, and it is ok to ship with your content built in.
The one thing I would say be careful with though is storing the unlock information in NSUserDefaults as someone will easily be able to forge purchases that way. You should store the unlock information in the keychain.

Refund the previously purchased non-renewing subscription, not the current one. Possible?

I'm implementing an iOS app with non-renewing subscription. Not much relevant information was available online; so I seek your guidance.
A use case which worries me the most is when a user purchased the subscription once and then immediately after purchase it again to extend the duration of service (see such scenario here). What if that user were to refund the first purchase, leaving the second one intact? Is this even possible in practice, or am I just too paranoid?
Assuming the above case is possible, my app will run into a problem because, as far as I know, verifyReceipt only returns the latest, good receipt (watch Managing Subscriptions with In-App Purchase in WWDC'12).
I find nowhere Apple provides relevant information about refunding policies.
(Auto-renewable subscription seems to rule out this case as a renewing action is taken care by iTunes automagically and it seems not possible to extend this type of subscription until iTunes allows it.)
verifyReceipt will not only return the latest good receipt, it will also tell you if the receipt you submitted for verification is good. So if you're concerned that a user may have cancelled* a transaction, then submit every receipt you're questioning.
*But what do you mean by "cancel" the first purchase? Do you mean when they tap "cancel" instead of "buy?" Well then the transaction won't go through and you won't even get a receipt.
Or do you mean when they request a refund? I don't know any other way they can cancel a purchase.
Edit:
If you're referring to refunds, there's no way for a developer to tell if a user has been issued a refund. The assumption is that Apple expects you to continue to deliver services to that user regardless of the fact that they received a refund. Your receipts will probably all verify correctly regardless of the status of a refund.

Resources