Keywords: iOS | UIDevice | uniqueIdentifier | identifierForVendor | UUID | Keychain | alternatives
Abstract: This article explores the deprecation of the UIDevice uniqueIdentifier property since iOS 5 and its unavailability in iOS 7 and above. It analyzes multiple alternative approaches, including using CFUUIDCreate, the limitations of MAC addresses, and the recommended use of identifierForVendor. Additionally, it discusses Keychain storage for stable IDs and provides detailed code examples to illustrate implementation. Recommendations are given for best practices based on different iOS versions and requirements, helping developers transition smoothly.
In iOS development, the UIDevice uniqueIdentifier property was historically used for uniquely identifying devices, but it has been deprecated since iOS 5 and removed in iOS 7 and above. This change has forced many applications to restructure their identification logic. Through analysis and code examples, this article details and recommends current alternative methods.
Historical Background and Problem Description
The original uniqueIdentifier property provided a persistent device ID for purposes like user tracking and device management. Due to privacy and security concerns, Apple deprecated it in 2012 and removed it in later versions, leading developers to seek stable and compliant alternatives.
Analysis of Main Alternative Approaches
Based on Apple's official documentation, the primary alternatives include:
1. Using CFUUIDCreate to Generate UUID
This is a common first choice for many developers. The CFUUIDCreate function generates a unique UUID on each call. A typical approach involves storing the UUID in NSUserDefaults, for example:
let uuid = CFUUIDCreateString(kCFAllocatorDefault, CFUUIDCreate(kCFAllocatorDefault)) as String
UserDefaults.standard.set(uuid, forKey: "appUUID")
However, if a user uninstalls and reinstalls the app, this UUID will be regenerated, causing identification instability.
2. Using MAC Address
In the past, some solutions involved querying the device's MAC address (e.g., from the en0 interface) to generate a unique ID. For instance, using ifconfig commands to retrieve the MAC and processing it with hashing like MD5. But in iOS 7 and above, Apple altered the return value to always be 02:00:00:00:00:00 to prevent this method from being exploited, rendering the approach obsolete.
3. Using identifierForVendor
This is Apple's recommended solution, available since iOS 6. identifierForVendor returns a unique ID for the vendor (i.e., the developer account). If a user installs multiple apps from the same vendor, this ID remains consistent; but if all apps are uninstalled, it resets. Code example:
if let vendorID = UIDevice.current.identifierForVendor?.uuidString {
print("Vendor ID: " + vendorID)
}
This method can often replace uniqueIdentifier with minimal changes, but note its dependency on the vendor account.
4. Storing UUID in Keychain
To address the issue of UUID change upon app reinstallation, using Keychain storage for the generated UUID is effective. Keychain data persists after app uninstallation and is only cleared upon device reset. Example using a library like SFHFKeychainUtils:
import Security
let keychainKey = "appUniqueID"
let uuid = CFUUIDCreateString(kCFAllocatorDefault, CFUUIDCreate(kCFAllocatorDefault)) as String
let status = SecItemAdd([kSecClass: kSecClassGenericPassword, kSecAttrAccount: keychainKey, kSecValueData: uuid.data(using: .utf8)!] as CFDictionary, nil)
if status == errSecSuccess {
print("UUID stored in Keychain")
}
This approach provides long-term stable identification but requires more complex security management.
Code Implementation Examples and Explanation
The following examples demonstrate how to choose different approaches based on requirements. Starting from core concepts, the code is rewritten to ensure better integration into explanations.
Scenario 1: Need stable identification across all iOS versions
If the app needs to support lower iOS versions (e.g., < 6.0), using Keychain storage for UUID is suitable. In this case, a framework can be implemented recursively to select the scheme based on device conditions, such as checking the version and using appropriate APIs. Note that the MAC method is disabled by Apple in iOS 7+, so it should be avoided.
Scenario 2: Application requires direct transition to modern methods
For scenarios needing stability and compatibility with high versions, identifierForVendor is the best choice. If the app supports only iOS 6+, it can be used directly. To ensure consistency, implement storage mechanisms (e.g., UserDefaults) to cache the ID and prevent regeneration.
Example of a comparison framework:
func generateDeviceID() -> String {
if #available(iOS 6.0, *) {
// Use identifierForVendor
if let vendorID = UIDevice.current.identifierForVendor?.uuidString {
return vendorID
}
}
// In other cases, use Keychain-stored UUID
let key = "deviceUniqueID"
if let storedID = KeychainHelper.retrieve(forKey: key) {
return storedID
} else {
let newID = UUID().uuidString
KeychainHelper.save(newID, forKey: key)
return newID
}
}
Through this approach, different solutions can be combined based on actual needs to optimize performance and security.
Recommendations and Best Practices
Based on the analysis, the following recommendations are proposed:
- High iOS versions (e.g., iOS 8+): Prioritize using
identifierForVendor, as it requires no extra storage and offers good privacy protection. - Low iOS versions (e.g., iOS 5): Consider using Keychain storage for UUID. But note that this method may require code beyond standard APIs.
- Cross-version support: It is advisable to adopt a reliable identification framework that uses version detection and fallback schemes to enhance compatibility.
- Common pitfalls to avoid: Do not use MAC addresses directly as IDs, as they are invalid in iOS 7+; also, be aware that UUIDs generated by
CFUUIDCreatechange upon uninstallation.
Overall, by integrating schemes and practical needs, developers can effectively address the challenges brought by the deprecation of uniqueIdentifier, thereby achieving more reliable and secure device identification.