Issue #159

当应用不再属于特定操作系统

Cover for Weekly Issue 159

本期周报中有三个颇有意思的项目:Cutefish、SimRun 和 Mac Android Subsystem。它们采用了不同的技术路线,有的通过兼容 API 和框架来提供运行环境,有的直接运行针对模拟器构建的应用,还有的将完整的虚拟系统隐藏在后台。但它们都在尝试做同一件事:让原本属于不同操作系统的应用,能够自然地出现在同一张桌面上。

跨平台运行当然不是什么新鲜事。从 Wine 到各种虚拟机、模拟器,开发者已经为此努力了几十年。不过,开发者不再仅仅满足于让应用「能够运行」,而是希望用户不必在意应用原本属于哪个平台。独立窗口、Dock、Spotlight、剪贴板、系统通知……当这些能力逐渐融合,运行环境便开始退居幕后,应用与宿主系统之间的边界也随之变得模糊。

AI 也正在加快这一进程。过去,无论是逆向分析系统 API、复刻框架行为,还是移植复杂的应用运行环境,都需要投入大量时间和人力。如今,Coding Agent 可以承担其中相当一部分探索、实现与验证工作,让个人开发者和小团队也有机会尝试过去难以负担的项目,打破这些边界的成本正在下降。

一个问题也逐渐呈现:如果应用不再那么依赖特定的操作系统,我们未来会如何选择硬件?过去,一款独占应用、一个不可替代的软件生态,可能就足以决定用户购买哪台设备。而当越来越多的应用可以跨越系统边界,硬件本身的设计、性能、价格、系统体验,甚至品牌忠诚度和个人喜好,或许会在购买决策中占据更大的分量。

有趣的是,这未必意味着平台之间的竞争会减弱。恰恰相反,谁能让来自不同生态的应用更自然、更稳定地融入自己的系统,谁就可能拥有新的吸引力。竞争的重点或许会逐渐从「我独占哪些应用」,转向「我能为这些应用提供怎样的使用体验」。

也许未来选择一台设备时,我们不必首先考虑它能运行哪些应用,而是可以更多地考虑,我们究竟喜欢怎样使用它。

近期推荐

在 Linux 上运行原生 Mac 应用 (Running Mac apps on Cutefish)

在 Linux 上运行 Windows 应用已经稀松平常,但让未经修改的 macOS 应用直接运行在 Linux 上,听起来则有些不可思议。⁠Cutefish 正在尝试实现这一目标。它没有采用虚拟机或指令模拟,而是通过一套名为 Reef 的兼容层,重新实现 Mach-O 加载器、Objective-C Runtime,以及 Foundation、AppKit、Core Graphics、SwiftUI 等框架,让 Mac 应用能够直接在 Linux 桌面环境中运行。本文不仅展示了当前的兼容成果,还坦诚讨论了性能问题:例如,局部状态变化时重建整棵视图树,以及滚动过程中的重复绘制。

Swift 正在不断拓展其跨平台能力,但大量使用 Swift 开发的应用仍然深度依赖苹果生态中的各类框架,难以直接移植到其他平台。Reef 则提供了另一种可能:不改变现有应用,而是让其他平台具备运行这些应用的能力。


iOS 触觉反馈完整指南 (Every iOS Haptic Pattern, With Code)

iOS 提供了多种触觉反馈 API,但不同机制之间的能力与适用场景并不完全相同。⁠Alok Singh 汇总了 UIKit 的 Feedback Generator、SwiftUI 的 .sensoryFeedback,以及 Core Haptics 的使用方式,并提供了涵盖系统预设反馈、自定义触觉模式、动态参数和 AHAP 文件的代码示例。

由于触觉反馈无法通过模拟器体验,Alok 还开发了 Haptics Explorer,让开发者能够直接在 iPhone 上比较不同触觉模式,并获取相应的 Swift 代码。


AVFoundation 音频闪避与平滑混音工程实践

在背景音乐与语音旁白需要同时播放的场景中,如果只是在语音开始和结束时直接调整背景音乐音量,很容易出现突兀的音量变化,甚至在语音自然停顿时产生反复起伏的「抽吸效应」。Snow Wu 介绍了如何通过非对称音量渐变,让背景音乐快速降低、缓慢恢复,并利用 Generation Token 与延迟窗口避免语音自然停顿引起的频繁音量变化。相较于代码,本文给出的设计思路更值得借鉴:音频状态变化需要符合人的听觉感知,而异步事件需要经过协调,才能转换成稳定的播放状态。


被拆掉的 NSHostingView 还会再建一次 View

在 SwiftUI 与 AppKit 混合开发中,NSViewRepresentable 的 dismantleNSView 已经被调用,是否意味着内部的视图不会再被创建?⁠王巍(Onevcat) 发现了一个反直觉的现象:外层 Representable 已经进入拆除流程,嵌套其中的 NSHostingView 却仍然可能在后续布局事务中重新调用子视图的 makeNSView,导致原本已经转移到 Canvas 的终端 Surface 被一个不可见的宿主重新夺走。

文章完整记录了从版本二分、发现 .overlay 角标与问题复现的隐蔽关联,到构建最小复现并确认嵌套 Hosting View 生命周期问题的过程。最终,作者不仅在 dismantleNSView 中主动移除内部的 NSHostingView,还改进了共享 Surface 的所有权规则,使其能够从不再显示的宿主中恢复。

本文的另一层价值在于它展示了 AI Agent 在复杂调试任务中的一种有效使用方式。Agent 不只是修改代码,而是通过反复实验建立证据链;开发者则在关键节点追问原因,避免在症状消失后过早结束调查。


一套工具契约,接入多种实时语音模型 (How I built Live Voice: one tool contract, six realtime voice providers)

在应用中接入实时语音 AI,难点不仅在于处理音频流和模型响应,还在于如何让模型安全、可靠地操作应用。⁠Apoorv Darshan 分享了他为开源应用 Fud AI(iOS 端基于 SwiftUI,Android 端基于 Compose)开发 Live Voice 功能的实践:通过统一的 JSON 工具契约定义 25 种应用操作,让 iOS、Android 和 Cloudflare Worker 遵循相同的接口,并使用独立的 Adapter 处理 Gemini Live、OpenAI Realtime、xAI 和 Qwen 等服务在音频格式、工具调用和视觉输入方面的差异。

Apoorv 将工具分为读取、导航、写入和破坏性操作,写入后提供 8 秒撤销窗口,破坏性操作则必须经过用户确认;默认设置下,普通写入同样需要确认。


当开发工具不再围绕编辑器 (Why Tuist should build the harness on top of compute)

几个月前,Tuist 联合创始人 ⁠Pedro Piñera 还在 ⁠The remote development mirage 中对全面转向远程开发的趋势持保留态度。但随着对 Amp 的深入使用,他开始重新审视这一判断。当 Coding Agent 可以独立完成越来越多的编码任务,开发者或许不再需要始终坐在电脑前,面对编辑器完成工作。移动设备、语音交互,甚至 Live Activities,都可能成为新的开发入口。

在本文中,Pedro 提出,随着 Compute 逐渐商品化,Tuist 应该将差异化竞争力建立在 Compute 之上的 Coding Harness 与开发体验中。他此前在 ⁠The automation graph agents need 中讨论过如何让 Agent 根据代码变更确定后续的测试与验证任务,而如今,他希望将这些能力与远程计算资源结合,让开发工具从被动执行命令,转向主动理解项目、组织任务并验证结果。

当代码编辑不再是开发活动的中心,我们需要的究竟是一款更智能的 IDE,还是一种全新的开发工作环境?


还没开始对话,Claude Code 就占用了 39.6k Token

Claude Code 的上下文开销究竟来自哪里?通过 /context all 指令,可以查看尚未输入任何提示词时的初始上下文占用。除了系统提示词和工具定义,CLAUDE.md、Rules、Skills 和自定义 Agents 也可能占据相当大的比例,而采用延迟加载的 MCP 工具并不计入初始占用。

Hao Liu 介绍了如何利用 /skill-doctor 和 /doctor prompt-audit 检查不常使用的 Skills、重复规则及过时指令,并提出按文件路径加载规则、精简 CLAUDE.md 等优化方法。作者也提醒读者,上下文占用并不等于每轮请求的实际费用,Prompt Caching 能够降低重复内容的计费成本,与其凭印象精简配置,不如先测量自己的环境,再决定哪些内容真正值得清理。

工具

SimRun:让 iOS 应用在独立的 Mac 窗口中运行

由 ⁠Cyandev 开发的 SimRun 是一个颇有意思的开源实验项目:无需启动完整的模拟设备,也无需为应用增加 Mac Catalyst 适配,使用者可以直接在 macOS 上以独立窗口运行 Xcode 为 iOS 模拟器编译的应用。对于需要反复调整 SwiftUI、UIKit 界面的开发者,这提供了另一种开发辅助方式。

项目还提供命令行、截图、视图层级检查,以及实验性的 JavaScript 自动化接口,并支持在不显示窗口的情况下运行应用,方便编写检查脚本或让 AI 编程代理操作应用。需要注意,SimRun 依赖 Apple 芯片 Mac、Xcode 与模拟器运行时,并要求关闭系统完整性保护(SIP)。


Mac Android Subsystem:让 Android 应用融入 Mac 桌面

与上面的项目有些神似,由 ⁠Harkhowalia 开发的 Mac Android Subsystem(MAS)尝试让 Android 应用拥有接近 Mac 应用的使用方式:双击 APK 即可安装,每个应用都有独立窗口和 Dock 图标,能够通过 Spotlight 搜索、使用 ⌘-Tab 切换,还支持通知中心和双向剪贴板。

MAS 并不是直接运行 Android 应用,而是基于 LineageOS、QEMU 和 Apple Hypervisor Framework,在后台运行完整的 Android 环境,再通过 scrcpy 将应用画面呈现到独立的 Mac 窗口中。目前项目仍处于早期预发布阶段,要求 Apple Silicon Mac 和 macOS 15 或更新版本,不包含 Google Play 商店及 Google 服务。

相关周报

订阅 Fatbobman 周报

每周精选 Swift 与 SwiftUI 开发技巧,加入众多开发者的行列。

立即订阅