NSUUID /CFUUIDRef /UIDevice -uniqueIdentifier /-identifierForVendor
Let’s say you’re making privacy software that also prevents piracy. I mean, it’s an obvious idea—someone’s going to do it. You’re just trying to be that person.
Until recently, it was trivial to uniquely identify devices between application launches, and even across applications: a simple call to UIDevice -unique
, and you were all set.
However, UIDevice -unique
was deprecated in iOS 5 with the following notes:
Use the
identifier
property of [For Vendor UIDevice
] or theadvertising
property of theIdentifier ASIdentifier
class instead, as appropriate, or use theManager UUID
method of theNSUUID
class to create aUUID
and write it to the user defaults database.
As of May 1st, Apple began enforcing this deprecation on all new app submissions, even for apps targeting earlier versions of iOS. Any use of unique
is grounds for immediate rejection of new binaries.
Just as privacy and piracy have phonetic and conceptual similarities, device identifiers, whether UUID / GUID, UDID, or otherwise can be rather confusing:
- UUID (Universally Unique Identifier): A sequence of 128 bits that can guarantee uniqueness across space and time, defined by RFC 4122.
- GUID (Globally Unique Identifier): Microsoft’s implementation of the UUID specification; often used interchangeably with UUID.
-
UDID (Unique Device Identifier): A sequence of 40 hexadecimal characters that uniquely identify an iOS device (the device’s Social Security Number, if you will). This value can be retrieved through iTunes, or found using
UIDevice -unique
. Derived from hardware details like MAC address.Identifier
Incidentally, all of the suggested replacements for UIDevice -unique
listed in its deprecation notes return UUID, whether created automatically with UIDevice -identifier
& ASIdentifier
or manually with NSUUID
(or CFUUIDCreate
).
Vendor Identifier
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 value in this property remains the same while the app (or another app from the same vendor) is installed on the iOS device. The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them. Therefore, if your app stores the value of this property anywhere, you should gracefully handle situations where the identifier changes.
In many ways, this is what should have been used the whole time. App developers now have a way to identify devices uniquely—even across other apps by the same developer—without being entrusted with something as sensitive as the device’s UDID.
For most applications, doing a find-and-replace of unique
to identifier
is enough.
However, for advertising networks, which require a consistent identifier across applications from many developers, a different approach is required:
Advertising Identifier
iOS 6 introduces the Advertising Identifier, a non-permanent, non-personal, device identifier, that advertising networks will use to give you more control over advertisers’ ability to use tracking methods. If you choose to limit ad tracking, advertising networks using the Advertising Identifier may no longer gather information to serve you targeted ads. In the future all advertising networks will be required to use the Advertising Identifier. However, until advertising networks transition to using the Advertising Identifier you may still receive targeted ads from other networks.
As the sole component of the Ad Support framework, ASIdentifier
’s modus operandi is clear: provide a way for ad networks to track users between different applications in a way that doesn’t compromise privacy.
Users can opt out of ad targeting in a Settings screen added in iOS 6.1, found at Settings > General > About > Advertising:
NSUUID & CFUUIDRef
NSUUID
was added to Foundation in iOS 6 as a way to easily create UUIDs. How easy?
let UUID = NSUUID.UUID().UUIDString
NSString *UUID = [[NSUUID UUID] UUIDString];
If your app targets iOS 5 or earlier, however, you have to settle for Core Foundation functions on CFUUIDRef
:
let UUID = CFUUIDCreate String(nil, CFUUIDCreate(nil))
CFUUIDRef uuid = CFUUIDCreate(NULL);
NSString *UUID = CFUUIDCreate String(NULL, uuid);
For apps building against a base SDK without the vendor or advertising identifier APIs, a similar effect can be achieved—as recommended in the deprecation notes—by using NSUser
:
func application(application: UIApplication!, did Finish Launching With Options launch Options: NSDictionary!) -> Bool {
let user Defaults = NSUser Defaults.standard User Defaults()
if user Defaults.object For Key("Application Unique Identifier") == nil {
let UUID = NSUUID.UUID().UUIDString
user Defaults.set Object(UUID, for Key: "Application Unique Identifier")
user Defaults.synchronize()
}
return true
}
- (BOOL)application:(UIApplication *)application
did Finish Launching With Options:(NSDictionary *)launch Options
{
NSString *UUID = [[NSUser Defaults standard User Defaults] object For Key:k Application UUIDKey];
if (!UUID) {
CFUUIDRef uuid = CFUUIDCreate(NULL);
UUID = (__bridge_transfer NSString *)CFUUIDCreate String(NULL, uuid);
CFRelease(uuid);
[[NSUser Defaults standard User Defaults] set Object:UUID for Key:k Application UUIDKey];
[[NSUser Defaults standard User Defaults] synchronize];
}
}
This way, a UUID will be generated once when the app is launched for the first time, and then stored in NSUser
to be retrieved on each subsequent app launch. Unlike advertising or vendor identifiers, these identifiers would not be shared across other apps, but for most intents and purposes, this is works just fine.
Of course, UUIDs have many other uses: primary identifiers for records in distributed systems, names for temporary files, or even a bulk color generator (chunk the hexadecimal representation into 5 groups of 6!). But on iOS, it’s all about tracking, about finding what was lost in a sea of network traffic and possibilities. Knowing where you stand on uniqueness is the first step to understanding all of this.