Dev Guide / 2026 ・ No.01
Mac 应用开发入门路线图
从零开始,到能把桌面实用小工具分发给别人
发布
全局地图 ── 8 个步骤
朱色框是 Mac 特有的部分。时间按每天约 1 小时估算,仅供参考
“想自己做一个在 Mac 上用的小工具。”
有这个想法的人,该从哪里学起、按什么顺序学,这里做了整理。
每一步要掌握的知识,以及动手做的练习作品,也一并介绍。
做什么,用什么做
目标是“能从菜单栏或快捷键调出来的实用小工具”。工具选 Swift 与 SwiftUI,不够的地方再补上 AppKit。不要一上来就做大作品,每一步完整做出一个小作品,才是捷径。
本文所说的“实用小工具”,指的是这样一类应用:
- 常驻菜单栏 ── 点一下就能用的计时器、剪贴板历史、便签
- 批量处理文件 ── 批量重命名、压缩图片、格式转换
- 用快捷键调出 ── 启动器、常用语输入,不打断手头的工作
为什么选 Swift 与 SwiftUI
Mac 应用也可以用 Electron、Tauri、Flutter 等技术来做,好处是能用上 Web 的知识,还能同时出 Windows 版。但如果只说常驻后台的小工具,Apple 原生的 Swift 与 SwiftUI 更有优势。
- 轻 ── 常驻也不怎么占内存、耗电
- 直接沿用 Mac 的规矩 ── 菜单栏、设置窗口、快捷键、深色模式,乃至 macOS 26 起的新设计(Liquid Glass),标准组件就能搞定
- 直通系统功能 ── 文件、剪贴板、通知、登录时启动等,都有官方 API
- 能从一手资料学 ── Apple 的官方教程和文档,本身就是教材
SwiftUI 是一种“声明界面长什么样”的写法,也是 Apple 当前最重视的 UI 框架。Mac 上还有历史悠久的 AppKit,SwiftUI 够不着的细节用 AppKit 补,是现在的标准做法。一开始只用 SwiftUI 就足够了。
路线图全貌
| STEP | 学什么 | 参考时间 | 练习作品 |
|---|---|---|---|
| 0 准备 | Mac 与 Xcode、Git | 1 天 | 运行一个空应用 |
| 1 Swift 基础 | 变量・类型・Optional・函数・结构体 | 2–3 周 | 命令行单位换算 |
| 2 SwiftUI 基础 | View・状态・布局・列表 | 3–4 周 | 把单位换算做成窗口 |
| 3 Mac 特性 | Scene・菜单栏・设置窗口・快捷键 | 2–3 周 | 菜单栏计时器 |
| 4 数据与存储 | 设置・JSON・文件・SwiftData | 2 周 | 常用语(片段)本 |
| 5 系统集成 | 沙盒・权限・登录启动・剪贴板 | 2–3 周 | 剪贴板历史 |
| 6 质量打磨 | 调试・测试・无障碍・多语言 | 并行 | 打磨已有作品 |
| 7 发布 | 签名・公证・App Store | 1–2 周 | 请朋友在他的 Mac 上打开 |
时间只是参考。如果是第一次学编程,STEP 1 和 2 花上两倍时间也很正常。这一步的练习作品能跑起来,就进入下一步——以此为信号即可。
STEP 0 ── 准备与 Xcode
有一台 Mac 和 Xcode(免费)就能开始。收费的 Apple Developer Program,到分发给别人(STEP 7)之前都用不着。
需要准备的东西
| Mac | Apple 芯片(M1 及以后)。2026 年 9 月发布的 Xcode 27 只能在 Apple 芯片的 Mac 上运行,且需要 macOS Tahoe 26.6 或更高版本 |
|---|---|
| 内存・空间 | 内存 16GB 以上、可用空间几十 GB 会比较安心(Xcode 及相关文件体积很大) |
| Xcode | 在 Mac App Store 免费获取。写代码、做界面、运行、发布,全靠它一个 |
| Apple 账户 | 平时用的就行。在 Xcode 的设置里登录 |
| Git | 管理修改历史。Xcode 已内置。有 GitHub 账号会更方便 |
手上是 Intel 的 Mac,最多能用到上一代的 Xcode 26。如果准备新买,只选 Apple 芯片。
认识 Xcode 的界面
Xcode 窗口(示意图)
对实际界面做了简化。各个区域都可以显示或隐藏
打开 Xcode,从 File › New › Project… 选择 macOS › App,就会生成一个新应用的模板。Interface 选 SwiftUI,Language 保持 Swift 即可。按 ⌘R(或左上角的 ▶)运行,什么都不写也会打开一个显示“Hello, world!”的窗口。这就是 STEP 0 的终点。
- 在左边选文件,在中间写,在右边的画布看结果。这个往返就是基本功
- 下方的调试区会显示 print() 的输出和错误。看到红色错误别怕,先把全文读一遍,养成习惯
怎样和 AI 助手相处
Xcode 内置了编程用的 AI。到了 Xcode 27,它能以“智能体”的方式工作:先定计划再写代码,并通过构建和预览检查结果。很方便,但学习阶段,与其“让它写”,不如“让它讲”,更能长本事。问它“这个错误是什么意思?”“这一行在做什么?”,对它给出的代码逐行阅读,不懂的词去官方文档核实。
STEP 1 ── Swift 基础
做界面之前,先熟悉Swift 这门语言本身。跳过这一步,SwiftUI 的代码看起来就会像“咒语”。
要掌握的知识
- 常量与变量(let / var)── 默认用 let,只有需要改的才用 var
- 类型与类型推断 ── Int、Double、String、Bool。不写类型,Swift 也能推断
- Optional(?)── 用类型表达“可能没有值”,用 if let / guard let 安全取出。这是 Swift 的第一个难关
- 集合 ── 数组(Array)、字典(Dictionary)、集合(Set)
- 控制流 ── if、switch、for-in、while
- 函数与闭包 ── 参数与返回值。“当场传进去的小函数”就是闭包,SwiftUI 的按钮就靠它工作
- 结构体与类 ── struct 是值类型(会被复制),class 是引用类型(会被共享)。SwiftUI 里 struct 是主角
- 枚举(enum)── 表示种类或状态,常与 switch 搭配
- 协议 ── “我具备这个能力”的约定。View 和 Codable 都是协议
- 错误处理 ── throws / try / do-catch。文件操作一定会用到
- 异步处理入门 ── async / await,“等待耗时操作”的写法
Optional 是一开始最容易困惑的地方。String? 表示“字符串,或者什么都没有”。它的作用是在运行之前,就挡住“不小心用了可能不存在的值”这类事故。
并发只需要“入门”
从 Swift 6 起,编译器会严格检查多个任务同时运行时的安全性,一开始可能会被陌生的警告吓到。不过,用 Xcode 26 及以后版本新建的项目,默认让代码运行在主线程(MainActor)上,初学者不容易撞上这堵墙。STEP 1 能读懂 async / await 就够了。
教材
- The Swift Programming Language(官方・英文)── 语言的官方指南。先通读开头的“A Swift Tour”,其余当字典查
- Xcode 的 Playground ── 写几行就能马上看到结果,适合确认语法
- 中文资料 ── 社区有官方指南的中文译本,可作辅助。但版本往往落后于原文,遇到出入以原文为准
练习作品:命令行单位换算
在 Xcode 里选择 macOS › Command Line Tool,可以做一个没有界面的程序。试着用 enum、switch 和函数,写“厘米换英寸”“摄氏换华氏”之类的换算。读取键盘输入的 readLine() 返回的是 Optional。想一想如果输入的不是数字怎么办?,Optional 的意义就真正明白了。
STEP 2 ── SwiftUI 基础
SwiftUI 不直接改写界面。先声明“状态(数据)是这样时,界面就是那样”,改变状态后,SwiftUI 会重新绘制界面。习惯这种思路,就是 STEP 2 的目标。
SwiftUI 的思路 ── 状态决定界面
按钮不改文字,只改状态,剩下的交给 SwiftUI 重绘
加在 count 上的 @State,意思是“这个值一变就重绘界面”。按钮只做 count += 1,哪里都没有改写显示的代码,数字却会 1、2、3 地涨上去。
要掌握的知识
- View 与修饰符 ── 给 Text、Button 等组件链式加上 .font()、.padding() 来调整外观。顺序不同,结果不同,要留意
- 布局 ── VStack(纵向)、HStack(横向)、ZStack(叠放)、Spacer、Grid
- 常用组件 ── Text、Image(SF Symbols 图标)、Button、Toggle、TextField、Picker、Slider
- 列表 ── 用 List 和 ForEach 把数组直接变成行。用来区分各行的 Identifiable 也在这里学
- 状态放在哪 ── 只在本界面用就用 @State;交给子界面去改就用 @Binding;多个界面共享的数据,整理进 @Observable 类
- 界面切换 ── Mac 上常用带侧边栏的 NavigationSplitView
- 预览 ── 写上 #Preview,不运行也能在画布上看到界面
看教材先看“是哪一年的”
一搜索,Apple 的“SwiftUI Tutorials”往往排在前面。但这个页面现在写着“不再展示当前 SwiftUI 与 Xcode 的做法”,并引导大家去看新的 Develop in Swift Tutorials。SwiftUI 的写法每年都在小幅变化,无论文章还是视频,都要养成先确认发布日期和对应 Xcode 版本的习惯。
Develop in Swift 是官方教材,从 Xcode 的用法到 SwiftUI、数据存储(SwiftData)、测试、发布,边动手边按顺序学。题材以 iPhone 应用为主,但 SwiftUI 的思路和写法在 Mac 上几乎一样。先把 SwiftUI 的章节学完,Mac 特有的部分在下一步 STEP 3 补上。
练习作品:把单位换算做成窗口
给 STEP 1 的单位换算加上界面:在 TextField 输入数字,用 Picker 选单位,结果的 Text 当场变化。计算部分应该能直接复用 STEP 1 的代码。把界面和计算分到不同文件里,之后写测试会轻松很多。
STEP 3 ── Mac 特性
把 iPhone 应用放大,并不会变成 Mac 应用。菜单栏、多个窗口、设置窗口、键盘快捷键——掌握 Mac 用户默认期待的这些规矩。做小工具,真正的主场从这里开始。
Mac 应用的骨架 ── App 与 Scene
去掉 WindowGroup、只留 MenuBarExtra,就成了只在菜单栏里的应用
要掌握的知识
- App 与 Scene ── 在应用入口(@main 的 App)里,并列窗口等“场景”
- WindowGroup 与 Window ── 同类窗口能开多个的是 WindowGroup,只有一个的专用窗口是 Window
- Settings ── 只要写上,应用菜单里就会出现“设置…”(⌘ ,)
- MenuBarExtra ── 常驻屏幕右上角菜单栏的图标,macOS 13 起可用。设为 .menuBarExtraStyle(.window) 可以弹出类似气泡的小窗口
- 不在 Dock 显示 ── 把 Info.plist 的 LSUIElement 设为 YES,就不会出现在 Dock 和应用切换器里。菜单栏工具的标配
- 菜单与快捷键 ── 用 .commands 往顶部菜单加项目,用 .keyboardShortcut 分配按键
- 工具栏与侧边栏 ── .toolbar 与 NavigationSplitView。窗口初始大小用 .defaultSize 决定
- 拖放与选择文件 ── 从访达拖入文件(.dropDestination),用“打开”面板选择(.fileImporter)
- 与 AppKit 衔接 ── SwiftUI 没有的功能用 AppKit:剪贴板的 NSPasteboard、打开应用和文件的 NSWorkspace 等。还可以用 NSViewRepresentable 把 AppKit 组件嵌进 SwiftUI
就这么几行,菜单栏里会出现一个时钟图标,选“Copy timestamp”,当前日期时间就进了剪贴板。NSPasteboard 是 AppKit 的组件,但在 Mac 上可以直接从 SwiftUI 调用。因为这个应用没有窗口,退出按钮也要自己放。
了解 Mac 的规矩
Apple 的 Human Interface Guidelines(HIG)整理了 Mac 应用应有的行为:菜单的排列、快捷键惯例(⌘ , 打开设置、⌘ W 关闭、⌘ Q 退出)、窗口的处理。按标准的方式用标准组件,外观和操作自然就有 Mac 味。macOS 26 起的新设计(Liquid Glass),标准组件只要用新 SDK 重新构建就会体现出来。
练习作品:常驻菜单栏的计时器
做一个 25 分钟工作、5 分钟休息循环的番茄钟。在菜单栏显示剩余时间,点击开始和停止;再用设置窗口(Settings)改时长,STEP 3 的要素就基本齐了。
STEP 4 ── 数据与存储
工具要能“接着上次用”才算好用。学习把设置、用户数据、用户选择的文件,各自存到合适的地方。
| 要保存的东西 | 用什么 | 例子 |
|---|---|---|
| 小的设置值 | @AppStorage(UserDefaults) | 显示格式、功能开关 |
| 成块的数据 | Codable + JSON 文件 | 常用语列表 |
| 大量记录的检索与排序 | SwiftData(macOS 14 及以后) | 几千条历史 |
| 用户的文件 | FileManager、文件面板 | 批量重命名的对象 |
要掌握的知识
- @AppStorage ── 加在变量上,值就会自动保存,下次启动也能恢复
- Codable ── 把自定义的 struct 转成 JSON(编码),再从 JSON 还原(解码)
- 存放位置 ── 应用数据放进“Application Support”文件夹。不要擅自在文稿或桌面上创建文件
- FileManager 与 URL ── 列出、复制、移动文件。删除时以“移到废纸篓”(trashItem)为主,避免无法挽回的删除
- SwiftData ── 给类加上 @Model,就能像数据库一样保存和查询。数据一多就用它
- 书签 ── 在沙盒里,即使是用户选过一次的文件夹,下次启动也读不了。要记住它,得保存“安全范围书签”
练习作品:常用语(片段)本
把常用的句子登记好,从菜单栏选中就进入剪贴板。列表存成 JSON;用菜单还是用小窗口显示列表,由 @AppStorage 的设置来切换。
STEP 5 ── 系统集成
小工具的价值,取决于能和系统功能结合得多深。同时,从这里开始就要考虑“在哪里发布”,因为发布方式会改变你能做的事。
App Sandbox ── 把应用装进盒子
通过 Mac App Store 发布的应用,必须在名为 App Sandbox 的“盒子”里运行。盒子里的应用,只能碰用户选择的文件和被允许的功能(网络、摄像头等)。需要的功能在 Xcode 的 Signing & Capabilities 里声明(这种声明叫 Entitlements)。
对用户是安全,对开发者是限制。比如移动其他应用的窗口、读取其他应用的内容这类工具,要用辅助功能(Accessibility)API,而它在沙盒里基本用不了。这类工具通常在自己的网站发布。
要掌握的知识
| 想做的事 | 用什么 | 注意 |
|---|---|---|
| 登录时启动 | SMAppService(macOS 13 及以后) | 做成由用户自己打开的设置 |
| 读写剪贴板 | NSPasteboard | 没有变化通知,要定期检查 changeCount |
| 发通知 | UserNotifications | 首次需要请求许可 |
| 打开应用・文件・URL | NSWorkspace | — |
| 从快捷指令或 Spotlight 调用 | App Intents | 把功能公开为“操作” |
| 全局快捷键 | 全局热键(旧 API 或封装它的包) | 选不与其他应用冲突的键 |
| 操作其他应用的窗口 | 辅助功能 API | 需要用户授权,放在沙盒外 |
| 读取屏幕内容 | ScreenCaptureKit | 需要录屏权限 |
先说明理由,再请求权限
在 macOS 上,辅助功能、录屏、完全磁盘访问等权限,由用户在“系统设置 › 隐私与安全性”里逐项批准,应用无法擅自获得。先在界面上说明为什么需要这个权限,再去请求,这是礼貌,也决定了用户会不会继续用下去。
练习作品:剪贴板历史
记录最近复制的最多 50 条文字,可以从菜单栏重新选取。定时检查 NSPasteboard 的 changeCount,一有变化就加进历史。存储用 STEP 4 的 SwiftData,登录启动用 SMAppService。也想一想密码之类的敏感信息该怎么处理(比如看到密码管理器加上的“请勿记录”标记,就不写进历史)。
STEP 6 ── 质量打磨
质量不是最后一口气补上的东西,而是从 STEP 1 起一点点并行养成的。
调试
- 先用 print() 输出值来确认。熟练之后,用断点(点击行号)让程序停下,查看当时的变量
- 停下后在调试区输入 po 变量名,就能看到内容
- 运行卡顿、内存一直涨,就用 Instruments(Time Profiler、Leaks)找原因
测试
加上 @Test 的函数就是测试,在 #expect 里写“应该是这样”(上面的 FileNamer 是举例用的类型)。先测计算、文件名拼接这类“逻辑”,而不是界面,比较容易上手。STEP 2 把界面和计算分开,在这里就派上用场了。
为用户着想
- 无障碍 ── 只有图标的按钮要加 .accessibilityLabel。用旁白(VoiceOver)操作一遍
- 多语言 ── 界面文字会自动汇集到 String Catalog(.xcstrings)。Xcode 27 还能让智能体帮忙翻译
- 深色模式 ── 颜色不用固定值,用系统颜色或资源目录里的颜色
- 图标 ── 用 Icon Composer 制作应用图标
用 Git 留下历史
每个作品建一个仓库,能跑就小步提交。改坏了也能回退的安心感,直接关系到学习的速度。
STEP 7 ── 发布
在自己的 Mac 上能跑,和在别人的 Mac 上能跑,是两回事。经过 Apple 的签名与检查,才会成为在别人 Mac 上也能顺利打开的应用。
发布的三条路
②和③需要加入 Apple Developer Program(每年 99 美元;各地区以本地货币定价,价格可能调整)
在自己的网站发布(Developer ID + 公证)
通过网站或 GitHub,以 .dmg 或 .zip 分发。公证(notarization)是 Apple 的服务器自动检查应用(有没有恶意软件、签名是否有问题),合格后签发“票据”的机制。它和 App Store 的审核不是一回事,通常一小时内就会返回结果。
公证要求用 Developer ID 证书签名,并启用 Hardened Runtime(运行时保护)。推送更新,常见做法是集成 Mac 应用中广泛使用的开源框架 Sparkle。
通过 Mac App Store 发布
对用户最放心,支付和更新也可以交给商店。相应地,审核指南(2.4.5)里有 Mac 专属的规定:
- 必须在 App Sandbox 中运行
- 未经用户同意,不得在登录时自动启动
- 只能通过 App Store 更新,不能自带自动更新
- 不得请求管理员权限,不得要求输入许可证密钥
如 STEP 5 所说,有些工具在沙盒里做不出来。想做的东西一旦确定,就尽早决定在哪里发布,免得之后推倒重来。
练习作品:请朋友在他的 Mac 上打开
做一个已公证的 .dmg 发给朋友,请他打开。能否毫无警告地打开?不加说明,他能否看懂怎么用?第一次接触的人的反应,是最好的测试。
坚持下去的窍门
- 每天都碰一点 ── 与其每周一次 1 小时,不如每天 20 分钟。手会记住 Xcode
- 错误信息读全文 ── 即使是英文,也翻译着读一遍,答案常常就写在里面
- 用一手资料核实 ── 搜到的文章,去 Apple 文档确认一下。越旧的文章,写法越可能已经变了
- 把 AI 当家教 ── 让它讲解、让它比较,最后自己动手写。粘贴进来的代码,要做到能逐行解释
- 做自己每天会用的东西 ── 解决自己不便的工具,才有动力做完
- 把作品公开 ── 代码放到 GitHub,附上简短说明。会连到下一份工作和新的伙伴
想继续深入的话
- WWDC 的专题视频 ── 每年 6 月发布,新功能的一手信息。先从“What's new in SwiftUI”看起
- Hacking with macOS(SwiftUI Edition) ── 专讲 Mac 的实战书(英文・付费),边做边学的结构
- 开源的 Mac 应用 ── 在 GitHub 上找 Swift 写的菜单栏应用来读。真实的代码是最好的教材
结 — 一页总结
- 目标是“从菜单栏或快捷键调用的小工具”。工具选 Swift + SwiftUI,不够再用 AppKit。
- STEP 0:Apple 芯片的 Mac 加免费的 Xcode 就能开始。收费注册到发布时才需要。
- STEP 1–2:Swift 的难关是 Optional。SwiftUI 是改了状态,界面自动跟上。
- STEP 3:App 与 Scene。用 MenuBarExtra・Settings・菜单与快捷键做出 Mac 味。
- STEP 4–5:存储位置的区分,以及与系统的结合。沙盒的限制决定发布方式。
- STEP 6:调试、测试、无障碍,从一开始就并行。
- STEP 7:自己网站发布靠 Developer ID 与公证,App Store 发布靠沙盒与审核。
- 看教材要看发布日期和对应版本。对 AI,与其让它写,不如让它讲。
参考
- Apple — Develop in Swift Tutorials
- The Swift Programming Language (6.4)
- Apple — Xcode 27 Release Notes(运行要求・新功能)
- Apple — MenuBarExtra
- Apple — SMAppService
- Apple — Notarizing macOS software before distribution
- Apple — App Review Guidelines(2.4.5 Mac App Store 要求)
- Apple — Human Interface Guidelines
- Sparkle — software update framework for macOS
- Hacking with macOS: SwiftUI Edition
- Donny Wals — Setting default actor isolation in Xcode 26
开发指南 No.1 — Mac 应用开发入门路线图 / 2026.09