团队开发的 macOS 菜单栏应用需要在用户登录后启动。你在云端 Mac 上点击“开机启动”,界面显示已启用;断开远程桌面、重新连接,却发现应用本来就没退出。这不能证明登录项有效。验收要把 注册、用户批准、真正重新登录后的启动 分开记录,尤其不能把远程客户端断线当成 macOS 登出。
先确定测试对象与边界
本文测试的是使用 SMAppService.mainApp 注册的主应用登录项,不是后台辅助程序或系统启动服务。目标应用需面向 macOS 13 或更新版本,并在应用自己的进程中调用注册接口;单独运行一段命令行 Swift 脚本,不能替它完成同一项注册。
准备一个独立的标准用户作为测试账号,提前确认能重新进入该账号的图形桌面。不要直接拿正在承载构建任务的工作账号实验:登出会结束交互会话,也可能打断依赖该会话的进程。先保存工作、记录回连方式,再开始测试。
“已注册”“已获批准”“登录后已启动”是三个不同结论。每个结论都要有对应证据,不能从前一个状态推断下一个状态。
检查安装后的应用
用计划交付的应用包测试,而不是只在 Xcode 中点击运行。以下路径换成实际安装位置:
APP="/Applications/ExampleApp.app"
test -d "$APP" || { echo "App bundle not found"; exit 1; }
/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' \
"$APP/Contents/Info.plist"
codesign --verify --deep --strict --verbose=2 "$APP"
记录输出的 bundle identifier,并核对它与本次构建目标一致。codesign 验证失败时,先处理应用包,不要把无法正常启动误判为登录项故障。签名验证也不等于已完成用户批准或登录后启动测试。
在应用内处理注册状态
把注册动作接到应用设置中的明确开关,而非每次启动都无条件调用。下面的代码放在 macOS 应用目标内,调用方应把返回状态转换成界面提示:
import ServiceManagement
@MainActor
func enableLaunchAtLogin() throws -> SMAppService.Status {
let service = SMAppService.mainApp
if service.status == .notRegistered {
try service.register()
}
return service.status
}
返回 .enabled 才能在界面上描述为已启用;.requiresApproval 应提示用户到系统设置检查,而不是显示为操作失败或偷偷反复注册。异常也要保留给界面处理。关闭开关时,在应用内调用 try SMAppService.mainApp.unregister(),随后重新读取状态,不能只改开关外观。
核对用户批准
在同一个测试账号下打开系统设置,查看登录项相关页面,确认应用是否列出、是否需要手动允许。设置入口的名称可能随 macOS 版本变化,应以当前系统界面为准。批准后返回应用,再读取 SMAppService.mainApp.status;不要仅凭系统设置里出现应用名称就写下“自动启动已通过”。
做一次真正的重新登录
先正常退出应用,记录此时它不在运行。随后使用 macOS 菜单明确退出测试账号,再重新登录该账号的图形桌面。观察应用窗口、菜单栏图标或应用自身可核对的运行状态;测试前先约定其中哪一项算“启动成功”,避免把启动后立即崩溃当成通过。
| 检查点 | 应保留的证据 |
|---|---|
| 注册前 | 应用版本、bundle identifier、测试账号 |
| 注册后 | 应用读取到的登录项状态 |
| 批准后 | 系统设置中的状态与应用重新读取的状态 |
| 重新登录后 | 应用是否运行,以及能否正常交互 |
| 停用并再次登录后 | 应用未因该登录项自动启动 |
最后一行要在应用内停用登录项后再测试。若应用还通过其他机制启动,应先识别那些机制,不能仅凭进程存在否定停用结果。测试结束再按需重新启用,并确认开关状态。
排除远程会话造成的假象
关闭远程桌面客户端、网络短暂中断或只锁定屏幕,都不一定结束 macOS 用户会话。重新连接后看到旧窗口,通常只能证明会话仍在,不能证明登录项触发过。通过 SSH 启动应用同样不是图形登录测试;SSH shell 与桌面会话的环境不同。
若注册状态正确而登录后没看到应用,按顺序检查:是否进入了注册时的同一用户、是否测试了安装包而非另一个构建副本、系统设置是否仍要求批准,以及应用是否启动后立即退出。若应用有启动日志,记录事件时间与本次登录时间,区分“未启动”和“启动后失败”;日志中不要写入访问凭据。
把验收结果留给下一次构建
保留一份简短记录:应用版本、bundle identifier、macOS 版本、测试账号、注册前后状态、批准操作、重新登录结果,以及停用后的复测结果。每次更新应用包后至少复核安装包身份和重新登录结果;涉及登录项实现变更时,重走注册与停用两条路径。
这套流程的价值不是证明某台机器“总会自动启动”,而是让一次具体构建的行为可复现、可排错。只要把图形登录与远程连接分开,登录项问题通常能缩小到应用包、用户批准或应用启动本身。
常见问题
SMAppService 注册成功后,为什么重新登录仍未启动应用?
先检查状态是否为 requiresApproval,并在测试账号的系统设置中确认登录项;再确认测试的是已安装应用、进行了真正的退出登录,以及应用启动后没有立即退出。
断开远程桌面连接可以代替退出登录测试吗?
不可以。断开连接通常只结束客户端会话,不一定结束 macOS 用户登录会话;应使用测试账号明确退出登录,再重新进入图形桌面验证。
让云端 Mac 接入你的工作流
VPSPush 提供可远程连接的独享物理 Mac。选择节点与租期后,在订单中核对接入信息和最终金额。