拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于Swift与AppKit的macOS菜单栏应用开发:从自动化需求到原生实现

1. 从“想吃”到“一键下单”一个吃货程序员的执念作为一个资深吃货兼 macOS 重度用户我经常遇到一个让人抓狂的场景深夜写代码突然馋虫上脑想吃小龙虾。打开外卖 App搜索、筛选、比价、凑单、领券……一套流程下来可能半小时过去了灵感没了食欲也凉了半截。为什么不能像切换 Wi-Fi 或者调节音量一样在菜单栏上点一下就直接下单我最常吃的那家小龙虾呢这个想法在我脑子里盘旋了很久。直到最近我决定不再忍受这种低效动手打造一个名为OpenClaw的 macOS 应用。它的核心目标极其简单把“点小龙虾”这个高频、刚需的动作变成一个固定在菜单栏上的、一键触达的按钮。这不仅仅是把外卖 App 的图标放在 Dock 栏而是深度集成实现从“唤起想法”到“完成支付”的最短路径。今天我就来详细拆解这个项目的构思、实现过程以及背后的技术选型思考希望能给同样想提升生活效率或者对 macOS 开发感兴趣的朋友一些启发。2. OpenClaw 的核心设计哲学极简与自动化在动手写第一行代码之前我花了大量时间思考 OpenClaw 应该是什么以及不应该是什么。我不想做一个功能臃肿的“外卖聚合平台”那违背了初衷。它的设计哲学必须围绕两个词极简与自动化。2.1 为什么是菜单栏Menu BarmacOS 的菜单栏是一个被严重低估的效率入口。它常驻屏幕顶端全局可访问不占用宝贵的屏幕工作区域。对比 Dock 栏、桌面快捷方式甚至 Alfred/LaunchBar 这类启动器菜单栏有几个独特优势零认知负担图标永远在那里无需记忆快捷键或打开其他应用。操作路径最短鼠标移动到顶部点击即可比切换到其他应用再操作更直接。状态可视化我们可以让图标显示一些状态比如店铺是否营业、是否有优惠券可用实现“一眼知天下”。因此将核心功能锚定在菜单栏是缩短用户操作路径、实现“所想即所得”的最佳载体。2.2 功能边界定义少即是多明确了载体接下来要严格定义功能边界。OpenClaw 的核心用户场景只有一个快速复购。用户不是来探索新店、写长篇评价的他们目的明确——以最快速度吃到上次觉得不错的小龙虾。基于此我划定了核心功能清单预设菜单管理允许用户预设1-3个最常点的菜品组合如“麻辣小龙虾大份拌面”并关联到常去的店铺。一键下单点击菜单栏图标选择预设菜单应用自动跳转到对应外卖平台如美团、饿了么的该店铺该商品页面并自动填充收货地址、优惠券如可用用户只需完成最后的支付确认。状态显示图标可简单显示店铺状态如打烊时变灰或优惠信息如红点提示。订单追踪进阶下单后在菜单栏下拉项中显示订单的简易状态如“商家已接单”、“骑手已取货”。同时我坚决砍掉了以下功能搜索比价这是外卖 App 的本职工作。浏览完整菜单预设就是为了跳过这一步。多平台比价增加复杂度违背“一键”原则。用户通常已对某个平台有偏好和会员权益。这个“做减法”的过程至关重要它确保了应用的核心体验聚焦且锋利。3. 技术架构选型与核心实现路径要实现上述功能技术选型是关键。作为一个独立开发者我需要权衡开发效率、性能、与 macOS 系统的集成度以及后期维护成本。3.1 原生 vs. 跨平台为什么选择 Swift 和 AppKit市面上有很多优秀的跨平台框架如 Electron、Flutter、Tauri 等它们能让我用熟悉的 Web 或 Dart 技术快速构建界面。但对于 OpenClaw 这样一个系统集成度要求高、追求极致性能和原生体验的菜单栏应用我最终选择了苹果官方的Swift AppKit组合。理由如下系统级集成能力AppKit 对菜单栏NSStatusItem的支持是原生且最稳定的。可以轻松创建、管理状态栏图标和菜单响应各种系统事件如暗色模式切换这是跨平台框架通过桥接实现所难以比拟的稳定性和性能。内存与性能一个常驻内存的菜单栏应用必须轻量。Electron 应用动辄占用上百 MB 内存而一个精心编写的原生 Swift 应用可以控制在 20MB 以内对系统资源更友好。自动化操作的实现与外卖平台的交互核心是模拟用户点击和跳转。这涉及到 URL Scheme 调用、WebView 内自动化操作如自动点击“结算”按钮。原生WebKit框架与 Swift 的配合更紧密执行此类自动化脚本通过 JavaScript更高效可靠。分发与沙盒通过 Mac App Store 分发或直接打包为.app都更方便沙盒机制也更清晰。当然代价是学习曲线和开发速度。但对于一个目标明确、功能聚焦的小工具投入时间掌握原生开发是值得的它能带来最好的最终用户体验。3.2 核心模块拆解OpenClaw 的架构可以拆解为以下几个核心模块1. 状态栏控制器StatusBarController这是应用的门面。使用NSStatusItem创建一个状态栏项目为其设置图标.template模式以支持暗色主题。我们需要监听图标的点击事件弹出NSMenu。菜单项包括预设的菜品、设置入口和退出选项。import Cocoa class StatusBarController { private var statusItem: NSStatusItem! private let menu NSMenu() init() { statusItem NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) if let button statusItem.button { button.image NSImage(named: claw_icon) // 你的图标 button.image?.isTemplate true // 支持暗色模式 } setupMenu() } private func setupMenu() { // 从持久化存储中加载预设菜单 let presetMenus PresetManager.shared.loadPresets() for menu in presetMenus { let item NSMenuItem(title: menu.displayName, action: #selector(placeOrder(_:)), keyEquivalent: ) item.target self item.representedObject menu // 关联数据 self.menu.addItem(item) } self.menu.addItem(NSMenuItem.separator()) self.menu.addItem(NSMenuItem(title: 设置..., action: #selector(openSettings(_:)), keyEquivalent: ,)) self.menu.addItem(NSMenuItem.separator()) self.menu.addItem(NSMenuItem(title: 退出 OpenClaw, action: #selector(quitApp(_:)), keyEquivalent: q)) statusItem.menu menu } objc func placeOrder(_ sender: NSMenuItem) { guard let preset sender.representedObject as? PresetMenu else { return } OrderAutomator.shared.executeOrder(for: preset) } // ... 其他方法 }2. 预设管理器PresetManager负责菜品预设的增删改查和持久化。数据模型PresetMenu需要包含预设名称、关联的外卖平台美团/饿了么、店铺ID、商品ID、规格选项ID、用户备注等。持久化使用UserDefaults或更结构化的Core Data/SQLite即可。3. 订单自动化执行器OrderAutomator这是技术核心也是最复杂的一部分。它的任务是根据一个PresetMenu对象自动完成从打开平台到跳转至结算页的全过程。这里没有官方API只能通过模拟用户操作实现。实现路径通常有两种URL Scheme 深度链接理想情况。如果外卖平台提供了完善的 URL Scheme能直接定位到店铺、商品甚至规格选择页面那将是最优雅的方案。我们需要仔细研究平台 App 的 URL Scheme 规则。WebView 自动化更通用的方案。在后台启动一个不可见的WKWebView加载外卖平台的 H5 页面然后通过注入并执行 JavaScript 代码模拟点击“店铺”、“加入购物车”、“选规格”、“去结算”等一系列操作。import WebKit class OrderAutomator: NSObject, WKNavigationDelegate { static let shared OrderAutomator() private var webView: WKWebView! private var currentPreset: PresetMenu? private var completion: ((Bool, Error?) - Void)? private override init() { super.init() let config WKWebViewConfiguration() // 可配置User-Agent使其更像移动端浏览器避免被重定向到PC站 config.applicationNameForUserAgent Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 webView WKWebView(frame: .zero, configuration: config) webView.navigationDelegate self // 可选注入通用脚本如跳过登录弹窗如果已登录 } func executeOrder(for preset: PresetMenu, completion: ((Bool, Error?) - Void)? nil) { self.currentPreset preset self.completion completion // 1. 构建目标URL例如店铺主页 guard let url URL(string: preset.shopDeepLink) else { return } let request URLRequest(url: url) // 2. 加载页面 webView.load(request) // 后续步骤在 navigationDelegate 回调中通过JS脚本逐步进行 } // WKNavigationDelegate 方法中在页面加载完成的回调里执行自动化脚本 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // 根据 currentPreset 的信息分步执行JS // 例如找到商品元素并点击 let jsClickProduct document.querySelector([data-product-id\(currentPreset!.productId)]).click(); webView.evaluateJavaScript(jsClickProduct) { _, error in if let error error { self.completion?(false, error) return } // 等待一下然后执行下一步如选择规格 DispatchQueue.main.asyncAfter(deadline: .now() 1.0) { self.selectSpecification() } } } private func selectSpecification() { // 类似的JS脚本选择规格、点击去结算... // 这是一个简化的示意实际脚本非常复杂且需要针对不同平台适配 } }注意Web 自动化方案极其脆弱。外卖平台的 H5 页面结构随时可能变更导致你的 CSS 选择器或 JS 路径失效。因此这个模块必须有完善的错误处理和日志记录并且需要设计一个“学习模式”让用户在第一次设置预设时手动走一遍流程应用记录下关键节点的点击路径这比硬编码选择器要稳健得多。4. 配置界面PreferencePane一个简单的视图用于添加、编辑、删除预设菜单。可以使用SwiftUI来快速构建并通过AppKit的NSHostingController嵌入到原生窗口中。界面元素包括文本框店铺/菜品名称、下拉菜单选择平台、以及一个“录制宏”按钮来辅助完成上述的自动化路径学习。4. 开发中的关键挑战与避坑指南实际开发过程远比设计复杂以下是几个我踩过的“坑”和解决方案。4.1 沙盒Sandbox权限与网络请求如果你计划上架 Mac App Store应用必须在沙盒内运行。这会给自动化操作带来巨大挑战网络访问需要声明com.apple.security.network.client权限。自动化其他 App沙盒应用严格禁止控制其他应用。这意味着你无法通过AppleScript或System Events去直接操控美团/饿了么的客户端。这是迫使你选择 WebView 自动化方案的核心原因之一因为操作发生在应用自身的 WebView 内不违反沙盒规则。文件访问存储预设配置需要用户明确授权或存储在容器内。建议开发初期可以先关闭沙盒进行功能验证待核心流程跑通后再开启沙盒并逐一解决权限问题。这能避免过早被沙盒限制搞得寸步难行。4.2 对抗反自动化与页面动态加载外卖平台的页面为了安全和防止爬虫会采用各种反自动化措施元素延迟加载商品列表可能通过滚动动态加载。你的脚本需要在点击前等待元素出现。使用WKNavigationDelegate的完成回调并不够还需要在 JS 中使用MutationObserver或轮询检查目标元素是否存在。验证码这是自动化之敌。如果触发验证码整个流程将失败。因此OpenClaw 的定位必须是“辅助工具”最终支付环节必须由用户手动完成这也能避免法律和安全风险。我们的自动化只负责把用户带到“确认支付”页面之前。随机化的 CSS 类名一些现代前端框架会生成随机的类名。不能依赖.class-name这样的选择器。更可靠的方式是使用>
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门