iOS设备唯一标识-(UUID+Keychain)

在iOS设备上获取唯一的设备标识符需要特别注意隐私保护。苹果为了保护用户隐私,限制了开发者直接访问设备的唯一标识符(如UDID)。不过,可以采用UUID+Keychain方式代替唯一标识。
将UUID存储于Keychain中,这种方法的好处是,当用户卸载并重新安装应用时,这个标识符会保持不变,但如果用户更换了设备,则会生成新的标识符。

具体实现如下:

1、导入 Security 框架

1
import Security

2、定义Keychain操作函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import UIKit
import Security

// 将信息存入Keychain中,用户卸载应用信息不丢失
class DPKeychain {
// 将字符串值保存到Keychain中。
static func saveToKeychain(_ value: String, service: String, account: String) -> Bool {
guard let data = value.data(using: .utf8) else { return false }

// 删除旧的数据
SecItemDelete(query(service: service, account: account) as CFDictionary)

// 添加新的数据
let query = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecValueData as String: data
] as [String: Any]

let status = SecItemAdd(query as CFDictionary, nil)
return status == errSecSuccess
}
// 从Keychain中加载字符串值
static func loadFromKeychain(service: String, account: String) -> String? {
let query = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecReturnData as String: kCFBooleanTrue!,
kSecMatchLimit as String: kSecMatchLimitOne
] as [String: Any]

var item: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &item)

if status == errSecSuccess, let data = item as? Data {
return String(data: data, encoding: .utf8)
}

return nil
}
// 从Keychain中删除指定的服务和账户的数据。
static func deleteFromKeychain(service: String, account: String) -> Bool {
let query = query(service: service, account: account)
let status = SecItemDelete(query as CFDictionary)
return status == errSecSuccess
}

private static func query(service: String, account: String) -> [String: Any] {
return [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account
]
}


}

3、创建Keychain服务

1
2
let keychainService = "com.yourcompany.yourapp" 
let keychainAccount = "uniqueIdentifier"

4、使用UUID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import UIKit

// keychainService = com.yourcompany.yourapp
let keychainService = "com.wh.b"
let keychainAccount = "uniqueIdentifier"

class DPUser {

// 获取iOS设备唯一标识
static func getUniqueIdentifier() -> String {
// 检查Keychain中是否已有UUID,如果有则返回,否则生成新的UUID并保存到Keychain中。
if let identifier = DPKeychain.loadFromKeychain(service: keychainService, account: keychainAccount) {
return identifier
} else {
let newIdentifier = UUID().uuidString
let success = DPKeychain.saveToKeychain(newIdentifier, service: keychainService, account: keychainAccount)
if !success {
print("Failed to save unique identifier to Keychain")
}
return newIdentifier
}
}
}

// 获取唯一标识符
let uniqueIdentifier = DPUser.getUniqueIdentifier()
print("当前设备唯一标识-UUID: \(uniqueIdentifier)")

此处有demo