saving current date and time in my iPhone application? - iphone

In my application i am using In - App purchases to provide a subscription of 1 year….now i need to save the time and date when the user buys the subscription and need to check when the subscription expires?? i have not used database before is there any other way to store date and time in my application and retrieve it every time the application starts??

You should store the purchase of a subscription on a server, with backup in place, not only on the device.
You might have noticed that if you delete any iPhone app, and later re-install it, then the next download is free. There can be many reasons as to why the user might loose your app, a system update went bad, or whatever.
Apple specifically requires that the user do not loose what they have bought. If you have promised 1 year, then you must make sure they get 1 year no matter what happens to your app. Otherwise Apple can, and will, reject your app.
Storing the expiration date on a server also give the added benefit of protection against users fiddling with your data and granting themselves extended subscriptions.
Start by looking at the In App Purchase Programming Guide.

You can simply store it in NSUserDefaults:
[[NSUserDefaults standardUserDefaults] setObject:[NSDate now] forKey:#"purchaseDate"];
Then retrieve it like such:
NSDate *purchaseDate = [[NSUserDefaults standardUserDefaults] objectForKey:#"purchaseDate"];
And when you're done with it:
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"purchaseDate"];

Related

Determine the time period of when my app was purchased

Is there a way (in code) that you can give an app different features based on when it was purchased??
I have people who have bought my app for a different price and some had it free during a promotion.
It would be nice to give a little thank you with an extra feature in my app for the ones who paid for it.
Is that in anyway possible?
Without having it in place beforehand, you won't ever know about the past, but nothing prevents you from putting the timestamp of when a user first opened your app into e.g. the user settings. Something like
[[NSUserDefaults standardUserDefaults]
setObject:[NSDate date]
forKey:#"install_date"];
which you could then use to decide how to "treat" (I guess) the user. The one catch is that if a user ever deletes the app and then reinstalls it, their early adopter bonus or whatever will be lost. The only other option you have is to send the device ID to a dedicated server somewhere, e.g. a PHP script with a simple MySQL db where device id's are stored along with dates. You could then do something like
NSDate *purchaseDate = [[NSUserDefaults standardUserDefaults]
objectForKey:#"purchase_date"];
if (nil == purchaseDate) {
// we need to get the date for this user from the server, or
// we need to register the user as it's the first time
} else {
// we know when this user installed the app, and they did so
// (approximately) at the purchaseDate time.
}
Date format issues aside, the above should be pretty straightforward, but as said, does require a server somewhere (which can be a slow mo because the above only happens on first install and reinstalls).
Edit: you can use [[UIDevice currentDevice] uniqueIdentifier] (deprecated as of iOS 5) or [[UIDevice currentDevice] identifierForVendor] (new as of iOS 6.. lol) to get the device ID.
You have to manage it by code officially Apple don't provide any code for that. But if in case you need any kind of analysis of app. Like , which part of app was used by user, which part makes crash of app, something kind of feature you can try this Flurry Analytics for it .
There is no way to detect from within your app when an app has been purchased. You could add detection of when it was installed, but that could have happened at any later time, even multiple times.

Approaching App Release: 2 Quick Questions

as I get closer to releasing my app, I'm trying to make sure that I'm using stable code to check if the app has been launched before (in order to perform some first time setup). Is this (obviously a no frills method that doesn't take into account app version and updates) pretty much a rock solid way to determine if the app has been launched?
In my app delegate didFinishLaunchingWithOptions method, I perform the following each time:
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
if(![defaults objectForKey:#"not_first_launch"])
{
NSLog(#"This is the first time the app has been launched.\nPerforming first-time setup procedures...");
[self runFirstTimeSetup];
}
My second question is basically, can I assume that when I release an app update, that the user's documents directory for my specific app's sandbox will be left unerased? Does an app update simply add to the directory, not wipe it clean and re-install? I need the user's files to stick around even when I update the app (pretty obvious) but I don't want to make the wrong assumption and have users lose data every time I release an update.
Thanks!
Yes, that's a good use of NSUserDefaults.
User data is preserved through updates.
Just make sure you keep the data that comes with your app and the data generated during runs in separate bins. So that if you have to change the former (via an app update), the latter remains untouched. For example, don't put both of them in the same SQLite table.
I know you already accepted an answer, but I just wanted to touch on the subject. The way I check if the app is being launched for the first time is like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...normal code...
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"kFirstUse"]) {
[defaults setObject:[NSDate date] forKey:#"kFirstUse"];
[defaults synchronize];
}
}
The reason why I wanted to post is because while I check if this is the user's first launch, I also save the date of their first launch. For no extra code, I figured why not save this first launch date. I don't use that info at all in my app, but I was thinking maybe in the future I might. In the future, I was thinking about adding in App Purchase, and I would give the stuff away for free to my initial users; so this allows me to be prepared for the future and accomplish my goal at the same time.
And just for completeness, NSUserDefaults do persist between app updates, just make sure not to change the key to any object, otherwise that object won't be found.
Another good thing to add is that line [defaults synchronize]; - that literally makes the app save that data. The app periodically automatically saves the data, but I like to be safe and know that my stuff is saved.
let me know if you have any other questions

How persistent is [NSUserDefaults standardUserDefaults]?

I'm using [NSUserDefaults standardUserDefaults] for storing application settings.
My questions are:
do those settings are removed on app deletion?
are they kept after an application update (through the
AppStore)?
Because I'm using it to store a password and don't want my users to reset them at each update. Also, I'd like that the only way to reset the password would be to remove the app and re-install it.
Is NSUserDefault the right choice?
Thanks,
Jérémy
Yes, they are removed on app deletion and yes they are kept when an application is updated.
However, you're not advised to store sensitive data in the NSUserDefaults, instead I would look at using the Keychain.
I use NSUserDefaults in my app to allow additional access to my app for my colleagues. They just have to enter the code word in settings and the app is fully opened.
to the point each time I update the app they have to re-enter the code word, so I would say from experience that they are not kept after updates. The values need to be re-entered.

How easy is it to hack a plist file in an app store app?

Don't worry, I'm not trying to hack someone else's app, if that's what you're thinking =).
I want to have 2 versions of my app, a free version and a deluxe version. My plan was to use an in-app purchase to enable the deluxe version by setting a boolean value in the plist file.
My question is: is this secure or is it easily circumvented? And if it is not secure, can someone suggest a simple alternative? I don't want to download additional content, I would rather keep all of the functionality within the app and enable it somehow.
Edit: I don't mean the application plist file, but something like the user defaults file.
You should store this in the keychain, this is what I'll do. The keychain is far more secure than a .plist or the user defaults (which are .plists, too, as far as I know). Have a look at SFHFKeychainUtils, you should be able to use this or just implement a better method exactly for the need to save a simple bool.
It is easy to edit the com.something.plist without jailbreaking. With a free tool* you can browse your device, you can also edit and save these files. If you store your inapp purchase something like this:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"com.example.pack1"];
[[NSUserDefaults standardUserDefaults] synchronize];
then this will be written to the plist:
<key>com.example.pack1</key>
<true/>
If you name your packages like this: pack1, pack2 etc., and somebody edits your plist (copy/pasting the first key), he/she could use the locked feature easily.
A not too hard to implement method would be to save like this:
[[NSUserDefaults standardUserDefaults] setValue:[self sha1ValueForKey:#"com.example.pack1"]
forKey:#"com.example.pack1"];
[[NSUserDefaults standardUserDefaults] synchronize];
where -sha1ValueForKey: is
-(NSString *)sha1ValueForKey:(NSString *)key {
return [self sha1:[NSString stringWithFormat:#"<SALT>%#", key]];
}
You have to change <SALT> to something.
You can find -sha1: here: http://www.makebetterthings.com/iphone/how-to-get-md5-and-sha1-in-objective-c-ios-sdk/
After this you can verify if the key matches the hashed value.
If somebody wants to hack your plist he/she has to know your hashing mechanism and salt.
This is not the safest way to protect your application but it is easy to implement.
*iExplorer
EDIT:
The suggested method only protects - somewhat - your IAP if the user doesn't have access to the hashed value. If someone gets it from somewhere, it is easy to copy that data to the plist. If the SALT is device dependent copying is useless.
I would recommend reading up on verifying in-app purchases. It sounds to me like you are trying to roll your own in-app purchase verification system which may be wrought with issues you might not have thought of yet. You have to be careful with your user's purchases that they will behave the same in your application as they will in any other, lest ye lose their trust (and future sales!)
Instead of worrying about the Info.plist file, why not just set a preference? Somewhere in your code, this would give you your boolean value:
[[NSUserDefaults standardUserDefaults] boolForKey:#"someKey"];
If the value doesn't exist, the result will be nil. This code sets the value:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"someKey"];
Plus, these values will be backed up in iTunes, so if the user moves their backup to a new iPhone or simply restores from backup, the values will be restored.
I don't have an answer, but it seems that editing your plist file dynamically is not possible, if I trust this subject :
You can not edit you're info.plist
file dynamically. When you submit your
app to The App Store, your app bundle,
which includes info.plist, can't
change because the signature created
when you compile you app is based on
the bundle.
Any pirate has a jail-broken iPhone
Any jail-broken device offers full file system access via tools like PhoneDisk, etc
Any file system access allows people to change the values in your applications .plist file
Game over.
Now, its not trivial to wrapper that up for the script kiddies but then again its not that hard either.
Storing state in defaults is no more nor less safe from privacy than having two versions of your app. Pirates will either pirate the deluxe version, or they'll pirate the unified version with the flag set.

how to get Iphone UDID of device while installing the application from app store?

In my Iphone application , i am able to get the UDID of the device and have display it on alertview.
my query is that while any user go to the apple appstore and try to istall the application, at that same time how to get the UDID of the device and store it to the Database and also want the UDID of application at the time of uninstallation.
Whether is it possible or not?
If possible please provide any code or any useful link or any other info,which would be appreciated.
Thanks,
Mishal Shah
You can't run any process when your application is not actually running - this includes at download time and at uninstallation.
Instead, you should try to find other ways to measure what you want. You can, for example, have your application keep track (in NSUserDefaults or similar) of whether or not this is the first time the user has launched your app, and if it is submit the UDID to your server.
Tracking uninstallation is a lot harder - the best you may be able to do is to keep track of how long it's been since the user last launched your app (if you have the app submit a launch time every time the user opens it).
Keep in mind that a lot of tech-savvy users will object to your gathering the UDID or usage patterns within your app without their express permission (or at all).