I'm implementing a trial then subscribe model into my app which allows the user to use the app for free for 14 days, then at the end of the trial it'll alert them that the trial ended and they need to subscribe to continue use.
I'm doing this settings an NSDate object in standardDefaults the first time the app is opened. Then it compares the current date with the stored date, and compares the returned time interval to the number of seconds in 14 days.
My question is this: Do standardDefaults stay in memory if the user deletes the app? If not, how can I prevent a user from deleting then redownloading the app to restart the trial period?
Apple is quite proud about their sandboxing concept and the fact, that if a app is deleted, all the data will be deleted.
The only way of ensuring this information won't be lost will be to save it to a Database on a server and periodical check from your app.
This as technical solution. But make sure, if Apple will allow this in there AppStore if you plan to release it there.
Apple forbids trial versions, though I am not sure, if you could deliver in-app purchased content free for a while and later start billing.
But the main rule is: what ever was given to the user for free must stay free.
There are some apps that have trial periods for certain features. Look at the Puffin Browswer or ChessFree they both offer features that expire. Puffin allows for flash support (actually really cool feature!) and after a few days that feature is removed. Although the rest of the browser is still accessible the main purpose of it is removed.
ChessFree gives you points that you can use for different things, lessons, playing games, taking moves back, etc... I am not sure what happens when you run out of points but it appears that you cannot really do anything anymore.
If I were to implement something like this I would just save a variable in the keychain telling how many days they have left or the date they installed it (as a string). That way it will not be deleted if the app is uninstalled (keychain items stay stored even if the app is removed, so just always check/decrement/increment that as you wish). I would probably keep some features available to users that reach the expired time limit (like Puffin) but I honestly believe that is up to you.
Related
My app has a functionality of auto-renewable subscription. To validate the subscription, I'm trying to validate app store receipt locally on device, For now i'm checking the expiration date of receipt with device's current date. But this condition may fail if user changes the device date to past.
How can i handle this condition?
Any help much appreciate. Thanks!
The correct way and the securest would be to use a server as Paulw11 already wrote. Nevertheless, there are ways of identifying users who eventually turned their device time back, but personally, I wouldn't use them in production to restrict access to features or content, because they're unreliable and I would rather have someone who uses my service for free than possibly several whom I wrongly exclude.
I have used the following approaches only to get a feeling on how many users actually tried to get access by turning their device time back and it turned out, that the number was that small, that I decided that it was not worth investing more time on that.
Enough waffling, here are my approaches:
1) Every time you do the local receipt validation you could save the current time to the user defaults and compare the last saved value with the current device time.
2) Pull the current time from some clock api from the internet (for example http://worldclockapi.com/)
I am planning to make an app on iOS. The app will be free. This app will work without the internet. The app should not be able to query my database if the subscription is not paid.
However the app will still receive "notification" or RSS links even without subscription. The subscription will be monthly minimum.
I did some research but some people are saying it is not possible and some are saying this has been changed by apple and it is now possible.
Edit
I would like to add that the app will be as much secured as possible. I will have an SQLCypher database inside - so the key will be stored there too (hidden).
Here is the problem that someone told me: The user can use the app only if it paid the monthly/annual subscription, so the key has to be revocable. It seems not compatible with that because the app will have the database deciphered with the key. And if it is deciphered one day, then it will be deciphered next month too.
Why exactly people tell you is not possible?
The only problem I see from what you write is if the free version of your app doesn't do anything. As a general note Apple doesn't allow "demo" versions (even if that concept is not always clear or enforced consistently): a free app must do something not trivial (and of course lots more if the customers pay).
I now spent about 24 hours implementing Apple's StoreKit IAP system. After 3 hours I got "purchasing" itself working but the last 21 hours I wasted on implementing all the receipt communication. Now I am struggling to get openSSL working (some bitcode compiler error) and I reached the point of giving up.
I don't care about people cracking my apps or things like this, so is there a simple way of just asking the App Store servers whether an in-app purchase has been made? Without any encryptions, keys, certificates or likewise?
The flow would be like this:
set a NSUserDefault to "true" after purchasing
on every app launch, if there is an internet connection, check again
unless the device is connected to the internet, the NSUserDefault stays on "true"
if a user tempered with the NSUserDefault, it will be overwritten as soon as the app connects to the internet again
If the user finds his way around it, he deserves to keep the item, no user on the world can pay me enough to spend one more hour on that
So if you know a simple way of achieving this, please let me know. I noticed that after buying a (non-consumable) product with the test account, the popup tells you that you've already bought this item before. Maybe this can be used for this purpose?
I am sorry for the rather informal way of posting right now, but this is the first ever time where I think Google did a better job with Android than Apple did with iOS. There are cracks for literally every app anyway, Google's system is far from being bulletproof but in the end of the day, what difference does it make if a cracker takes 10 minutes or 2 hours to manipulate the app?
It took me like 1 hour to get in app payments working in my Android apps but what Apple requires here is ridiculous. Their "instructions" aren't helping at all, it's like they want to make it a secret how to implement all that and you gotta take a guess.
If you don't want to check receipts, you only need to implement the SKPaymentTransactionObserver protocol and add whatever object you implemented it in as an observer using SKPaymentQueue's addTransactionObserver. Ideally, you want this done early in your App Delegate to ensure you receive any transactions sent to your app on launch (this is most important for subscriptions).
In the paymentQueue:updatedTransactions: method, check the transactionState of each transaction. If it's SKPaymentTransactionStatePurchased or SKPaymentTransactionStateRestored, then the purchase is (supposed to be) valid. You can then store the status in NSUserDefaults or a database.
Don't forget to implement restoring purchases.
This works quite well, but anyone who has jailbroken their device and installed whatever software it is that bypasses IAPs will get IAPs for free: it does not need to be specific to your app, they just return "purchased" for any IAP.
I'm working on an iOS app and am currently trying to come up with strategies of how to manage in-app purchases:
Android has the nice capability that it caches product ownership information locally on the device and can therefore check ownership without having to prompt the user for a password. iOS, on the other hand, cannot restore purchases at all without asking the user to log in and Apple therefore specifically discourages ownership-checks at app-launch in their Restoring Purchased Products documentation (last sentence of first paragraph).
Now, technically, you can get iOS to provide the same "ownership caching" for non-consumable items as Android does, by just never calling finishTransaction:, except in the case of failed transactions. That way, at every app launch, as soon as you call addTransactionObserver:, you get a list of owned products without a user login request.
Clearly, I can also provide this cache myself using something like NSUserDefaults, but that would be a bit more work and just adds more opportunities to make mistakes in implementing the ownership tracking. And since I need to handle randomly reported transactions from the transaction observer anyways for good measure, I would basically have to implement the above idea and then duplicate its functionality again using NSUserDefaults or such.
Thus my questions: Is it OK to (mis-)use unfinished transactions in this way? Will they ever expire automatically? Might Apple reject my app if they notice that this is what I'm doing? Are there any negative implications of this idea (reliability, performance, wasted memory/storage)?
I want to offer my app free for a period and then charge to continue using it. I understand that the way to do this is to force the user to buy an In-App product after the free period. However, if I simply record the date that the user starts using the app in the standardUserDefaults and use this to calculate when the user must buy the upgrade the user could simply delete the app when the time arrives (I assume the sandbox is also deleted) and download the app again for another free period.
First question. Is my reasoning so far correct?
Second question. Is there any way of accessing the date that an app is first downloaded?
Assuming the answers to these questions are Yes and No I have come up with the following solution.
Upon downloading the app the user is first forced to "buy" free an In-App product which then will have the date it was added to the transaction queue. This In-App product would then be downloaded for any subsequent download and I could use the date of this product as my reference date.
As I can find no reference to this problem or solutions I really wanted confirmation that this was a sound way to proceed or if there was another more standard way of dealing with the problem.
Thank you
Silas
You are not allowed to limit you app for free for a limited period:
11.9 Apps containing content or services that expire after a limited time will be rejected, except for specific approved content (e.g.
films, television programs, music, books)
If you want to risk it, you could save the date (encrypted) in keychain to make it more persistent. Just so you know, user are able to access their keychain data if they iCloud keychain sharing and are on a Mac. So if they delete the correct key or rest there device your app will fall back to the free/trial mode.
This does not seem entirely consistent with:
Communicate the value of your products to your users. Users want to
know exactly what they’re going to buy. Combine information from the
App Store, such as product prices and descriptions, with additional
data from your server or the app bundle, such as images or demos of
your products. Let users interact with a product in a limited way
before buying it. For example, a game that gives the user the option
to buy new race cars can allow users to run a test lap with the new
car. Likewise, a drawing app that lets the user buy additional brushes
can give users the chance to draw with the new brush on a small
scratch pad and see the difference between brushes. This kind of
design provides users an opportunity to experience the product and be
convinced they want to purchase it.
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/ShowUI.html
One way of letting the user interact with a product feature in a limited way is to let them use it a few times before requiring that they pay to use the feature.