本期周报最有价值的部分,是把三个「让应用离开原生系统」的项目放在一起比较,而它们的实现路线完全不同,正好构成一张技术选型图。
路线一:重写框架,而不是模拟硬件
Cutefish 想让未经修改的 macOS 应用跑在 Linux 上。它没有走虚拟机或指令模拟,而是做了一层叫 Reef 的兼容层:自己实现 Mach-O 加载器、Objective-C Runtime,再逐个把 Foundation、AppKit、Core Graphics、SwiftUI 这些框架的行为复刻出来。选这条路的代价很直接——框架语义要靠人一点点对齐,作者自己也承认了性能问题:局部状态变化时会重建整棵视图树,滚动过程中存在重复绘制。收益是不需要 CPU 模拟,跑的是原生指令,速度上限比全虚拟化高得多。这也解释了为什么它只能先支持一部分应用:Swift 生态里大量代码默认苹果框架一定存在,兼容层漏掉一个 API,应用就崩在启动路径上。
路线二:不模拟设备,直接跑模拟器产物
SimRun 走的是另一条捷径。Xcode 为 iOS 模拟器编译出来的产物本身就是针对宿主架构的,SimRun 直接把它放进 macOS 的独立窗口里运行,既不用启动完整模拟设备,也不用给应用加 Mac Catalyst 适配。对反复调 SwiftUI、UIKit 界面的人,这意味着改一版就能立刻看效果,省掉模拟器启动的那几十秒。它还提供命令行、截图、视图层级检查,以及实验性的 JavaScript 自动化接口,并支持无窗口运行——这几项拼起来,实际上是把 App 变成了可被脚本和 AI Agent 驱动的对象:Agent 可以启动应用、截图、读取层级、点击,形成闭环。限制也很硬:必须 Apple 芯片、必须装 Xcode 与模拟器运行时,还要关闭 SIP,所以它只能是开发机上的工具,进不了普通用户桌面。
路线三:整套系统藏在后台
Mac Android Subsystem 的目标是让 Android 应用「看起来像 Mac 应用」:双击 APK 安装,每个应用独立窗口和 Dock 图标,Spotlight 能搜到,⌘-Tab 能切,通知中心与双向剪贴板都打通。它的实现最重:用 LineageOS、QEMU 加 Apple Hypervisor Framework 在后台跑一个完整 Android 环境,再用 scrcpy 把画面投到独立窗口。换句话说,窗口是真的,系统也是真的,只是被藏起来了。代价同样明显——早期预发布、只支持 Apple Silicon 与 macOS 15 以上、不带 Google Play 与 GMS,等于把最难适配的那批应用排除在外。
三条路的取舍
把三者叠起来看,判据其实只有一条:**你愿意为「原生速度」付出多少适配成本,又愿意为「兼容广度」付出多少资源开销**。兼容层最轻、最快,但覆盖面上限取决于复刻了多少框架;模拟器产物直跑最省事,但前提是产物本来就为宿主架构编译;整机虚拟化覆盖最广,代价是内存、启动时间与系统版本门槛。周报里那句判断值得记住:竞争重点正从「我独占哪些应用」转向「我能多自然地接住别人的应用」。
顺带几篇值得看的
iOS 触觉反馈那篇把 UIKit Feedback Generator、SwiftUI 的 sensoryFeedback 与 Core Haptics 三套 API 放在一起,还配了能在真机上对比触感并直接导出代码的工具——触觉没法在模拟器里验证,这类工具比文档有用。AVFoundation 音频闪避那篇讲的是非对称渐变:背景音乐快速压低、缓慢恢复,再用 Generation Token 加延迟窗口过滤语音自然停顿造成的抖动,思路可以迁移到任何「异步事件要收敛成稳定状态」的场景。NSHostingView 那篇记录了一个反直觉的 bug:外层 Representable 已进入拆除流程,嵌套的 Hosting View 仍可能在后续布局事务里重建子视图,把已经移交 Canvas 的终端 Surface 又抢回去——排查方式是构建最小复现、反复实验建立证据链,而不是看到症状消失就收工。还有一篇把实时语音接入抽象成统一 JSON 工具契约,25 种应用操作在 iOS、Android、Cloudflare Worker 三端共用,写入后留 8 秒撤销窗口,破坏性操作强制确认,这套权限分级值得抄。
小结
三个项目说明跨系统运行已经过了「能跑就行」的阶段,开始拼窗口、Dock、剪贴板、通知这些细节的融合度;而 Coding Agent 的介入,让个人开发者也有能力做过去只有团队才做得动的兼容层。真要选型,先问自己是要速度、要覆盖面,还是要零改造,再决定站在哪条路上。
内容与图片版权归原作者所有 · 原文: https://fatbobman.com/zh/weekly/issue-159/