src/Apptag/Info.plist、src/CHANGELOG.md、src/Release/AppStore-7.9.1-20260614.1454/QA_RELEASE_EVIDENCE.mdTagLauncher 是一个 macOS 菜单栏/桌面工具。它扫描本机标准 App 目录,生成带标签、备注和使用行为的本地应用库;用户通过全屏 overlay 的 App Grid 或 Quick Search 打开应用,并可维护标签体系、备注、显示偏好和本地数据备份。
运行时代码是单体 macOS App,不使用 Xcode 工程文件构建,而由 src/build.sh 直接调用 swiftc 编译 src/Apptag/**/*.swift。主要框架包括:
SwiftUI:App 入口、主界面组合、设置页、部分弹窗和编辑态 UI。AppKit:NSPanel、NSWindow、菜单栏、全局/局部事件、NSCollectionView、自绘 App Grid、文件面板。Carbon:固定全局快捷键注册,主快捷键为 ⌥⇧Space,Quick Search 快捷键为 Fn+Space。CoreServices:Spotlight metadata 读取,用于应用显示名和系统应用名称候选。Compression:运行时加载 deflate 压缩后的 Smart Start 与 Apple 默认应用多语言资源。App 是 LSUIElement=true 的菜单栏工具,同时支持按用户设置显示 Dock 图标。当前 bundle id 是 com.taglauncher.app。
| 模块 | 主要文件 | 职责 |
|---|---|---|
| App 生命周期与窗口编排 | ApptagApp.swift、OverlayWindowController.swift、ProcessSingleton.swift |
单实例、菜单栏、快捷键、Dock/activation policy、overlay/window 层级、Quick Search 事件、Settings 附着关系 |
| 主业务 UI | ContentView.swift |
App Grid、Quick Search 状态、编辑模式、Smart Start 提示、备注气泡、刷新与 snapshot 应用 |
| App Grid 与拖拽 | AppGridCollectionView.swift、AppDragCoordinator.swift、TagNavigationView.swift |
AppKit-backed 网格布局、标签导航、长按拖拽、drop target、容器内排序、使用技巧悬浮条、hover、滚动期间状态抑制 |
| 数据与索引 | DataLayer.swift、AppLibraryController.swift |
App 扫描、名称抽取、TagDatabase 本地存储、标签 CRUD、应用库 snapshot |
| Quick Search | QuickSearch.swift |
搜索文档生成、搜索打分、行为 boost、独立面板、键盘焦点和结果列表 |
| Smart Start | SmartStartService.swift、SmartCategorizationDraft.swift、SmartCategory.swift |
首次/手动智能分类、catalog 匹配、默认备注、备份、恢复 |
| Apple 默认应用 | AppleDefaultAppCatalog.swift、Research/AppleDefaultApps |
Apple 系统应用分类、熟悉/不常用判定、多语言显示名和默认备注 |
| 本地化与设置 | L10n.swift、PreferencesView.swift、AppDefaults.swift |
29 语言、设置页、启动登录、导入导出、系统方案应用 |
| 构建与 QA | build.sh、make_dmg.sh、Scripts/*.sh |
编译、资源压缩复制、签名、DMG、窗口/资源/搜索专项 QA |
TagLauncherApp 是 @main 入口,初始化时调用 TagLauncherProcessSingleton.acquireOrHandOffAndExit()。如果已有实例持有锁,新实例会通过 DistributedNotificationCenter 把 --show-overlay 意图移交给旧实例,然后退出,避免多个 Dock 图标或多个菜单栏实例。
主实例启动后,AppDelegate.applicationDidFinishLaunching 做以下初始化:
AppDefaults.register()。L10n.setup()。migrateDefaultGroupName()。TagDatabase.seedDefaultTags()。syncChromeSettings(force: true)。registerConfiguredHotkeys()。warmAppIndexInBackground()。relocalizeDefaultAppNotesForCurrentLanguageAsync()。TagLauncher 的核心闭环是“扫描应用 -> 合并本地数据 -> 生成 snapshot -> 展示/搜索 -> 用户修改 -> 刷新 snapshot”。
AppIndexer.scan 扫描标准 App 路径,抽取 bundle id、文件名、Finder/Spotlight 名称、InfoPlist 多语言名、Apple catalog 名称和图标。TagEditor.reconcileScannedApps 与 TagDatabase.Store 合并,处理新增/删除 App、Apple 默认备注、不熟悉系统应用标记。SmartStartService.runIfNeeded 在 catalog 版本落后或首次运行时生成或应用智能分类。AppLibraryController.makeSnapshot 产出 AppLibrarySnapshot,同时包含:apps:已标注标签、备注、不常用状态的 App 列表。quickSearchDocuments:Quick Search 搜索文档。tagColors:标签颜色。tagOrder:标签展示顺序。containerAppOrder:稳定容器 ID 到 App path 顺序的映射。ContentView.applyAppLibrarySnapshot 把 snapshot 写入 UI 状态,重建 App Grid 分组,并刷新 Quick Search 结果。TagDatabase。refreshApps 或 .tagLauncherDataDidChange 触发新一轮 snapshot。运行时用户数据不写入仓库,默认写入:
~/Library/Application Support/TagLauncher/tags.json~/Library/Application Support/TagLauncher/SmartStartBackups/~/Library/Application Support/TagLauncher/CategorySchemeBackups/~/Library/Application Support/TagLauncher/TagLauncher-diagnostics.log,仅在 diagnosticLoggingEnabled 开启时写入TagDatabase.Store 是核心本地数据模型,包含标签定义、App 到标签的映射、标签顺序、容器内 App 顺序、不常用标记、打开次数、备注、备注来源 metadata、Smart Start 状态、分类方案状态。
AppLibrarySnapshot,减少“网格看得到但搜索搜不到”的分叉风险。AppNoteOrigin 区分,避免切语言或刷新时覆盖用户编辑。containerAppOrder,按 uncategorized、appleBuiltIn、tag:<name>、system:<id> 保存,避免语言切换导致顺序丢失。ApptagApp.swift 同时承担生命周期、菜单、快捷键、Dock policy、窗口路由和 Quick Search 状态协调,改动需结合 window_logic_qa.sh 做回归。ContentView.swift 聚合主业务 UI 和状态机,刷新、Quick Search、Smart Start、拖拽、备注弹窗相互影响,改动需确认 modal/backdrop 抑制是否仍正确。DataLayer.swift 是扫描、名称、存储、标签 CRUD 和容器排序归一化的交汇点,名称解析、helper 过滤或 containerAppOrder 一旦改动需同步跑 Quick Search 名称 QA 和排序数据 QA。SmartStartService.swift 与 AppleDefaultAppCatalog.swift 有默认备注来源保护逻辑,改动需跑 SmartStart、Apple resource 和 note policy QA。先从 AppLibraryController.refresh 跟到 ContentView.refreshApps,再从 AppDelegate.showQuickSearchFromGlobalHotkey 跟到 QuickSearchEngine.search。这两条线分别对应产品最核心的 App Grid 和 Quick Search。理解这两条线后,再看窗口层级、拖拽和 Smart Start,成本最低。