模拟器总有偏差?vphone-cli用Apple官方框架虚拟iPhone。
许多开发者在进行iOS App开发时,都被模拟器“坑”过。界面看起来是对的,但网络行为、硬件传感器,甚至某些系统API的返回值与真机就是不一样。上线前不得不借用实体手机反复测试,既麻烦又容易遗漏边缘场景,结果用户一用就出问题。
实际上,现在有一款开源CLI工具vphone-cli,直接利用Apple自家的Virtualization.framework,能在Mac上启动一个运行iOS 26的虚拟iPhone。这不是模拟,而是真机级别的虚拟机,底层基于苹果的虚拟化技术。它把过去只能依赖实体机验证的测试场景,直接搬到了开发者的桌面上。 我第一次看到它详尽的测试环境列表时,就意识到这工具绝非玩具。

其核心在于绕过了传统模拟器的指令翻译层,直接将iOS固件以虚拟机形式运行在Apple Silicon芯片上。简单理解,就像在Mac上启动一个Windows虚拟机,只不过这次“系统”换成了完整的iOS。开发者再也不需要为了测试一个权限弹窗或低电量场景,四处寻找实体手机了。
这个工具到底解决了模拟器的哪些真实局限?
无论模拟器如何优化,底层始终是Xcode的指令翻译机制。iOS 26中新增的某些硬件加速特性、特定的entitlements(权限文件),或是与安全启动链相关的检查,模拟器根本无法模拟。vphone-cli则不同,它通过Virtualization.framework将整个iOS固件加载为虚拟机,CPU、内存、存储均由宿主机真实分配。理论上,这为App提供了与真机近乎一致的运行环境。
这一点为何重要?因为在跨平台适配或测试企业级MDM配置时,模拟器常常在关键时刻掉链子。例如,某个依赖Secure Enclave(安全区域)的特性,在模拟器中可能返回空值,但在真机上却能正常工作。在vphone-cli的虚拟机环境中,这些行为是真实存在的。
技术细节上,它支持四种渐进式的固件补丁变体,从最轻量的Patchless(仅3个补丁)到最完整的Jailbreak(112个补丁)。每种变体对应不同的启动链阶段和CFW安装流程。Patchless仅绕过AMFI、SSV等基础限制,适合希望保持较高安全性的场景;Jailbreak版则会在首次启动时自动运行安装脚本,完成符号链接、包管理器Sileo、APT以及TrollStore的初始化,直接提供一个可SSH、可安装tweak的完整环境。
我曾以为iPhone虚拟化只能停留在“接近真机”的水平,直到看到这个工具的补丁数量和阶段拆分,才发现Apple的框架其实早已为这类研究级虚拟机预留了可能性,只是之前没人将其流程封装成便捷的CLI工具。
四种固件变体该怎么选,边界条件在哪里?
选择变体本质是在安全性和便利性之间做权衡。
- Patchless变体最保守,仅3个补丁,启动链仅2个阶段,适合仅需验证App基础功能的开发者。它对宿主机SIP/AMFI的要求最低,但某些系统级API仍会因安全检查而受限。
- Regular和Development版分别有41和52个补丁,阶段增加到10和12个,增加了TXM entitlement和调试绕过,调试体验更好。
- Jailbreak版最彻底,112个补丁加14个阶段,首次启动后自动运行
/cores/vphone_jb_setup.sh,日志位于/var/log/vphone_jb_setup.log。完成后即拥有Sileo和TrollStore,安装openssh-server即可SSH登录。
这里需要纠正一个认知误区:我曾以为补丁越多越“危险”。实际使用下来,Jailbreak版在开发阶段反而最省事,因为可以直接修改系统文件、安装tweak来验证行为。而Regular版有时还需要手动处理dropbear的host key生成。社区对此也有争议,有人认为Patchless已足够日常测试,有人则认为JB版才算真正的虚拟机——最终选择取决于你的具体测试需求。
另外,项目README中的测试环境列表值得留意,全部基于Mac16,12 26.3主机,iPhone型号从17,3_26.1测到17,3_26.3.1,CloudOS也同步升级。这些不整齐的数字恰恰说明项目已在多种真实硬件和系统版本上经过了反复验证。
环境准备和依赖安装的实际门槛
宿主机必须是macOS 15+(Sequoia),因为PV=3虚拟化特性从此版本才开始稳定。配置SIP/AMFI是第一道必须跨越的门槛。有两种主要做法:一是彻底关闭SIP并添加amfi_get_out_of_my_way=1引导参数;二是保留大部分SIP,仅通过amfidont或amfree等工具针对vphone-cli的路径进行放行。
我本人更倾向于第二种方案,因为它对系统的改动最小。安装amfidont后,只需执行sudo amfidont --path [你的vphone目录]。项目还提供了make amfidont_allow_vphone命令来帮助计算CDHash。对于选择了此路径的Patchless变体,还需额外添加-S参数。
依赖安装不复杂,但步骤必须完整。需要通过Homebrew安装aria2、wget、gnu-tar、openssl@3、ldid-procursus、sshpass、keystone、libusb、ipsw等一系列工具。克隆项目时必须使用--recurse-submodules参数,否则后续的fw_prepare会因缺少资源而失败。整个过程首次运行大约需要40分钟,主要耗时在下载IPSW固件文件。
操作指南:从零启动虚拟iPhone
目标是用一条命令完成从依赖安装到首次启动的全流程。
# 这行命令一次性搞定setup_tools、build、vm_new、fw_prepare、patch和cfw_install
# 可以通过参数指定使用的变体
make setup_machine
# 或者指定变体:LESS=1 对应Patchless;DEV=1 对应Development;JB=1 对应Jailbreak
完成后,虚拟机目录会被创建,config.plist中已记录CPU、内存、磁盘大小等默认配置。默认配置通常够用,但你可以自定义:
# 自定义配置示例
make vm_new CPU=16 MEMORY=16384 DISK_SIZE=128
⚠️ 注意:restore流程必须开启两个终端。第一个终端保持运行make boot_dfu;第二个终端执行make restore_get_shsh获取SHSH blob,然后执行make restore刷入固件。此过程不可中断,否则需要重来。
固件打补丁后,停止DFU,再次运行make boot_dfu,然后在第三个终端使用usbmux进行端口转发:
# 第三个终端需要一直保持运行
python3 -m pymobiledevice3 usbmux forward 2222 22
之后,在第二个终端执行make cfw_install(Jailbreak版使用cfw_install_jb)。安装完成后,执行make boot启动虚拟机。
首次启动Jailbreak版时,虚拟机会出现Sileo和TrollStore。若要进行SSH连接,需先在控制台执行那几行export PATH和dropbearkey命令来生成host key,否则连接会立刻断开,这一步容易出错。
后续的每次启动就简单多了:
make boot
# 另外开一个终端转发usbmux
python3 -m pymobiledevice3 usbmux forward 2222 22
完成后,你将看到一个完整的iOS桌面窗口,neofetch能正常显示系统信息,内存占用也与配置一致。整个流程最容易出问题的地方是SIP配置不到位,或者克隆项目时没有拉取完整的子模块。
我原本以为这类虚拟机资源消耗会很大,实际在M系列Mac上运行却感觉相当轻量——当然这只是个人感受,具体表现还取决于你分配的CPU和内存资源。
最后不得不承认,我以前对苹果虚拟化能力的判断过于保守了。vphone-cli将原本只在研究实验室里折腾的技术,变成了普通开发者也能在本地运行的CLI命令。未来再测试iOS 26的边缘特性时,终于可以告别四处借真机的烦恼了。
你是否尝试过类似的工具?在第一次配置SIP时,你选择了直接禁用还是更精细的路径放行方案?欢迎在云栈社区的技术板块交流你的实践经验。