티스토리 뷰
사용자의 디바이스 모델명, OS, 앱 버전 상태를 확인하기 위한 방법을 알아보자.
이런 정보는 디버깅, 사용자 지원, UI 최적화, 기능 테스트, 마케팅 및 분석등 다양한 목적으로 사용될 수 있어 요구사항에 따라 적절하게 활용하면 된다.
📖 목차
1️⃣ 클래스 정의
2️⃣ 클래스 사용 예시
3️⃣ 주의 사항
1. 클래스 정의
🟡 속성
필요한 데이터인 모델명, 운영체제/앱 버전을 아래와 같이 정의한다.
- osVersion: 기기 운영체제 이름과 버전
- deviceModel: 기기 모델 이름
- appVersion: 앱의 버전
🟡 초기화 메서드
init()
: 클래스의 인스턴스를 초기화하고, osVersion, deviceModel, appVersion 속성에 값을 할당한다.
1️⃣ osVersion 초기화
let device = UIDevice.current
osVersion = "\(device.systemName) \(device.systemVersion)"
UIDevice.current를 사용하여 현재 기기에 대한 참조를 가져온다.
osVersion 속성은 기기의 운영체제 이름(systemName)과 버전(systemVersion)을 조합하여 설정한다.
2️⃣ deviceModel 초기화
var modelName = ""
let selName = "_\("deviceInfo")ForKey:"
let selector = NSSelectorFromString(selName)
if device.responds(to: selector) {
modelName = String(describing: device.perform(selector, with: "marketing-name").takeRetainedValue())
}
deviceModel = modelName
NSSelectorFromString을 사용하여 _deviceInfoForKey:라는 셀렉터를 동적으로 생성하고, perform 메서드를 사용하여 해당 셀렉터를 호출하고 있다.
_deviceInfoForKey:는 Apple의 공식 문서에 공개되지 않은 비공개 메서드이다.
이 부분이 비공개 API를 사용한 부분이다.
3️⃣ appVersion 초기화
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
{
appVersion = "\(version)"
} else {
appVersion = "Unknown"
}
Bundle.main.infoDictionary에서 CFBundleShortVersionString 및 CFBundleVersion 키를 사용하여 앱의 버전 정보를 가져온다. 가져온 버전 정보를 appVersion 속성에 할당하고, 만약 버전 정보를 가져오지 못하면 "Unknown"으로 설정된다.
전체 코드
import SwiftUI
class DeviceInfoHandler: ObservableObject {
@Published var osVersion: String
@Published var deviceModel: String
@Published var appVersion: String
init() {
let device = UIDevice.current
osVersion = "\(device.systemName) \(device.systemVersion)"
var modelName = ""
let selName = "_\("deviceInfo")ForKey:"
let selector = NSSelectorFromString(selName)
if device.responds(to: selector) {
modelName = String(describing: device.perform(selector, with: "marketing-name").takeRetainedValue())
}
deviceModel = modelName
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
{
appVersion = "\(version)"
} else {
appVersion = "Unknown"
}
}
}
2. 클래스 사용 예시
앱 초기화 시점에서 DeviceInfoHandler를 사용하여 기기 및 앱 정보를 수집하고 출력해보자.
이를 통해 앱 실행 시점에서 어떤 기기와 운영체제 버전이 실행되고 있는지 확인할 수 있다.
@main
struct ExampleApp: App {
init() {
let deviceInfoHandler = DeviceInfoHandler()
print("OS Version: \(deviceInfoHandler.osVersion)")
print("Device Model: \(deviceInfoHandler.deviceModel)")
print("App Version: \(deviceInfoHandler.appVersion)")
}
}
시뮬레이터를 실행하면 앱 실행 시점에서 아래와 같이 출력되는 걸 확인할 수 있다.

3. 주의 사항
🔴 비공개 API 사용 문제
위에서 비공개 API를 빨간색으로 강조한 이유가 있다.
Apple의 비공개 API는 공식적으로 문서화되지 않았고, Apple이 내부적으로 사용하는 API를 말한다.
비공개 API를 사용하는 것은 다음과 같은 이유로 문제가 될 수 있다고 한다,,,
1. 앱 스토어 심사에서 거부될 가능성
: Apple은 앱 스토어 심사 과정에서 앱의 안전성, 보안성, 일관성을 보장하기 위해 비공개 API의 사용을 엄격히 금지하고 있다. 비공개 API를 사용하는 앱은 심사에서 거부될 가능성이 높다.
2. 미래 호환성 문제
: 비공개 API는 문서화되지 않았기 때문에 Apple이 언제든지 변경하거나 제거할 수 있다. 이는 앱이 향후 iOS 업데이트에서 작동하지 않게 만들 수 있다.
3. 안전성 문제
:비공개 API는 공식적으로 지원되지 않기 때문에, 예상치 못한 동작이나 버그가 발생할 수 있다.
결론적으로,,, 사용하지 않는 것이 좋다 ㅎ
이런 비공개 API가 있다는 걸 몰랐는데 지금이라도 알아서 다행이다. 나중에 앱 심사 올리고 난 뒤에 알았으면 타격이 컸을듯 ㅜㅜ
그럼 비공개 API 사용하지 않고 다시 구현해보자!!
🟢 다시 구현
모델명을 출력하는 것에서 비공개 API를 사용했으니 이 부분 코드만 고쳐보았다.
sysctl를 사용하여 구현하는데 sysctl는 Unix 계열 운영체제에서 커널 매개변수를 조작하고 시스템 정보를 얻기 위해 사용되는 함수라고 한다.
iOS에서도 sysctl을 통해 기기 모델명, CPU 정보 등 다양한 시스템 정보를 안전하게 얻을 수 있다.
import SwiftUI
class DeviceInfoHandler: ObservableObject {
@Published var osVersion: String
@Published var deviceModel: String
@Published var appVersion: String
init() {
self.osVersion = UIDevice.current.systemVersion
self.appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
self.deviceModel = DeviceInfoHandler.getModelName()
}
static func getModelName() -> String {
var systemInfo = utsname()
uname(&systemInfo)
let modelCode = withUnsafePointer(to: &systemInfo.machine) { ptr in
return String(cString: UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self))
}
let modelMap: [String: String] = [
"iPhone13,4": "iPhone 12 Pro Max",
"iPhone13,3": "iPhone 12 Pro",
"iPhone13,2": "iPhone 12",
"iPhone13,1": "iPhone 12 Mini",
// 필요한 모델 코드와 이름 추가
]
return modelMap[modelCode] ?? modelCode
}
}
코드의 흐름은 아래와 같다.
- 시스템 정보 가져오기: uname(&systemInfo)를 사용하여 시스템 정보를 가져온다.
- 모델 코드 추출: systemInfo.machine에서 모델 코드를 추출한다.
- 모델 코드 매핑: modelMap 사전을 사용하여 모델 코드를 사람이 읽을 수 있는 이름으로 변환한다.
이렇게 고침으로써 비공개 API 사용을 없애고 안전성 문제를 해결할 수 있었다!!
모델명을 모두 정의해야 하는 점이 귀찮긴한데,, 한번 정의만 해두면 괜찮으니까 ㅎ
결과적으로 사용자 기기 모델명, OS/앱 버전을 모두 출력해볼 수 있었고, 앞으로 필요한 경우에 따라서 사용하면 될 것 같다!
'스위프트 > SwiftUI' 카테고리의 다른 글
[SwiftUI] - Object Storage presigned url 발급 (0) | 2024.08.08 |
---|---|
[SwiftUI] - 리스트 항목의 터치 영역 설정 (0) | 2024.07.08 |
[SwiftUI] - Unit Testing (0) | 2024.05.13 |
[SwiftUI] - Kakao ID 토큰에 nonce 추가 (0) | 2024.04.25 |
[SwiftUI] - ViewModel에서 @State 사용시 문제점 (0) | 2024.04.18 |