Recently I decide to change the FullControl business model from paid download to freemium ( free download and PRO version via In-App purchase ). Then I had to deal with a couple of issues: receipt validation, PRO version available for “older” users, In-App purchase validation flow. In this post we are going to discuss the last point.
Red states represent the failures, but it is not necessary to show something to user, it depends on where you do the validation. Of course take into account that they are different errors. The important thing is that you disable all paid features and don’t make any assumption on why the procedure fails (e.g. cracking).
Show In-App view state means that you should display the views to show to the user the availability of extra-paid features when needs.
Should the feature be enabled state verifies the In-App items to enable the features. In case you are switching from paid download to freemium, as I do, you should use original bundle version also.
When to use validation process?
You can start the validation process on application startup or when you have to create user interface to know what to show. The following is the flow that I adopt:
Enable feature or Show In-App view means that you set a boolean value somewhere then you use it to show the right UI and so on.
Note: Receipt-feature validation state consist of validation flow see above except for one thing: I don’t refresh the receipt because it causes that iOS will popup AppStore login alert to the user. I prefer to guide the user to the In-App view and then invite him/her to restore or buy.
In In-App purchase view if the user wants to restore, the validation process will start from Refresh receipt and follow the above flow, else if the user buys an item you have to account to a particular flow. This is my implementation:
There is a crucial doubt about what to do when transaction state is equal to purchased. You should verify the receipt, enable the feature and then call finishTransaction: method, but what to do if validation fails? From Apple documentation, Persisting Using the App Receipt section in particular, it is clear that the purchased item must be in the receipt when transaction is equal to purchased. So if validation fails I don’t call finishTransaction: and I don’t enable extra-paid feature, but I try to start validation process from Refresh receipt state.
At the moment of writing, I know, by usage stats, that this case (transaction purchased but unable to verify it) happens, but none of users complained about this.
Officially receipt is available starting from iOS 7.
This post is based on non-consumable In-App purchase items.
Apple suggests to use receipt as persistent record to check purchased products (non-consumable). Personally I save something in NSUserDefaults also and I validate receipt sometime in different points of my app.
Remember that NSUserDefaults plist file can be edited easily by an user. I detected a little percentage of users that edited the NSUserDefaults plist file, I simply disable the feature and restore the correct value.
In FullControl 3.0.3 I introduced a bug in validation code then all the people that had or would buy the PRO version were unable to unlock the features. So make sure that validation code works perfectly (write a test) or make the system more flexible allowing the user to use the features although it seems not allowed.