# ipswitch
**Repository Path**: yeti1/ipswitch
## Basic Information
- **Project Name**: ipswitch
- **Description**: 原生 macOS 网络配置切换应用
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-07-05
- **Last Updated**: 2026-07-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
IP Switch · 网络配置切换
原生 macOS 应用,用于管理网络预设并一键切换系统 IP / DNS 配置。
SwiftUI 构建,通过 networksetup 与特权 XPC helper 真正修改系统网络设置,提供 GUI 与命令行(CLI)两种交付形态。
---
> 🖼️ 仓库根目录的 `index.html` 是项目的高保真前端原型 / 设计落地页,SwiftUI 实现以其为视觉与交互基准。
## ✨ 功能特性
- 🗂️ **预设管理**:保存多套网络配置(网卡、服务名、手动/DHCP、IP、掩码、网关、DNS),增删改查。
- ⚡ **一键切换**:点击卡片或菜单栏项即可切换;可选切换前确认。
- 🍎 **菜单栏常驻**:`NSStatusItem` 动态预设菜单,配合主窗口使用。
- 🔄 **启动状态校正**:以记忆的激活预设为锚,校验当前网卡配置;被外部更改则提示,恰好匹配则自动采纳。同一时刻最多一个激活态。
- ⌨️ **CLI 工具**:`status` / `active` 子命令,支持 `--json`,可嵌入 shell 工作流。
- 🔐 **特权 helper**:XPC LaunchDaemon 执行需要 root 的写操作;**免签名脚本安装**,仅需免费 Apple ID 即可真机部署。
- 🔌 **系统集成**:登录时启动(`SMAppService`)、切换后通知(`UNUserNotificationCenter`)。
- 🛡️ **命令注入防护**:仅调用绝对路径 `/usr/sbin/networksetup`;IP/掩码/网关/DNS 严格 IPv4 校验;服务名仅来自系统枚举并统一加引号。
## 📋 系统要求
- 🍎 macOS 26.5+,Apple Silicon(arm64)
- 🛠️ Xcode 16+,Swift 5.0
- ✅ 构建/运行无需 Developer ID(helper 采用免签名安装)
## 🚀 快速构建
```bash
# Debug 构建(App + CLI + helper,helper 与 CLI 嵌入 App bundle)
xcodebuild -project src/ipswitch/ipswitch.xcodeproj \
-scheme ipswitch -configuration Debug \
-derivedDataPath src/ipswitch/build build
# Release 构建(分发用)
xcodebuild -project src/ipswitch/ipswitch.xcodeproj \
-scheme ipswitch -configuration Release \
-derivedDataPath src/ipswitch/build build
# 只构建 CLI(产物:src/ipswitch/build/Build/Products/Debug/ipswitch-cli)
xcodebuild -project src/ipswitch/ipswitch.xcodeproj \
-target ipswitch-cli -configuration Debug \
-derivedDataPath src/ipswitch/build build
# 跑单元测试
xcodebuild -project src/ipswitch/ipswitch.xcodeproj \
-scheme ipswitch -configuration Debug \
-derivedDataPath src/ipswitch/build test
```
📦 构建产物:
| 产物 | 位置 |
|------|------|
| `ipswitch.app` | `src/ipswitch/build/Build/Products/{Debug,Release}/ipswitch.app` |
| App 主二进制 | `ipswitch.app/Contents/MacOS/ipswitch` |
| CLI 二进制(嵌入 App) | `ipswitch.app/Contents/MacOS/ipswitch-cli` |
| 特权 helper(嵌入 App) | `ipswitch.app/Contents/Library/LaunchServices/ipswitch-helper` |
## 🎮 使用方式
### 🖥️ GUI
启动 `ipswitch.app`:主窗口管理预设,菜单栏图标快速切换。首次切换前,App 通过内置安装器部署特权 helper(`launchctl bootstrap`,弹管理员授权)。
状态持久化于 `~/Library/Application Support/IP Switch/state.json`(`{schemaVersion, presets[], activeId, settings}`,原子写)。
### ⌨️ CLI
CLI 嵌入 App bundle,也可单独构建:
```bash
# 列出所有预设与激活态
ipswitch-cli status
ipswitch-cli status --json
# 查看当前激活预设(支持模糊匹配)
ipswitch-cli active
ipswitch-cli --help
ipswitch-cli --version
```
退出码:`0` ✅ 成功,`1` ⚠️ 一般失败(参数错误 / 未匹配 / 命令失败 / 授权取消),`2` 🔥 内部错误(state 解析失败等)。
### 🔧 特权 helper 部署位置
- 二进制:`/Library/PrivilegedHelperTools/com.yeti.ipswitch.helper`
- LaunchDaemon plist:`/Library/LaunchDaemons/com.yeti.ipswitch.helper.plist`
卸载由 App 内置安装器执行(`launchctl bootout` + 清理文件)。
## 🧩 架构概览
工程含 4 个 target:
| Target | Bundle ID | 说明 |
|--------|-----------|------|
| `ipswitch` | `com.yeti.ipswitch` | GUI App(SwiftUI) |
| `ipswitch-cli` | `com.yeti.ipswitch.cli` | 命令行工具,共享 6 个核心源文件 |
| `ipswitch-helper` | `com.yeti.ipswitch.helper` | 特权 XPC LaunchDaemon |
| `ipswitchTests` | `com.yeti.ipswitchTests` | 单元测试 |
模块依赖:
```
ipswitchApp (@main, SwiftUI)
└─ AppDelegate ── MenuBarController (NSStatusItem)
└─ ContentView ── PresetCard / PresetEditorSheet / SettingsSheet / ToastView
└─ AppViewModel (@MainActor ObservableObject,唯一协调者)
├─ PresetStore JSON 持久化
├─ NetworkService 网卡枚举/读取/应用 + 启动状态校正
│ └─ CommandRunner (protocol)
│ ├─ RealCommandRunner (NSAppleScript 提权 / Process 只读)
│ └─ FakeCommandRunner (测试桩)
├─ PresetApplyExecutor 切换执行(helper 优先,回退直接 networksetup)
│ └─ HelperClient ──XPC── ipswitch-helper
└─ SystemIntegration SMAppService 登录项 / UNUserNotificationCenter
```
🔀 **切换流程**:UI/菜单 → `AppViewModel.performSwitch` → `PresetApplyExecutor` → `HelperClient`(XPC)→ `ipswitch-helper` 拼装并执行 `networksetup` 命令组 → 成功则更新激活态、持久化、Toast、(可选)通知。
🔒 **helper 安装策略**:`HelperInstaller` 通过 `HelperInstallerStrategy` 协议隔离,默认 `ScriptInstallerStrategy`(免签名脚本安装,`launchctl bootstrap`/`bootout`);`SMJobBlessStrategy` 作为备选(需 Developer ID)。
## 📂 项目结构
```
ipswitch/
├── index.html # 高保真前端原型 / 设计落地页
├── 生成脚本.md # 常用构建命令速查
├── src/ipswitch/
│ ├── ipswitch.xcodeproj/ # Xcode 工程
│ ├── ipswitch/ # App 源码
│ │ ├── ipswitchApp.swift # @main 入口
│ │ ├── AppDelegate.swift # NSApplicationDelegate
│ │ ├── MenuBarController.swift # 菜单栏 NSStatusItem
│ │ ├── ContentView.swift # 主窗口
│ │ ├── PresetCard.swift # 预设卡片
│ │ ├── AddPresetCard.swift # 新增预设入口
│ │ ├── PresetEditorSheet.swift # 预设编辑表单
│ │ ├── SettingsSheet.swift # 设置面板
│ │ ├── ToastView.swift # Toast 提示
│ │ ├── AppViewModel.swift # 状态协调者
│ │ ├── Models.swift # 数据模型(Preset/Settings/...)
│ │ ├── PresetStore.swift # JSON 持久化
│ │ ├── NetworkService.swift # 网卡枚举/读取/应用
│ │ ├── CommandRunner.swift # 命令执行(提权/只读)
│ │ ├── PresetApplyExecutor.swift # 切换执行器
│ │ ├── HelperClient.swift # XPC 客户端
│ │ ├── HelperProtocol.swift # XPC 协议
│ │ ├── HelperPayloads.swift # 请求/响应载荷
│ │ ├── HelperInstaller.swift # helper 安装器
│ │ ├── SystemIntegration.swift # 登录项/通知
│ │ ├── IPv4.swift / PresetValidation.swift # 校验
│ │ ├── DesignTokens.swift # 设计令牌
│ │ ├── HoverCursor.swift # 光标扩展
│ │ └── cli/ # CLI 专属源(仅 CLI target 编译)
│ │ ├── main.swift
│ │ ├── CLIDispatcher.swift
│ │ ├── StatusCommand.swift
│ │ ├── ActiveCommand.swift
│ │ ├── FuzzyMatch.swift
│ │ └── CLIInstaller.swift
│ ├── ipswitch-helper/ # 特权 XPC helper
│ │ ├── main.swift
│ │ ├── HelperApplyPresetCommandBuilder.swift
│ │ ├── launchd.plist
│ │ └── Info.plist
│ └── ipswitchTests/ # 单元测试
├── tools/ # 验证脚本(Python)
│ ├── verify_privileged_helper_task1.py … task10.py
│ └── verify_unsigned_helper_install.py
└── docs/superpowers/ # 设计文档 / 实现计划 / 验证报告
├── specs/
├── plans/
└── reports/
```
## 🧪 测试与验证
### 单元测试
`src/ipswitch/ipswitchTests/` 注入 `FakeCommandRunner`,不触网、不提权,覆盖:IPv4 校验、表单校验、`PresetStore` JSON round-trip + 原子写、命令拼装(手动/DHCP/DNS 有值/DNS 清空)、helper client/installer、helper payloads、`PresetApplyExecutor`、CLI dispatch、active/active 模糊匹配、状态命令、网络服务、设置行。
测试中**不得**真实调用 `SMJobBless` / `SMJobRemove` / `AuthorizationCreate`。
### 验证脚本
`tools/` 下 Python 脚本对每个变更任务做静态接线检查 + 实际 `xcodebuild` 构建/测试验证:
- `verify_privileged_helper_task1.py` … `task10.py` — helper target 接线、XPC 协议、payload 校验、GUI 集成、构建矩阵、测试覆盖矩阵。
- `verify_unsigned_helper_install.py` — 免签名安装路径、launchctl 引导、健康检查。
运行示例:
```bash
python3 tools/verify_privileged_helper_task10.py
```
## 📚 文档与变更管理
- 📐 `docs/superpowers/specs/` — 各变更的技术设计文档(应用、CLI、特权 helper、免签名安装等)。
- 📝 `docs/superpowers/plans/` — 实现计划。
- 📊 `docs/superpowers/reports/` — 验证报告。
- 🌌 `openspec/` — OpenSpec delta spec 与变更目录(Comet 流程管理)。
## 📌 状态
版本 1.0。开发中,本地构建与签名(ad-hoc / Personal Team),未公证。