Notice
Recent Posts
Recent Comments
Link
투케이2K
60. (TWOK/UTIL) [Ios/Objc] S_DeviceID - 단말기 고유값 지정 실시 (키 체인 , UUID) 본문
투케이2K 유틸파일
60. (TWOK/UTIL) [Ios/Objc] S_DeviceID - 단말기 고유값 지정 실시 (키 체인 , UUID)
투케이2K 2022. 6. 24. 08:43[설 명]
프로그램 : Ios / Objective-C
설 명 : S_DeviceID - 단말기 고유값 지정 실시 (키 체인 , UUID)
[소스 코드]
import Foundation
import Security
import UIKit
@objc class S_DeviceID: NSObject {
// MARK: - [클래스 설명]
/*
// -----------------------------------------
1. 디바이스 고유값 저장 클래스
// -----------------------------------------
2. 디바이스 정보 저장 : [[S_DeviceID shared] createDeviceID];
// -----------------------------------------
3. 디바이스 정보 조회 : [[S_DeviceID shared] getDeviceID];
// -----------------------------------------
4. 디바이스 정보 삭제 : [[S_DeviceID shared] deleteDeviceID];
// -----------------------------------------
5. 호출 방법 :
NSString *deviceId = [[S_DeviceID shared] getDeviceID];
if ([[C_Util shared] stringNotNullWithStr:deviceId] == true){
// [저장된 디바이스 고유값 확인 실시]
}
else {
// [디바이스 고유값 저장 실시]
[[S_DeviceID shared] createDeviceID];
}
// -----------------------------------------
*/
// MARK: - [키 체인 설명]
/*
// -----------------------------------------
1. Keychain 은 디바이스 안에 암호화된 데이터 저장 공간입니다
// -----------------------------------------
2. Keychain 은 보안 기능이 뛰어나 사용자 정보 및 결제 정보 등 민감한 정보를 저장할 수 있습니다
// -----------------------------------------
3. Keychain 은 앱 종료 및 앱 삭제 후 재설치를 진행해도 동일하게 저장된 값을 사용할 수 있습니다
- 영구적인 데이터
- 사용자가 삭제하지 않는 이상 유지
- Keychain 은 사용자가 데이터를 삭제하거나, 휴대폰 공장 초기화를 진행 시 삭제됩니다
// -----------------------------------------
4. 설정 패키지 : import Security
// -----------------------------------------
*/
// MARK: - [UUID 설명]
/*
// -----------------------------------------
1. uuid 는 32개의 문자+숫자로 이루어집니다
// -----------------------------------------
2. iOS4까지는 iOS기기의 고유 넘버로 udid를 사용했지만, 보안 문제로 iOS5부터는 uudi(임의로 생성한 고유값)를 사용합니다
// -----------------------------------------
3. uuid는 앱을 삭제하면 새롭게 생성됩니다
// -----------------------------------------
4. uuid는 Vender 에 따라서 값이 달라집니다 (공급업체(벤더)가 같은 앱들은 모두 같은 고유 ID를 가집니다)
// -----------------------------------------
5. uuid 외에도 ADID (IDFA) 라는 것이 있는데 이는 광고 식별자이고 기기마다 고유한 값을 가집니다
- 앱 스토어 등록 심사 시 필수 광고 식별자 사용을 체크하고 사유를 적어야합니다 (아니면, 앱 스토어 등록 거부될 수 있습니다)
// -----------------------------------------
6. 설정 패키지 : import UIKit
// -----------------------------------------
*/
// MARK: - [Keychain 생성 정보 정의]
private let account = "ServiceSaveKeyTwok" // [디바이스 고유값 KEY]
private let service = Bundle.main.bundleIdentifier // [번들 아이디]
// MARK: - [클래스 이름 설정]
let ACTIVITY_NAME = "S_DeviceID"
// MARK: - [클래스 싱글톤 설정]
@objc static let shared = S_DeviceID()
// MARK: - [Keychain 사용해 디바이스 고유값 저장 실시]
@objc func createDeviceID() {
// -----------------------------------------
guard let serviceCheck = self.service as? String
else {
// [프리퍼런스에 UUID 저장 : [앱 삭제 시 지워짐]]
let uuidCreate = UUID().uuidString
UserDefaults.standard.set(uuidCreate, forKey: self.account)
UserDefaults.standard.synchronize() // 동기화 실시
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> createDeviceID() :: Service Check :: false]")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 UUID 저장 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
return
}
// -----------------------------------------
// [번들 아이디 널 체크 수행 실시]
var serviceId = ""
if serviceCheck != nil && serviceCheck.count>0 && serviceCheck != "" {
serviceId = serviceCheck
}
else {
serviceId = "com.app." + self.account
}
// -----------------------------------------
// [디바이스 고유값 생성 실시]
let deviceID = self.setDeviceID()
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> createDeviceID() :: [사전] 디바이스 고유값 [저장] 에 필요한 정보 확인]")
print("-------------------------------")
print("account :: \(self.account)")
print("-------------------------------")
print("service :: \(serviceId)")
print("-------------------------------")
print("deviceID :: \(deviceID)")
print("====================================")
print("")
// -----------------------------------------
/*
// [일반 프리퍼런스에 UUID 저장 : [앱 삭제 시 지워짐]]
let uuidCreate = UUID().uuidString
UserDefaults.standard.set(uuidCreate, forKey: self.account)
UserDefaults.standard.synchronize() // 동기화 실시
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> createDeviceID() :: 디바이스 고유값 [저장] [성공]]")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 UUID 저장 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
// */
// -----------------------------------------
///*
// [키 체인 쿼리 생성]
let query:[CFString: Any]=[kSecClass: kSecClassGenericPassword, // 보안 데이터 저장
kSecAttrService: serviceId, // 키 체인에서 해당 앱을 식별하는 값 (앱만의 고유한 값)
kSecAttrAccount: self.account, // 앱 내에서 데이터를 식별하기 위한 키에 해당하는 값 (사용자 계정)
kSecValueData: deviceID.data(using: .utf8, allowLossyConversion: false)!] // 키값에 디바이스 고유값 저장
// [keychain 에 저장을 수행한 결과 값 반환 (true / false)]
let status: OSStatus = SecItemAdd(query as CFDictionary, nil)
if status == errSecSuccess {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> createDeviceID() :: 디바이스 고유값 [저장] [성공]]")
print("-------------------------------")
print("Success Status :: \(status)")
print("-------------------------------")
print("type :: [키 체인] 데이터")
print("-------------------------------")
print("deviceID :: \(deviceID)")
print("====================================")
print("")
}
else {
// [프리퍼런스에 UUID 저장 : [앱 삭제 시 지워짐]]
let uuidCreate = UUID().uuidString
UserDefaults.standard.set(uuidCreate, forKey: self.account)
UserDefaults.standard.synchronize() // 동기화 실시
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> createDeviceID() :: 디바이스 고유값 [저장] [실패]]")
print("-------------------------------")
print("Fail Status :: \(status)")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 UUID 저장 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
}
// */
// -----------------------------------------
}
// MARK: - [Keychain 사용해 디바이스 고유값 호출 실시]
@objc func getDeviceID() -> String {
// -----------------------------------------
guard let serviceCheck = self.service as? String
else {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> getDeviceID() :: Service Check :: false]")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 저장된 값 반환 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
// [프리퍼런스에 저장된 값 반환 실시]
return UserDefaults.standard.string(forKey: self.account) ?? ""
}
// -----------------------------------------
// [번들 아이디 널 체크 수행 실시]
var serviceId = ""
if serviceCheck != nil && serviceCheck.count>0 && serviceCheck != "" {
serviceId = serviceCheck
}
else {
serviceId = "com.app." + self.account
}
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> getDeviceID() :: [사전] 저장된 디바이스 고유값 [호출] 에 필요한 정보 확인]")
print("-------------------------------")
print("account :: \(self.account)")
print("-------------------------------")
print("service :: \(serviceId)")
print("====================================")
print("")
// -----------------------------------------
// [사전 UUID 로 저장된 정보가 있는지 확인 실시]
let checkUUid = UserDefaults.standard.string(forKey: self.account) ?? ""
if checkUUid != nil && checkUUid.count > 0 && checkUUid != "" {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> getDeviceID() :: 저장된 디바이스 고유값 [호출] [성공]]")
print("-------------------------------")
print("type :: [UUID] 데이터")
print("-------------------------------")
print("deviceID :: \(checkUUid)")
print("====================================")
print("")
// [프리퍼런스에 저장된 값 반환 실시]
return checkUUid
}
// -----------------------------------------
// [키 체인 쿼리 정의]
let query:[CFString: Any]=[kSecClass: kSecClassGenericPassword, // 보안 데이터 저장
kSecAttrService: serviceId, // 키 체인에서 해당 앱을 식별하는 값 (앱만의 고유한 값)
kSecAttrAccount : self.account, // 앱 내에서 데이터를 식별하기 위한 키에 해당하는 값 (사용자 계정)
kSecReturnData : true, // kSecReturnData에 true를 리턴시켜 값을 불러옵니다
kSecReturnAttributes: true, // kSecReturnAttributes에 true를 리턴시켜 값을 불러옵니다
kSecMatchLimit : kSecMatchLimitOne] // 값이 일치하는 것을 찾습니다
// [키 체인에 저장된 값을 읽어옵니다]
var dataTypeRef : CFTypeRef?
let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
// [처리 결과가 성공인 경우 >> 키 체인에서 읽어온 값을 Data 타입으로 변환 >> 다시 String 타입으로 변환]
if status == errSecSuccess {
guard let existingItem = dataTypeRef as? [String: Any]
else {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> getDeviceID() :: Type Check :: false]")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 저장된 값 반환 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
// [프리퍼런스에 저장된 값 반환 실시]
return UserDefaults.standard.string(forKey: self.account) ?? ""
}
let deviceData = existingItem[kSecValueData as String] as? Data
let uuidData = String(data: deviceData!, encoding: .utf8)!
if uuidData != nil && uuidData.count>0 && uuidData != "" {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> getDeviceID() :: 저장된 디바이스 고유값 [호출] [성공]]")
print("-------------------------------")
print("Success Status :: \(status)")
print("-------------------------------")
print("type :: [키 체인] 데이터")
print("-------------------------------")
print("deviceID :: \(uuidData)")
print("====================================")
print("")
return uuidData
}
else {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> getDeviceID() :: 저장된 디바이스 고유값 [호출] [실패]]")
print("-------------------------------")
print("Fail Status :: 저장된 데이터 값이 NULL 상태")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 저장된 값 반환 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
// [프리퍼런스에 저장된 값 반환 실시]
return UserDefaults.standard.string(forKey: self.account) ?? ""
}
}
else if status == errSecItemNotFound || status == -25300 {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> getDeviceID() :: 저장된 디바이스 고유값 [호출] [실패]]")
print("-------------------------------")
print("Fail Status :: 저장된 데이터가 없습니다")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 저장된 값 반환 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
// [프리퍼런스에 저장된 값 반환 실시]
return UserDefaults.standard.string(forKey: self.account) ?? ""
}
else {
// [처리결과가 실패라면 nil을 반환]
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> getDeviceID() :: 저장된 디바이스 고유값 [호출] [실패]]")
print("-------------------------------")
print("Fail Status :: \(status)")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 저장된 값 반환 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
// [프리퍼런스에 저장된 값 반환 실시]
return UserDefaults.standard.string(forKey: self.account) ?? ""
}
// -----------------------------------------
}
// MARK: - [Keychain 에 저장된 값 삭제 수행]
@objc func deleteDeviceID() {
// -----------------------------------------
guard let serviceCheck = self.service as? String
else {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> deleteDeviceID() :: Service Check :: false]")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 저장된 값 삭제 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
// [프리퍼런스에 저장된 값 삭제]
UserDefaults.standard.removeObject(forKey: self.account)
UserDefaults.standard.synchronize() // 동기화 실시
return
}
// -----------------------------------------
// [번들 아이디 널 체크 수행 실시]
var serviceId = ""
if serviceCheck != nil && serviceCheck.count>0 && serviceCheck != "" {
serviceId = serviceCheck
}
else {
serviceId = "com.app." + self.account
}
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> deleteDeviceID() :: [사전] 디바이스 고유값 [삭제] 에 필요한 정보 확인]")
print("-------------------------------")
print("account :: \(self.account)")
print("-------------------------------")
print("service :: \(serviceId)")
print("====================================")
print("")
// -----------------------------------------
// [사전 UUID 로 저장된 정보가 있는지 확인 실시]
let checkUUid = UserDefaults.standard.string(forKey: self.account) ?? ""
if checkUUid != nil && checkUUid.count > 0 && checkUUid != "" {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> deleteDeviceID() :: 디바이스 고유값 [삭제] [성공]]")
print("-------------------------------")
print("type :: [UUID] 데이터")
print("====================================")
print("")
// [프리퍼런스에 저장된 값 삭제]
UserDefaults.standard.removeObject(forKey: self.account)
UserDefaults.standard.synchronize() // 동기화 실시
return
}
// -----------------------------------------
// [키 체인 쿼리 정의]
let query:[CFString: Any]=[kSecClass: kSecClassGenericPassword, // 보안 데이터 저장
kSecAttrService: serviceId, // 키 체인에서 해당 앱을 식별하는 값 (앱만의 고유한 값)
kSecAttrAccount : self.account] // 앱 내에서 데이터를 식별하기 위한 키에 해당하는 값 (사용자 계정)
// [현재 저장되어 있는 값 삭제]
let status: OSStatus = SecItemDelete(query as CFDictionary)
if status == errSecSuccess {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> deleteDeviceID() :: 디바이스 고유값 [삭제] [성공]]")
print("-------------------------------")
print("Success Status :: \(status)")
print("-------------------------------")
print("type :: [키 체인] 데이터")
print("====================================")
print("")
}
else {
print("")
print("====================================")
print("[\(self.ACTIVITY_NAME) >> deleteDeviceID() :: 디바이스 고유값 [삭제] [실패]]")
print("-------------------------------")
print("로 직 :: [프리퍼런스] 에 저장된 값 삭제 실시")
print("-------------------------------")
print("UUID :: \(UserDefaults.standard.string(forKey: self.account) ?? "")")
print("====================================")
print("")
// [프리퍼런스에 저장된 값 삭제]
UserDefaults.standard.removeObject(forKey: self.account)
UserDefaults.standard.synchronize() // 동기화 실시
}
// -----------------------------------------
}
// MARK: - [디바이스 고유 값 추출 메소드]
@objc func setDeviceID() -> String {
return UIDevice.current.identifierForVendor!.uuidString
}
} // [클래스 종료]
반응형
'투케이2K 유틸파일' 카테고리의 다른 글
Comments