My app is compatible with iOS5 and iOS6.
Until now I had no problem using:
NSString DeviceID = [[UIDevice currentDevice] uniqueIdentifier];
Now with iOS7 and with uniqueIdentifier not working anymore I changed to:
NSString DeviceID = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
The problem is, this would not work for iOS5.
How can I achieve backward compatibility with iOS5?
I tried this, with no luck:
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000
// iOS 6.0 or later
NSString DeviceID = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
#else
// iOS 5.X or earlier
NSString DeviceID = [[UIDevice currentDevice] uniqueIdentifier];
#endif
The best and recommend option by Apple is:
NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
Use it for every device above 5.0.
For 5.0 you have to use uniqueIdentifier. The best to check if it's available is:
if (!NSClassFromString(#"ASIdentifierManager"))
Combining that will give you:
- (NSString *) advertisingIdentifier
{
if (!NSClassFromString(#"ASIdentifierManager")) {
SEL selector = NSSelectorFromString(#"uniqueIdentifier");
if ([[UIDevice currentDevice] respondsToSelector:selector]) {
return [[UIDevice currentDevice] performSelector:selector];
}
//or get macaddress here http://iosdevelopertips.com/device/determine-mac-address.html
}
return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}
Why just not to use CFUUIDRef and be independent with iOS verion?
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
self.uuidString = (NSString *)CFUUIDCreateString(NULL,uuidRef);
CFRelease(uuidRef);
And of course remember calculated uuidString in the Keychain(in case of application removal)?
Here is written how to use keychain
As hard replacement of static macro, you can try dynamic if statement to check it.
UIDevice has property named 'systemVersion' and you can check this.
Related
I have to read the iOS device's udid in a project with base SDK 7.0 (I know I'm not supposed to, but I need to read it and the identifierForVendor is not an option). I have to to this only on iOS 6 devices, but the method uniqueIdentifier is not recognized because of the base SDK. Since I don't know how to determine the iOS version at compile time, I did the following:
#define SYSTEM_IS_IOS_7 ([[[UIDevice currentDevice] systemVersion] compare:#"7.0" options:NSNumericSearch] != NSOrderedAscending)
...
if (!SYSTEM_IS_IOS_7) {
SEL selector = NSSelectorFromString(#"uniqueIdentifier");
if ([[UIDevice currentDevice] respondsToSelector:selector]) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
[[[UIDevice currentDevice] class] instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
[invocation invoke];
NSString *udid = nil;
[invocation getReturnValue:&udid];
NSLog(#"%#", udid);
}
}
I'm running the code on iOS 6.1, the udid appears on the console, but the app crashes right after that with EXC_BAD_ACCESS in the main.m, with no message on the console. Any idea why and how to solve this?
This question already has answers here:
UIDevice uniqueIdentifier deprecated - What to do now?
(32 answers)
Closed 9 years ago.
Please, do not mark this as a duplicate. This question is about Simperium and the way it deals with uniqueIdentifier and identifierForVendor.
Simperium is still using
[[UIDevice currentDevice] uniqueIdentifier]
in Simperium.m. This has been deprecated and Apple is now completely rejecting apps that use that call.
I am experimenting with
[[[UIDevice] currentDevice] identifierForVendor] UUIDString];
but I am not sure if there would be any problem doing so.
What do you say?
Best,
According to Apple documents identifierForVendor can be used from iOS 6.0 and later so no issues in using identifierForVendor
It is should work. Because they say
"While you may have removed access and usage of UDIDs from your app,
the invalid binary message indicates that your app uses or accesses
UDIDs. Please check your source code for any occurrence of the
"uniqueIdentifier" method; this is the method that returns a device's
UDID."
So it is only matter of using "uniqueIdentifier" method.
Thanks
You can also use this method for fetching uniqueidentifier for your app.
- (NSString *)createUUID{
NSString *uIdentifier = [[NSUserDefaults standardUserDefaults] objectForKey:#"Unique identifier for test"];
if (!uIdentifier) {
CFUUIDRef uuidRef = CFUUIDCreate(NULL);
CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
CFRelease(uuidRef);
uIdentifier = [NSString stringWithString:(NSString *)CFBridgingRelease(uuidStringRef)];
[[NSUserDefaults standardUserDefaults] setObject:uIdentifier forKey:#"Unique identifier for test"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
return uIdentifier;
}
Apple doesn't allowed to add application to the app store that used the [UIDevice uniqueIdentifier] because the property become private in iOS SDK 6.0
What are the Alternatives?
you can use/create "your own" UDID:
+(NSString *)getUUID
{
CFUUIDRef newUniqueId = CFUUIDCreate(kCFAllocatorDefault);
NSString * uuidString = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, newUniqueId);
CFRelease(newUniqueId);
return uuidString;
}
You should keep in mind that this method will produce a different id on every call so you should persist it some how, thus it is not an identical alternative to the UDID, but for most uses it is even better like that.
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
- (NSString*)deviceId {
NSString *udidString;
if (SYSTEM_VERSION_LESS_THAN(#"6.0")) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
udidString = [defaults objectForKey:#"udidKey"];
if (!udidString) {
CFUUIDRef identifierObject = CFUUIDCreate(kCFAllocatorDefault);
// Convert the CFUUID to a string
udidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, identifierObject);
[defaults setObject:udidString forKey:#"udidKey"];
[defaults synchronize];
CFRelease((CFTypeRef) identifierObject);
}
} else {
udidString = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
}
return udidString;
}
if gets warning on the line: udidString = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; it means the Xcode SDK is less than 6.0
(Xcode 4.3 contains iOS SDK 5.1, Xcode 4.5 contains iOS SDK 6.0)
to update Xcode iOS SDK:
simply download the newest Xcode available on App Store (Apple doesn't give an option to download only the SDK).
if want to keep current Xcode version just:
download the newest Xcode version.
copy iOS SDK Library from :
newestXcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/
to
oldXcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/
Reopen old Xcode and thats it!
I have a question about uniqueIdentifier vs identifierforVendor. We use the UDID for login identification purposes and we are in the process of switching over to the new iOS 6 version of forVendor...
My questions are this
1) Is Apple rejecting apps that are still using uniqueIdentifier?
2) How can they reject this seeing as they don't allow first generation ipads to go up to 6.0?
PS - also found that identifierforVendor doesn't always work in 6.0, looks like it was resolved in 6.0.1
Here is the code I am using... do you think it will get rejected?
static inline NSString* UniqueDeviceId() {
if ([[[UIDevice currentDevice] systemVersion] compare:#"6.0.1" options:NSNumericSearch] != NSOrderedAscending)
return [[[UIDevice currentDevice] identifierForVendor] UUIDString];
return [[UIDevice currentDevice] uniqueIdentifier];
}
thanks
While I can't speak for the Apple review team. it is unlikely you will be rejected for using this deprecated API as long as your app supports a version of iOS that doesn't have the alternative.
I would update your code to properly check for the new method:
if ([[UIDevice currentDevice] respondsToSelector:#selector(identifierForVendor)]) {
return [[[UIDevice currentDevice] identifierForVendor] UUIDString];
} else {
return [[UIDevice currentDevice] uniqueIdentifier];
}
now Apps are not permitted to access the UDID and must not use the uniqueIdentifier method of UIDevice. Please update your apps and servers to associate users with the Vendor or Advertising identifiers introduced in iOS 6
NSUUID *uuid = [[UIDevice currentDevice] identifierForVendor];
NSString *uuidString = [uuid UUIDString];
and must to add ADSupport framework
How to detect my current device name through iOS?
Whether you are on an iPhone or a iPod Touch:
UIDevice *device = [UIDevice currentDevice];
NSString *systemName = [device systemName];
To detect the version of the OS:
UIDevice *device = [UIDevice currentDevice];
NSString *systemVersion = [device systemVersion];
To detect a specific model, you would need to test for some capability that only that model has, so to detect an iPhone 3GS, check for a video capability on the camera:
#define SOURCETYPE UIImagePickerControllerSourceTypeCamera
// does the device have a camera?
if ([UIImagePickerController isSourceTypeAvailable:SOURCETYPE]) {
// if so, does that camera support video?
NSArray *mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:SOURCETYPE];
bool isA3GS = [mediaTypes containsObject:kUTTypeMovie];
}
Here is a class written by Erica Sadun that provides extensive capabilities for this:
http://github.com/erica/uidevice-extension/blob/master/UIDevice-Hardware.m
Check out the rest of the repo - there are a few more classes that would prove to be really useful for fine-grained device querying.
From the UIDevice.h file:
[[UIDevice currentDevice] name] // e.g. "My iPhone"
[[UIDevice currentDevice] model] // e.g. #"iPhone", #"iPod Touch"
[[UIDevice currentDevice] localizedModel] // localized version of model
[[UIDevice currentDevice] systemName] // e.g. #"iPhone OS"
[[UIDevice currentDevice] systemVersion] // e.g. #"2.0"
[[UIDevice currentDevice] uniqueIdentifier] // a string unique to each device based on various hardware info.
What you are looking for is this:
UIDevice *device = [UIDevice currentDevice];
NSString *model = [device model];
This will return whether the device is an iPhone or iPod touch