🐸

【iOS / Swift】Swiftで実行中の端末の機種名を取得する方法

に公開

概要

Swiftでアプリを実行中の端末機種名を取得する方法を調査・実装しました。

きっかけ

アプリでログインAPIを実行する際、リクエストパラメータに端末の機種名を含めて欲しい、という要望があったため調査・実装しました。

開発環境

2023年10月時点

  • Xcode 14.3
  • 対応OS:iOS 14.0以降
  • UIKit
  • UIDevice

取得方法

SwiftにはUIDeviceというクラスがありますが、iPhone, iPadなどのモデルまでしか取得できません。
そのため、UIDeviceクラスを拡張して自分で端末の内部名を取得して、一般名に変換する必要があります。

  • iPhone13,3 → iPhone 12 Pro
  • 内部名 → 一般名

内部名の取得

utsnameというOSの名称を調べるメソッドを使用して、内部名を取得します。

var modelIdentifier: String {
    var systemInfo: utsname = utsname()
    uname(&systemInfo)
    let machineMirror: Mirror = Mirror(reflecting: systemInfo.machine)
    let identifier: String = machineMirror.children.reduce("") { identifier, element in
        guard let value = element.value as? Int8, value != 0 else {
            return identifier
        }
        return identifier + String(UnicodeScalar(UInt8(value)))
    }
    return identifier
}

内部名から一般名へ変換するためのリスト

内部名から一般名に変換するには、アプリ内に辞書型の配列["内部名": "一般名"]を持つ必要があります。
内部名と一般名の対応リストを作成する際に参考にした記事

var modelNameList: [String: String] {
    let modelNameList: [String: String] = [
    // iPhone
    // 全て記載すると長いのでiPhoneのみ
    "iPhone7,1": "iPhone 6 Plus",
    "iPhone7,2": "iPhone 6",
    "iPhone8,1": "iPhone 6s",
    "iPhone8,2": "iPhone 6s Plus",
    "iPhone8,4": "iPhone SE",
    "iPhone9,1": "iPhone 7",
    "iPhone9,3": "iPhone 7",
    "iPhone9,2": "iPhone 7 Plus",
    "iPhone9,4": "iPhone 7 Plus",
    "iPhone10,1": "iPhone 8",
    "iPhone10,4": "iPhone 8",
    "iPhone10,2": "iPhone 8 Plus",
    "iPhone10,5": "iPhone 8 Plus",
    "iPhone10,3": "iPhone X",
    "iPhone10,6": "iPhone X",
    "iPhone11,2": "iPhone XS",
    "iPhone11,4": "iPhone XS Max",
    "iPhone11,6": "iPhone XS Max",
    "iPhone11,8": "iPhone XR",
    "iPhone12,1": "iPhone 11",
    "iPhone12,3": "iPhone 11 Pro",
    "iPhone12,5": "iPhone 11 Pro Max",
    "iPhone12,8": "iPhone SE (2nd generation)",
    "iPhone13,1": "iPhone 12 mini",
    "iPhone13,2": "iPhone 12",
    "iPhone13,3": "iPhone 12 Pro",
    "iPhone13,4": "iPhone 12 Pro Max",
    "iPhone14,4": "iPhone 13 mini",
    "iPhone14,5": "iPhone 13",
    "iPhone14,2": "iPhone 13 Pro",
    "iPhone14,3": "iPhone 13 Pro Max",
    "iPhone14,6": "iPhone SE (3rd generation)",
    "iPhone14,7": "iPhone 14",
    "iPhone14,8": "iPhone 14 Plus",
    "iPhone15,2": "iPhone 14 Pro",
    "iPhone15,3": "iPhone 14 Pro Max",
    "iPhone15,4": "iPhone 15",
    "iPhone15,5": "iPhone 15 Plus",
    "iPhone16,1": "iPhone 15 Pro",
    "iPhone16,2": "iPhone 15 Pro Max"
    ]
    return modelNameList
}

一般名を取得

先ほど取得した内部名と対応リストを使用して一般名(機種名)を取得します。

/// 端末の機種名を取得する
func getDeviceModelName(modelIdentifier: String) -> String {
    return modelNameList[modelIdentifier] ?? ""
}

拡張したUIDeviceクラスを使用する

端末の機種名を取得したいタイミングで下記コードを記載します。

/// 端末の機種名
let modelName: String = UIDevice.current.getDeviceModelName(modelIdentifier: UIDevice.current.modelIdentifier)

print(modelName)
// iPhone 12 Pro

注意点

実装する際には下記に注意する必要があります。

  • 内部名と一般名の対応リストを作成する時はタイポに注意する。
  • 新機種が発売されたタイミングでリストを更新しなければならない。
  • サポート終了機種が追加されたタイミングで不要な機種は削除する。

ソースコード

UIDevice+Extension.swift

extension UIDevice {
    
    var modelNameList: [String: String] {
        let modelNameList: [String: String] = [
        // iPod
        "iPod5,1": "iPod touch (5th generation)",
        "iPod7,1": "iPod touch (6th generation)",
        "iPod9,1": "iPod touch (7th generation)",
        
        // iPad
        "iPad6,11": "iPad (5th generation)",
        "iPad6,12": "iPad (5th generation)",
        "iPad7,5": "iPad (6th generation)",
        "iPad7,6": "iPad (6th generation)",
        "iPad7,11": "iPad (7th generation)",
        "iPad7,12": "iPad (7th generation)",
        "iPad11,6": "iPad (8th generation)",
        "iPad11,7": "iPad (8th generation)",
        "iPad12,1": "iPad (9th generation)",
        "iPad12,2": "iPad (9th generation)",
        "iPad13,18": "iPad (10th generation)",
        "iPad13,19": "iPad (10th generation)",
        
        // iPad Mini
        "iPad5,1": "iPad mini (4th generation)",
        "iPad5,2": "iPad mini (4th generation)",
        "iPad11,1": "iPad mini (5th generation)",
        "iPad11,2": "iPad mini (5th generation)",
        "iPad14,1": "iPad mini (6th generation)",
        "iPad14,2": "iPad mini (6th generation)",
        
        // iPad Pro
        "iPad6,3": "iPad Pro 9.7 Inch",
        "iPad6,4": "iPad Pro 9.7 Inch",
        "iPad7,3": "iPad Pro (10.5-inch)",
        "iPad7,4": "iPad Pro (10.5-inch)",
        "iPad6,7": "iPad Pro (12.9-inch) (1st generation)",
        "iPad6,8": "iPad Pro (12.9-inch) (1st generation)",
        "iPad7,1": "iPad Pro (12.9-inch) (2nd generation)",
        "iPad7,2": "iPad Pro (12.9-inch) (2nd generation)",
        "iPad8,1": "iPad Pro (11-inch) (1st generation)",
        "iPad8,2": "iPad Pro (11-inch) (1st generation)",
        "iPad8,3": "iPad Pro (11-inch) (1st generation)",
        "iPad8,4": "iPad Pro (11-inch) (1st generation)",
        "iPad8,9": "iPad Pro (11-inch) (2nd generation)",
        "iPad8,10": "iPad Pro (11-inch) (2nd generation)",
        "iPad13,4": "iPad Pro (11-inch) (3rd generation)",
        "iPad13,5": "iPad Pro (11-inch) (3rd generation)",
        "iPad13,6": "iPad Pro (11-inch) (3rd generation)",
        "iPad13,7": "iPad Pro (11-inch) (3rd generation)",
        "iPad8,5": "iPad Pro (12.9-inch) (3rd generation)",
        "iPad8,6": "iPad Pro (12.9-inch) (3rd generation)",
        "iPad8,7": "iPad Pro (12.9-inch) (3rd generation)",
        "iPad8,8": "iPad Pro (12.9-inch) (3rd generation)",
        "iPad14,3": "iPad Pro (11-inch) (4th generation)",
        "iPad14,4": "iPad Pro (11-inch) (4th generation)",
        "iPad8,11": "iPad Pro (12.9-inch) (4th generation)",
        "iPad8,12": "iPad Pro (12.9-inch) (4th generation)",
        "iPad13,8": "iPad Pro (12.9-inch) (5th generation)",
        "iPad13,9": "iPad Pro (12.9-inch) (5th generation)",
        "iPad13,10": "iPad Pro (12.9-inch) (5th generation)",
        "iPad13,11": "iPad Pro (12.9-inch) (5th generation)",
        "iPad14,5": "iPad Pro (12.9-inch) (6th generation)",
        "iPad14,6": "iPad Pro (12.9-inch) (6th generation)",
        
        // iPad Air
        "iPad5,3": "iPad Air (2nd generation)",
        "iPad5,4": "iPad Air (2nd generation)",
        "iPad11,3": "iPad Air (3rd generation)",
        "iPad11,4": "iPad Air (3rd generation)",
        "iPad13,1": "iPad Air (4th generation)",
        "iPad13,2": "iPad Air (4th generation)",
        "iPad13,16": "iPad Air (5th generation)",
        "iPad13,17": "iPad Air (5th generation)",
        
        // iPhone
        "iPhone7,1": "iPhone 6 Plus",
        "iPhone7,2": "iPhone 6",
        "iPhone8,1": "iPhone 6s",
        "iPhone8,2": "iPhone 6s Plus",
        "iPhone8,4": "iPhone SE",
        "iPhone9,1": "iPhone 7",
        "iPhone9,3": "iPhone 7",
        "iPhone9,2": "iPhone 7 Plus",
        "iPhone9,4": "iPhone 7 Plus",
        "iPhone10,1": "iPhone 8",
        "iPhone10,4": "iPhone 8",
        "iPhone10,2": "iPhone 8 Plus",
        "iPhone10,5": "iPhone 8 Plus",
        "iPhone10,3": "iPhone X",
        "iPhone10,6": "iPhone X",
        "iPhone11,2": "iPhone XS",
        "iPhone11,4": "iPhone XS Max",
        "iPhone11,6": "iPhone XS Max",
        "iPhone11,8": "iPhone XR",
        "iPhone12,1": "iPhone 11",
        "iPhone12,3": "iPhone 11 Pro",
        "iPhone12,5": "iPhone 11 Pro Max",
        "iPhone12,8": "iPhone SE (2nd generation)",
        "iPhone13,1": "iPhone 12 mini",
        "iPhone13,2": "iPhone 12",
        "iPhone13,3": "iPhone 12 Pro",
        "iPhone13,4": "iPhone 12 Pro Max",
        "iPhone14,4": "iPhone 13 mini",
        "iPhone14,5": "iPhone 13",
        "iPhone14,2": "iPhone 13 Pro",
        "iPhone14,3": "iPhone 13 Pro Max",
        "iPhone14,6": "iPhone SE (3rd generation)",
        "iPhone14,7": "iPhone 14",
        "iPhone14,8": "iPhone 14 Plus",
        "iPhone15,2": "iPhone 14 Pro",
        "iPhone15,3": "iPhone 14 Pro Max",
        "iPhone15,4": "iPhone 15",
        "iPhone15,5": "iPhone 15 Plus",
        "iPhone16,1": "iPhone 15 Pro",
        "iPhone16,2": "iPhone 15 Pro Max"
        ]
        return modelNameList
    }
    
    var modelIdentifier: String {
        var systemInfo: utsname = utsname()
        uname(&systemInfo)
        let machineMirror: Mirror = Mirror(reflecting: systemInfo.machine)
        let identifier: String = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else {
                return identifier
            }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        return identifier
    }
    
    /// 端末の機種名を取得する
    func getDeviceModelName(modelIdentifier: String) -> String {
        return modelNameList[modelIdentifier] ?? ""
    }
}

参考

Discussion