← 全部日志
2026-08-28

在 Windows 上造一个自包含的 Mac 应用

节律引擎要搬到 Mac 上,但开发环境只有 Windows。我们从 Windows 上交叉造出了一个完全自包含、双击就能运行的 macOS 应用。

节律引擎是我们给自己写的一套提醒系统。它决定一天里的每个时段该做什么,到点响铃、语音播报、推送到手机;同一个提醒重复触发时,会折叠计数,而不是弹出一堆窗口。它已经在我们的 Windows 电脑上每天运行了半年,里面有 26 条真实的提醒。

后来我们也开始在 Mac 上工作,节律不能断。于是需要一个 Mac 版。

难点在于:开发环境只有 Windows。

常规的路走不通

节律引擎是用 Python 写的。在 Windows 上,我们用打包工具把它做成一个可以直接运行的程序。但这类打包工具不能交叉编译:想要一个 Mac 程序,通常就得在 Mac 上打包。

换个角度看 .app

我们换了个角度:一个 macOS 应用,本质上只是一个按约定结构组织的文件夹。只要文件夹的结构对,里面放的东西在 Mac 上能运行,它就是一个应用。

所以我们不在 Windows 上”编译”Mac 程序,而是在 Windows 上组装它:

  • 把一个可以整体搬家、为 macOS 编译好的独立 Python 运行环境,直接放进应用包里;
  • 把节律引擎的代码和资源放进去;
  • 为 Mac 做了 18 处平台适配:菜单栏图标、深色模式配色、中文菜单等等。

这样,Mac 上不需要预先安装任何东西,双击就能运行。

不验证,就是交付一个死包

在 Windows 上组装 Mac 应用,最大的风险是:你没法在打包的机器上试运行它。

所以打包之前,我们先做静态检查:确认应用包里每一个 Mac 二进制文件所依赖的库,都指向应用包内部的相对路径,而不是某台开发机上的绝对路径。只要有一处指错,这个包拿到别的 Mac 上就打不开。

最终的自包含检查一共 33 项,全部通过之后才交付。

两个只有到了 Mac 上才会暴露的坑

  • 双击没有任何反应。 在 Windows 上压缩的文件,不会带上 Unix 系统的可执行权限。解压到 Mac 上,程序的启动文件没有执行权限,双击之后什么也不发生,也没有任何报错。
  • 换新版本就打不开。 macOS 会给从网上下载的文件打上一个隔离标记。如果用”首次运行时留一个标记文件”的办法来判断是否已经处理过这个标记,每次换新版本都会出问题。

还有一个没有绕过去的限制:这个应用没有经过苹果的开发者签名,第一次打开时需要按住 Control 键点击。对一个只给自己用的工具来说,这个代价可以接受。

为什么值得写下来

它是一个很小的工具,Mac 版也只有我们自己在用。但这次移植让我们确认了一件事:当常规的路走不通时,先回到事物最基本的结构上去想——一个应用到底是什么,而不是”这个工具支不支持”。