On March 21st Apple notified developers that as of May 1st, apps that accessed UDIDs would no longer be approved and that developers should switch over to using “Vendor or Advertising identifiers introduced in iOS 6”.
We had been warned that
uniqueIdentifier was going away, and now Apple is giving us not just one but two alternatives to use. But which one should you use and when is it appropriate to choose one over the other? The documentation doesn’t answer these questions and it is left up to you to decide what is best for your applications’ purposes.
I am going to outline each of the iOS supported and deprecated unique identifier methods to explain what they do in hopes of arming you with the knowledge you need to make the right decisions.
Starting with the oldest, CFUUID has been around since iOS 2.0. It is part of the CoreFoundation package and therefore C style API. CFUUIDCreate is the method you use to create the CFUUIDRef and you can get an NSString representation of the created CFUUIDRef like this.
CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault); NSString *cfuuidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
The thing to know about the CFUUID is that it is not persisted at all. Every time you call
CFUUIDCreate the system will return to you a brand new unique identifier. If you want to persist this identifier you will need to do that yourself using NSUserDefaults, Keychain, Pasteboard or some other means.
This is the new younger cousin to CFUUID. NSUUID just popped up in iOS 6. It is pretty much exactly the same as CFUUID except it has a nice, modern Objective-C interface. + (id)UUID is the class method you call to get a UUID and you can get an NSString representation of that UUID object like this.
NSString *uuid = [[NSUUID UUID] UUIDString];
Just like the CFUUID, this is not persisted at all and you will get a new unique identifier each time you call it. You must do all the persisting yourself. I noticed an interesting thing while reading the docs on NSUUID. The example ID that Apple gives for both CFUUID and NSUUID are the exact same identifier.
Another new method as of iOS 6, advertisingIdentifier is part of the new AdSupport.framework. The ASIdentifierManager singleton exposes the method advertisingIdentifier and calling that returns an instance of the NSUUID class mentioned above.
NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
Unlike the direct CFUUID and NSUUID calls, the advertisingIdentifier is persisted by the system. However, even though it is persisted there are a few scenarios in which it will get regenerated. If the user does a full system reset (Settings.app -> General -> Reset -> Reset All Content and Settings) the advertisingIdentifier will get regenerated. If the user explicitly resets it (Settings.app -> General -> About -> Advertising -> Reset Advertising Identifier) it will get regenerated. There is one caveat to the Advertising Reset. If your app is running in the background while the user does a “Reset Advertising Identifier” and then returns to your app, the advertisingIdentifier is not immediately reset the next time you call it. You must terminate your app and then re-launch it to get the reset advertisingIdentifier. My guess is that this is because ASIdentifierManager is exposed as a singleton.
Another option available to users is to “Limit Ad Tracking”. As our own Nick Arnott has already pointed out, turning this option on does nothing to actually limit your access to the advertisingIdentifier. It is simply a boolean flag that you are supposed to respect when sending the advertisingIdentifier to any servers.
Identifier for Vendor (IDFV)
This call was also added in iOS 6, but it was added as a new method on the existing UIDevice class. Just like advertisingIdentifier, it returns an NSUUID object.
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
The documentation for the identifierForVendor says this.
The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.
The question I had after reading that was, “what’s a vendor?” My first thought was that a vendor was defined as an Apple Developer Account. That turned out to be dead wrong. Next I thought it might it have to do with the AppIdentifierPrefix; similar to how Keychain Access can be shared between apps. Also dead wrong. It turns out to be very simple. A Vendor is defined by the first two parts of the reverse DNS formatted CFBundleIdentifier. For example
com.doubleencore.app2 would be able to get the same identifierForVendor since they share the same
com.doubleencore part of the CFBundleIdentifier. But
com.massivelyoverrated or even
net.doubleencore would get a completely different identifierForVendor.
The other thing to point out here is that if a user uninstalls all of the apps from a vendor and then re-installs them, the identifierForVendor will be reset.
The old tried and true but deprecated in iOS 5. You know it, you love it but don’t even think of using it again because it is going away. At least it is for apps that will be submitted to the App Store. It remains to be seen if
uniqueIdentifier will be turned into a private method or completely removed in a future iOS version. It is still needed for developers to provision devices in the iOS Developer Portal. And if you are distributing Enterprise signed applications it can also be very handy.
NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];
Back when iOS 5 was released and uniqueIdentifier became deprecated there was a rush to find an alternative to the UDID that was not controlled by Apple. It seems that OpenUDID is the most widely used open source UDID alternative. OpenUDID is super simple to implement in your project and is supported by a slew of advertising providers.
NSString *openUDID = [OpenUDID value];
OpenUDID uses a very clever way to persist the identifier across applications. It uses specially named Pasteboards to store the identifier. This way, other apps that also use OpenUDID know where to go look and can grab the already generated identifier instead of generating a new one.
It has been mentioned that Apple will start to enforce the use of either the
advertisingIdentifier or the
identifierForVendor in the future. If this is the case, even though OpenUDID might seem like a good option now, you might have to transition to one of the Apple approved calls anyway.
I hope I have presented you with enough information to help you make an informed decision about which unique identifier is right for your app. I have created a small unique identifier test app that you can run and view the output of all of the above mentioned calls. And below you will find a couple of tables that outline the calls, their iOS availability and when you can expect the identifier to get reset.
* The app must be restarted in order to see the change.
** All apps from that vendor must be deleted in order to change the value.