如何在iOS模拟器中模拟不同外形规格的设备?
搞定iOS模拟器下的设备型号判断难题
我太懂你这种处境了——想覆盖不同iOS设备的测试,但不可能把所有真机都买齐,模拟器绝对是救星,但之前用switch语句判断设备型号的逻辑到了模拟器就拉胯,毕竟模拟器本身的设备标识和它模拟的真机完全不是一回事,确实头疼。
先猜猜你之前大概是这么写的(基于sysctlbyname拿设备型号的常规操作):
func getDeviceModel() -> String { var systemInfo = utsname() uname(&systemInfo) let machineMirror = Mirror(reflecting: systemInfo.machine) let identifier = machineMirror.children.reduce("") { identifier, element in guard let value = element.value as? Int8, value != 0 else { return identifier } return identifier + String(UnicodeScalar(UInt8(value))) } switch identifier { case "iPhone14,2": return "iPhone 13 Pro" case "iPad13,1": return "iPad Air (4th gen)" // 一堆真机型号的case... case "x86_64", "arm64": return "Simulator" default: return identifier } }
这种写法在真机上跑没问题,但模拟器只会返回x86_64(Intel Mac)或arm64(Apple Silicon Mac),根本没法知道你当前模拟的是哪款iPhone/iPad,测试不同设备布局的时候特别不方便。
给你个完美解决方案:获取模拟器模拟的真机型号
其实苹果在模拟器环境里悄悄留了个后门——一个叫SIMULATOR_MODEL_IDENTIFIER的环境变量,直接能拿到当前模拟设备的型号标识,和真机上的完全一致!我们可以把这个逻辑整合进去:
import UIKit func getCurrentDeviceIdentifier() -> String { // 先判断是不是模拟器环境 #if targetEnvironment(simulator) // 从环境变量里捞模拟的真机型号 if let simModelID = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] { return simModelID } return "Unknown Simulator" #else // 真机环境下的常规型号获取逻辑 var systemInfo = utsname() uname(&systemInfo) let machineMirror = Mirror(reflecting: systemInfo.machine) let identifier = machineMirror.children.reduce("") { id, element in guard let val = element.value as? Int8, val != 0 else { return id } return id + String(UnicodeScalar(UInt8(val))) } return identifier #endif } // 然后用统一的switch来映射型号到设备名称 func getDeviceName() -> String { let deviceID = getCurrentDeviceIdentifier() switch deviceID { case "iPhone14,2": return "iPhone 13 Pro" case "iPhone15,3": return "iPhone 15 Pro" case "iPad13,1": return "iPad Air (4th Generation)" case "iPad17,1": return "iPad Pro 12.9-inch (6th Gen)" // 这里可以继续补充所有你需要支持的设备型号 default: return deviceID } }
为啥这方法好使?
- 模拟器里,
SIMULATOR_MODEL_IDENTIFIER会直接返回你当前模拟的设备型号(比如你选了iPhone 15 Pro模拟,就返回iPhone15,3),和真机上拿到的标识一模一样,这样你的switch语句不用单独写模拟器的case,一套逻辑通吃真机和模拟器。 - 用
#if targetEnvironment(simulator)做编译条件判断,真机环境下根本不会执行模拟器相关的代码,完全不影响性能。
额外小tip
如果你需要更新设备型号对应关系,苹果官方文档里有完整的列表,也可以找一些维护及时的开源设备型号库来批量导入,省得自己一个个加,毕竟苹果每年都出新机子嘛。
这样改完之后,不管你在真机还是模拟器上跑,都能准确识别出对应的设备型号,测试不同布局的时候就顺畅多啦~
内容的提问来源于stack exchange,提问作者iKK




