I want to check whether or not my application was previously installed on a particular device. Is there any programmatic way to do so?
You can use keychain. but when user reset his/her phone this value will be lost .
I think there is no option is available to such case except you have to use iAd in your app. apple provide unique id for that that will remain constant after reinstall application.
OPTION #1:
You can use NSUserDefaults or save the flag to keychain, in order to not lose it after app uninstall, and check in application:didFinishLaunchingWithOptions: method:
BOOL installFlag = get it from user defaults or keychain;
if (installFlag)
{
//App was installed
}
else
{
//This is the first install ever
installFlag = YES;
//Here save the YES value to user defaults or keychain
}
If you will save the flag to keychain, then use a Keychain Wrapper, like this
one.
The weak part of this option is that even if keeping the flag in keychain, the value could be lost, after reseting device settings, that's why I would prefer the following option:
OPTION #2:
Keep the flag remotely on a server database, as a key you can use device identifier:
NSString *uniqueIdentifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
And you will have to check, if there is a record in your database with current device identifier, then app was already installed, if no then add the flag and the identifier to the database. (But you will need internet connection every time).
You can use keychain to keep log of your app previously installed or not.
Related
This is how it is accomplished in my app:
I keep the data in iCloud.
I need to do some time consuming thing for users who already used my app. But this will also start for completely new users... they just downloaded my app from AppStore for the first time. And this is not expected.
How can I determine that the app is running, but downloaded from AppStore for the first time?
What I could do, but I did not:
put any boolean data in the Keychain, and then check if it exists.
Since you have no non-app end to distinguish users Keychain as you mentioned is your only app persistance option that will survive app uninstalling. Only device Reset to factory settings would remove it.
you can use NSUserDefaults . if appDelegate.m ->didFinishLaunchingWithOptions use this code :
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
if([userDefaults objectForKey:#"first_time"] == nil){
[userDefaults setObject:#"1" forKey:#"first_time"];
//do whatever you need
}
this condition will satisfied only once after installation .
Assume a following situation:
User restarts his/her iPhone.
User lets device locked, does
not unlock it.
Server sends a (silent) push notification on the
device (or anything happens that wakes the application up on the
background, such as Apple Watch extension requests data, etc.).
App wakes up and tries to access Keychain items stored with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly accessibility.
Now, the Keychain items should not be accessible, since device was not unlocked yet. How do I correctly check for this situation?
Note: In my case, the presence of an item stored in the keychain determines if the app is "active" or not, so I would need something to stop this check soon enough, otherwise my app will assume it's not active (value cannot be read) and perform init steps...
I've come across the same situation in my app and here's how I'm checking if the keychain is available (objective-c code):
+ (BOOL)isKeychainAvailable {
NSString *testVal = #"testVal";
NSString *testKey = #"testKey";
[JNKeychain saveValue:testVal forKey:testKey];
NSString *validatedValue = [JNKeychain loadValueForKey:testKey];
[JNKeychain deleteValueForKey:testKey];
return (validatedValue == testVal);
}
I basically save a value in the keychain and try to read it again. If it's not the same as I've just written it means the keychain is unavailable, which also means the phone hasn't been through the first unlock since the keychain should be available after the first unlock thanks to the option kSecAttrAccessibleAfterFirstUnlock.
What I ended up doing in this situation is terminating the app if it was started in the background and the keychain is unavailable:
- (void) methodStartedInBackgroundThatNeedsKeychain {
if (!JNKeychain.isKeychainAvailable && [UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
exit(0);
}
}
ATTENTION! please be aware that Apple strongly discourages the usage of exit(0) when the app is in foreground mode, thats why I'm making sure to only call it in background with [UIApplication sharedApplication].applicationState != UIApplicationStateActive. Here's Apple's QA discussion on the subject: https://developer.apple.com/library/archive/qa/qa1561/_index.html
I would like the determine if I have access to files that have been saved with the attribute NSFileProtectionKey = NSFileProtectionCompleteUntilFirstUserAuthentication.
I have tried [UIApplication sharedApplication].protectedDataAvailable, however from my tests it will return NO whenever the device is locked (if a pin code is set) even if the user has unlocked the device at least once since last starting the phone.
It says quite clearly in the docs: The value of this property is NO if data protection is enabled and the device is currently locked, and in this case files that were assigned the NSFileProtectionComplete or NSFileProtectionCompleteUnlessOpen protection key cannot be read or written by your app. i.e. this is not the correct property.
You need use one of the multi-tasking keys that causes the launch the app on boot - e.g. the voip key for UIBackgroundModes.
Mind you, you're pretty much testing the OS at that point - if you set the keys appropriately when creating the files it should work as advertised. If it doesn't then log a radar.
Problem: using UDID is deprecated - we cannot use it anymore.
There are some solutions on the net: generate GUID and store it in the "safe place", iCloud, IdentifierForVendor starting with iOS6, OpenUID, SecuredID and so on...
Request:
I need to have a unique identifier of the Device to store user data on our server.
Question:
Can I use deviceToken of Push Notification as a unique identifier?
What are the pros and cons of this idea?
(-) user can disable push notifications
(+) unique number
(+) supported in all iOS
This is a terrible idea, the token can change if the user changes device or for some other unknown reason.
The user can have multiple devices
If the user reinstalls the app they can get an other token
It's not 100% that the user will keep the same token.
And most important of all: You are identifying devices not users!
One solution is to generate a UUID and save it in the user keychain where you retrieve it. But this can also be removed if the user clear the device.
You best option is to allow the user to login with an account, which that can create. Then you can combine this with the UUID in the keychain.
You should use identifierForVendor. The deviceToken for push notification is unique, but CAN change.
The token can change if the user reset the device, for unique device identifying you can use the following code
float currentVersion = 6.0;
NSString *udid = nil;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= currentVersion)
{
//below code is taken from the Apple Sample code, to check you can download the files
https://developer.apple.com/library/ios/releasenotes/StoreKit/IAP_ReceiptValidation
// OR
http://developer.apple.com/library/ios/releasenotes/StoreKit/IAP_ReceiptValidation/VerificationController.zip (line number 319)
udid = [UIDevice currentDevice].identifierForVendor.UUIDString;
}
else
{
//may cause apple rejection
udid = [UIDevice currentDevice].uniqueIdentifier;
//i think we can use the below link for ios5 or below but not sure it may accept or reject
https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5
}
//just saw a link which may help you better and have a look at image
http://www.doubleencore.com/2013/04/unique-identifiers/
can someone suggest the best way to persist the unique id even after reinstall app, delete app or system restart or system boot or factory reset
I am a beginner iPhone app developer and I am trying to show the iPhone or App unique identifier on a label through an IBAction button. I researched a little and know that some of the code have been deprecated and CFUUID is used instead. The code below is what I used. However, every time I touch the IBAction button, the UUID changes. What am I doing wrong?
CFUUIDRef udid = CFUUIDCreate(NULL);
NSString *udidString = (NSString *) CFUUIDCreateString(NULL, udid);
uuid.text= udidString;
I think you have misunderstood the purpose of CFUUIDCreate(), Read its documentation you'll understand.
I guess the API is serving it's purpose properly, which is to create universally unique identifier means every time you call this it will return you back unique identifier randomly.
You can use
[[UIDevice currentDevice] uniqueIdentifier]
However, this method is depreciated. In order to get a unique identifier for each device, you can still use CFUUIDCreateString and save the output to user defaults. Load this value each time the app runs. If the app is deleted and then reinstalled this value will be different.
If you do need a unique identifier across app installs you can use the network MAC address.
As mentioned above, CFUUIDCreate is intended to create a different UUID each time it is run. You can create one, and store it in your app if you like, or you could try something like https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5 - basically, it provides a uniqueGlobalDeviceIdentifier function on the UIDevice, using an MD5 hash of the MAC address as its basis.
[[UIDevice currentDevice] uniqueGlobalDeviceIdentifier]