As you might be aware, Apple puts lots of restrictions on unique identifiers because of privacy concerns. But in this article, we will look at some of the available options which can use to uniquely identify Apple (iOS, tvOS, and macOS) devices.

1. Store unique device identifier in KeyChain

We can use KeyChain to persistently store a device identifier. KeyChain storage is independent of Apps storage so when we delete the app then the system doesn't delete the value stored in KeyChain by that app.

Also, we can access KeyChain from different apps by configuring the keychain sharing. To store the value in KeyChain we can use KeychainAccess cocoapods. Here is the example -

import Foundation
import KeychainAccess

struct DeviceUUID {
	static let keychainServiceIdentifier: String = "co.developerinsider"
	static let deviceUUIDIdentifier: String = "co.developerinsider.hash"

	static func getUUID() -> String {
		let keychain = Keychain(service: keychainServiceIdentifier)
		var deviceUUID: String = ""
		do {
			deviceUUID = try keychain.get(deviceUUIDIdentifier) ?? ""
		} catch {
			dump(error)
		}

		if deviceUUID.isEmpty {
			do {
				let uuid = UUID().uuidString
				try keychain.set(uuid, key: deviceUUIDIdentifier)
				deviceUUID = uuid
			} catch {
				dump(error)
			}
		}
		return deviceUUID
	}
}

Now to get this value we can use it like this -

DeviceUUID.getUUID()

This is the most reliable option to get a device identifier right now for Apple platforms.

2. DeviceCheck API

Using the DeviceCheck APIs, in combination with server-to-server APIs, you can set and query two bits of data per device, while maintaining user privacy. You might use this data to identify devices that have already taken advantage of a promotional offer that you provide, or to flag a device that you've determined to be fraudulent. The DeviceCheck APIs also let you verify that the token you receive comes from an authentic Apple device on which your app has been downloaded.

Read more about DeviceCheck API here.

3. Identifier for Vendor

Another option is identifierForVendor. This is an alphanumeric string that uniquely identifies a device to the app's vendor. 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. We can access this value like this -

UIDevice.current.identifierForVendor?.uuidString

But the value of identifierForVendor can change due to different reasons. Like:

  • The value changes when the user deletes all apps of a vendor.
  • The value might change when the user reinstalls one or more apps for a vendor.
  • The value can also change when installing test builds using Xcode or when installing an app on a device using ad-hoc distribution.

Therefore, we can't rely on the identifierForVendor to uniquely identify a device.

4. Advertising Identifier

If you want a universal ID then you have the option to use advertisingIdentifier. However, if the user has limited ad tracking in their device settings or disallows the application to not use cross-app tracking then this value will simply return all zeroes.

import AdSupport

let identifierManager = ASIdentifierManager.shared()
if identifierManager.isAdvertisingTrackingEnabled {
    let deviceId = identifierManager.advertisingIdentifier.uuidString
}

On devices running iOS 14.5 and later and iPadOS 14.5 and later, your app must request tracking authorization before it can get the advertising identifier.

Also, Apple recommends that this code only be used by companies building advertisement frameworks, rather than the app developers themselves. If you use this within your code for non-ad-related purposes then prepare to have your app rejected.