Focalboard Mac 个人桌面版:Swift 壳应用、单用户服务端架构与 Xcode/Safari 调试指南
【免费下载链接】focalboardFocalboard is an open source, self-hosted alternative to Trello, Notion, and Asana.项目地址: https://gitcode.com/GitHub_Trending/fo/focalboard
Focalboard 的mac/目录承载的是 Mac Personal Desktop(个人桌面版)完整实现:一个轻量级 Swift Mac 应用壳、以单用户模式(single-user)运行的服务端二进制,以及打包进应用内的 Web 前端。本文以 mac/README.md 为主干,结合 AppDelegate.swift、ViewController.swift、server/main/main.go 与根目录 Makefile 中的实现细节,系统讲解其架构组成、单用户服务端的启动与鉴权原理,并给出在 Xcode 中调试客户端、用 Safari 开发者工具调试 WebView、以及在浏览器中独立验证单用户服务端的完整操作步骤。
目录结构与打包形态:一次看懂 Mac 桌面版由什么组成
mac/目录并非一个独立的完整应用,而是“壳 + 服务端 + Web 前端”三件套的装配现场:
- Swift 壳应用:位于 mac/Focalboard,包含
AppDelegate.swift、ViewController.swift、CustomWKWebView.swift、DownloadHandler.swift、PortUtils.swift等,负责拉起服务端进程、注入会话令牌、承载 WebView 渲染界面。 - Mac 服务端二进制:由 Go 编写的服务端以 darwin 目标交叉编译得到,运行时被复制进应用资源目录。
- Web 前端(webapp):即仓库根目录 webapp 构建出的静态产物
pack,与服务端一起随应用分发。
官方 README 对这三者的关系做了明确定义:"It packages a lightweight Swift Mac App with the Mac build of the server, and the webapp. The server is run in a single-user mode."(它把一个轻量级 Swift Mac App、Mac 版服务端以及 Web 前端打包在一起,且服务端以单用户模式运行。)
从根目录 Makefile 的mac-app目标可以还原出完整构建流水线:
mac-app: server-mac webapp ## Build Mac application. rm -rf mac/temp mac/dist mac/resources/bin mac/resources/pack mkdir -p mac/resources/bin cp bin/mac/focalboard-server mac/resources/bin/focalboard-server cp app-config.json mac/resources/config.json cp -R webapp/pack mac/resources/pack xcodebuild archive -workspace mac/Focalboard.xcworkspace -scheme Focalboard \ -archivePath mac/temp/focalboard.xcarchive \ CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED="NO" CODE_SIGNING_ALLOWED="NO" \ || { echo "xcodebuild failed, did you install the full Xcode and not just the CLI tools?"; exit 1; } cp -R mac/temp/focalboard.xcarchive/Products/Applications/Focalboard.app mac/dist/ cd mac/dist; zip -r focalboard-mac.zip Focalboard.app MIT-COMPILED-LICENSE.md NOTICE.txt webapp-NOTICE.txt其中server-mac目标负责以GOOS=darwin交叉编译服务端(见 Makefile),webapp目标负责构建前端静态资源。最终产出Focalboard.app与focalboard-mac.zip分发包,这是理解后续所有调试步骤的前提:桌面应用里跑的其实就是一个本地回环地址上的单用户服务端。
在 Xcode 中调试:打开工作区,而不是项目
README 给出的第一步非常明确:打开Focalboard.xcworkspace而非.xcodeproj。该工作区位于 mac/Focalboard.xcworkspace,其好处是统一管理主工程 mac/Focalboard.xcodeproj 及共享的 Scheme(位于 mac/Focalboard.xcodeproj/xcshareddata/xcschemes),直接 Run Scheme 即可启动应用。
启动后的完整生命周期可在 AppDelegate.swift 中看到:applicationDidFinishLaunching依次执行copyResources()(把pack与config.json复制到 Application Support 目录)、startServer()(拉起 Go 服务端进程)、展示更新说明,最后通过NotificationCenter广播serverStarted通知;ViewController.swift 监听该通知并延迟 0.5 秒后加载首页http://localhost:<port>/。
几点实现细节有助于理解调试行为:
- 端口自动避让:PortUtils.swift 会先用 socket
bind/listen探测默认端口 8088 是否空闲,若被占用则从 50000~65000 区间挑选一个空闲端口,并写入AppDelegate.serverPort。因此调试时若提示端口冲突,实际监听端口可能与默认值不同。 - 服务端进程随壳启停:
applicationWillTerminate中调用stopServer()结束子进程;服务端还通过-monitorpid <pid>参数监控壳进程,壳退出时服务端自行退出(见 server/main/main.go 的 PID 监控逻辑)。 - 会话令牌动态生成:每次启动都会用
SecRandomCopyBytes生成 16 字节随机数,前缀su-得到形如su-<32位hex>的令牌(见 AppDelegate.swift),后续注入 WebView 用于单用户鉴权。
用 Safari 开发者工具调试客户端 WebView
桌面应用使用WKWebView渲染整个前端界面,因此调试前端无需 Xcode 内的 Web Inspector,直接用 macOS 自带的 Safari 即可。README 给出的步骤为:
- 从 Xcode 运行 Focalboard 桌面应用;
- 打开 Safari;
- 启用 Safari 的开发者工具(Safari 菜单 → 设置 → 高级 → 勾选“在菜单栏中显示‘开发’菜单”);
- 在“开发”菜单下选择你的电脑名称,即可看到 Focalboard 应用对应的 WebView 入口,点击进入调试。
这一调试路径之所以可行,是因为 ViewController.swift 中的viewDidLoad创建了标准的CustomWKWebView(继承自WKWebView,见 CustomWKWebView.swift),并实现了WKNavigationDelegate、WKUIDelegate、WKScriptMessageHandler等协议,Safari 可附加到该 WebView 进程进行元素审查、断点与 Console 调试。
调试时值得关注的两个注入脚本(在 ViewController.swift 的updateSessionTokenAndUserSettings中):
- 会话令牌脚本:在文档加载前执行
localStorage.setItem('focalboardSessionId', '<token>'),为前端提供登录态; - 用户设置脚本:注入
const NativeApp = { settingsBlob: "<base64编码的localStorage>" };,实现用户设置在本地的持久化桥接;前端通过didChangeUserSettings等WKScriptMessage回调把变更写回UserDefaults(见 ViewController.swift)。
单用户模式服务端:一键启动与浏览器直连
README 提供了一个不依赖 Xcode、仅用浏览器就能验证单用户服务端的路径:
FOCALBOARD_SINGLE_USER_TOKEN=testtest make watch-single-user该命令会同时以监听模式运行服务端与 Web 前端,其中服务端以--single-user标志启动。对应 Makefile 目标(Makefile)为:
watch-single-user: modd-precheck ## Run both server and webapp in single user mode watching for changes env FOCALBOARDSERVER_ARGS=--single-user FOCALBOARD_BUILD_TAGS='$(BUILD_TAGS)' modd它依赖根目录的 modd.conf 配置,适合开发期热更新;若只需跑一个固定的单用户服务端,也可以直接构建后手动指定参数运行。
单用户模式的底层鉴权原理
从源码可以完整还原该模式的工作方式:
- 启动校验:
-single-user标志在 server/main/main.go 中被解析。一旦开启,必须从环境变量FOCALBOARD_SINGLE_USER_TOKEN读取令牌,否则直接logger.Fatal("The FOCALBOARD_SINGLE_USER_TOKEN environment variable must be set for single user mode")退出。也就是说,单用户模式“强制要求”会话令牌,这是该模式的安全边界。 - 会话注入:每次请求到达时,auth.go 的
attachSession中间件会比较请求携带的 token 与singleUserToken:不匹配则返回 401"invalid single user token";匹配则构造一个固定 ID 为model.SingleUser的虚拟会话放入请求上下文,后续 handler 一律视为同一用户。 - 能力收敛:单用户模式下多用户相关接口被显式拒绝,例如注册、登录、登出等会直接返回
"not permitted in single-user mode"(见 auth.go 等处的多处判断);系统信息接口也会将 SKU 标记为personal_desktop(参见 server/api/system_test.go 的测试用例)。
在浏览器中完成登录态注入
README 给出了利用浏览器开发者工具手动注入会话令牌的操作序列:
- 打开浏览器访问
http://localhost:8000; - 打开浏览器开发者工具(如 Chrome DevTools),进入 Application → Local Storage →
localhost:8000; - 将键
focalboardSessionId的值设置为testtest(即与FOCALBOARD_SINGLE_USER_TOKEN一致); - 刷新或重新导航到
http://localhost:8000。
完成注入后,前端发起的请求都会携带该令牌,服务端attachSession校验通过,即可以单用户身份正常使用全部看板功能。这与桌面应用内部WKUserScript注入localStorage的做法在原理上完全一致——区别仅在于桌面版由 AppDelegate.swift 用-single-user -port <port>参数及FOCALBOARD_SINGLE_USER_TOKEN环境变量自动完成令牌的生成与传递,而手动调试时需要你自己把令牌写进 Local Storage。
常见调试场景与排查建议
- WebView 白屏或加载失败:ViewController.swift 中
didFailProvisionalNavigation会在首页未加载成功时每隔 0.5 秒重试一次;若反复失败,请确认服务端进程确实已启动、端口未被其他程序占用,并检查 Application Support 目录下的Focalboard/server资源是否完整(含bin/focalboard-server、pack、config.json)。 - 端口冲突:默认端口 8088 被占用时应用会自动改用 50000~65000 区间内的空闲端口(PortUtils.swift)。需要确认实际端口时,可在 Xcode 中触发
showDiagnosticsInfo(对应 ViewController.swift 的诊断弹窗)查看。 - 浏览器直连时提示未授权:检查 Local Storage 中
focalboardSessionId是否与启动命令中的FOCALBOARD_SINGLE_USER_TOKEN完全一致(含大小写);若漏设环境变量,服务端会在启动阶段直接报错退出(server/main/main.go)。 - 需要在正式构建中验证打包:运行
make mac-app会依次完成服务端交叉编译、前端构建、资源复制与xcodebuild archive,产出位于mac/dist/;该命令同时要求本机安装完整版 Xcode(而非仅 Command Line Tools),否则会打印明确提示后失败(见 Makefile)。
小结
Focalboard 的 Mac 个人桌面版是理解“单用户模式”这一特性的最佳入口:壳应用通过-single-user、-port、-monitorpid参数与FOCALBOARD_SINGLE_USER_TOKEN环境变量拉起服务端,再以WKUserScript注入会话令牌完成自举。无论是用 Xcode + Safari 调试 WebView,还是用make watch-single-user在浏览器中独立验证服务端,掌握本文的启动链路与鉴权细节后,你都能快速定位问题并在此基础上做二次开发。
【免费下载链接】focalboardFocalboard is an open source, self-hosted alternative to Trello, Notion, and Asana.项目地址: https://gitcode.com/GitHub_Trending/fo/focalboard
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考