98 lines
2.8 KiB
Swift
98 lines
2.8 KiB
Swift
//
|
|
// KeychainHelper.swift
|
|
// dimensionhub
|
|
//
|
|
// Created by 安礼成 on 2025/6/26.
|
|
//
|
|
import Foundation
|
|
import Security
|
|
import UIKit
|
|
|
|
struct KeychainHelper {
|
|
|
|
// MARK: - 设备标识符获取
|
|
static func getPersistentUserId() -> String {
|
|
let keychainAccount = "com.jihe.dimensionhub.deviceUUID"
|
|
|
|
// 1. 尝试从Keychain读取
|
|
if let uuid = load(key: keychainAccount) {
|
|
return uuid
|
|
}
|
|
|
|
// 2. 生成新的UUID
|
|
let newUUID = generatorUserId()
|
|
|
|
// 3. 尝试保存到Keychain
|
|
let data = newUUID.data(using: .utf8)!
|
|
if !save(key: keychainAccount, data: data) {
|
|
NSLog("save uuid to keychain error")
|
|
}
|
|
|
|
return newUUID
|
|
}
|
|
|
|
/// 从 Keychain 加载字符串
|
|
private static func load(key: String) -> String? {
|
|
if let data = loadFromSecurity(key: key) {
|
|
return String(data: data, encoding: .utf8)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
/// 删除 Keychain 中的项
|
|
static func delete(key: String) -> Bool {
|
|
let query = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrAccount as String: key
|
|
] as [String: Any]
|
|
|
|
let status = SecItemDelete(query as CFDictionary)
|
|
return status == errSecSuccess || status == errSecItemNotFound
|
|
}
|
|
|
|
// MARK: - 私有方法
|
|
|
|
private static func save(key: String, data: Data) -> Bool {
|
|
let query = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrAccount as String: key,
|
|
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
|
|
kSecValueData as String: data
|
|
] as [String: Any]
|
|
|
|
// 先删除已存在的项
|
|
SecItemDelete(query as CFDictionary)
|
|
|
|
// 添加新项
|
|
let status = SecItemAdd(query as CFDictionary, nil)
|
|
return status == errSecSuccess
|
|
}
|
|
|
|
private static func loadFromSecurity(key: String) -> Data? {
|
|
let query = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrAccount as String: key,
|
|
kSecReturnData as String: kCFBooleanTrue!,
|
|
kSecMatchLimit as String: kSecMatchLimitOne
|
|
] as [String: Any]
|
|
|
|
var dataTypeRef: AnyObject?
|
|
let status = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
|
|
|
|
if status == errSecSuccess {
|
|
return dataTypeRef as? Data
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 生成uuid
|
|
private static func generatorUserId() -> String {
|
|
if let uuid = UIDevice.current.identifierForVendor?.uuidString {
|
|
return uuid.lowercased()
|
|
} else {
|
|
return UUID().uuidString.lowercased()
|
|
}
|
|
}
|
|
|
|
}
|