Xcode 项目清理脚本 clean_pod.sh:开发思路与使用指南
Xcode 项目清理脚本 clean_pod.sh:开发思路与使用指南
前言
在实际 iOS 开发中,Xcode 缓存、CocoaPods、Bundler、模拟器数据等经常成为「神秘问题」的根源:构建失败、无法解析头文件、模拟器存储暴涨、设备支持文件占用几十 GB……为此我写了一个一站式脚本 clean_pod.sh,支持命令行和交互两种方式,覆盖常见的清理与重装动作,尽量做到安全、可视、可回退。
源码位置:clean_pod.sh
设计目标与整体架构
- 双入口:
- 命令行参数直达:-p/-b 选择清理 Pods 或 Bundler;-r 重新安装依赖;-i/-I 仅安装
- 无参数进入交互式菜单,包含组合动作与设备/模拟器管理
- 可靠的项目探测:自动识别 .xcworkspace 优先,否则回退到 .xcodeproj
- 清晰的阶段化输出:彩色提示、结果摘要、失败兜底建议
- 安全优先:仅删除当前项目相关 DerivedData;模拟器与设备支持文件均需二次确认
功能概览
- Xcode 缓存
- 自动探测 workspace 或 project,并按三阶段规则选择 Scheme(优先精确匹配项目名;过滤 Tests/UITests/Example/Demo/Sample;最后回退第一个可用)
- 在 workspace 模式下优先查找同名 .xcodeproj 的共享 schemes,其次使用 workspace 自身的共享 schemes
- xcodebuild clean,删除 ./build,定向清理 DerivedData/<项目名>-*项目名>
- CocoaPods
- 删除 Pods 与 Podfile.lock,可选清理 pod 缓存
- 安装策略:检测到 Bundler 时优先 bundle exec;无 Bundler 回退 pod install
- .bundle/config 的写入与恢复:仅在需要时创建/修复,并始终将 path 指向 vendor/bundle
- Bundler
- 删除 vendor/bundle 与 .bundle;bundle clean –force
- 重新安装并恢复本地 path(vendor/bundle);在仅安装 Pods 且 .bundle/config 不存在时,为 pod 安装做一次性路径配置
- 设备与模拟器
- 查看模拟器占用、删除不可用设备、选择性删除关机设备、抹除全部模拟器数据
- 显示连接真机;清理 iOS DeviceSupport;清理 Xcode Archives
- 任务收尾
- 非「仅安装」模式下自动关闭 Xcode;输出清理结果摘要与下一步提示
核心执行流程
1) 探测项目结构:优先 .xcworkspace,回退 .xcodeproj 2) 解析可用 Schemes,按三阶段规则选中最终 Scheme,并在日志中明确打印 3) 根据选项执行 Xcode 缓存清理(xcodebuild clean + 本地 build + 定向 DerivedData) 4) Pods 清理与安装:
- 清理 Pods/Podfile.lock 与可选的 pod cache
- 优先 bundle exec pod install –clean-install;若无 Bundler,回退 pod install –clean-install 5) Bundler 清理与安装:
- 删除 vendor/bundle 与 .bundle;bundle clean –force
- bundle config set –local path ‘vendor/bundle’ + bundle install 6) 设备与模拟器工具箱(可选):查看/删除/抹除/统计等 7) 收尾:尝试关闭 Xcode,汇总结果
使用方式
- 交互式(推荐):
- 直接执行:
- ./clean_pod.sh
- 典型选项:
- 完整清理(Xcode + Pods + Bundler)
- 完整清理 + 重新安装所有依赖
- 进入「设备和模拟器管理」
- 直接执行:
- 命令行直达:
- 清理 Pods:
- ./clean_pod.sh -p
- 清理 Pods 并重装:
- ./clean_pod.sh -p -r
- 清理 Bundler 并重装:
- ./clean_pod.sh -b -r
- 仅安装 Pods / 仅安装 Bundler:
- ./clean_pod.sh -i
- ./clean_pod.sh -I
- 清理 Pods:
关键实现要点
1) 项目探测与 Scheme 获取(修复后)
- 优先 workspace,其次 project;Scheme 缺失时回退为项目名
- 三阶段选择规则:
- 优先精确匹配项目名同名的 Scheme(例如项目 xxx -> Scheme xxx)
- 过滤 Tests/UITests/Example/Demo/Sample 等测试或示例类 Scheme
- 仍未命中则回退到第一个可用 Scheme
- 在 workspace 分支中先查找同名 .xcodeproj 的共享 Schemes,再回退到 workspace 自身的共享 Schemes(更贴合多工程聚合场景)
- 清理 DerivedData 仅匹配 “<项目名>-*",避免误删其他项目缓存项目名>
代码解析与实现细节
1) 命令行参数解析与交互主循环
- 支持命令行直达和交互式两种入口。当没有参数时进入交互菜单,有参数时使用 case 解析选项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 无参数进入交互式
if [[ "$#" -eq 0 ]]; then
INTERACTIVE_MODE=true
run_interactive_mode
else
# 命令行参数解析
while [[ "$#" -gt 0 ]]; do
case $1 in
-h|--help) show_help; exit 0 ;;
-p|--pods) CLEAN_PODS=true ;;
-b|--bundle) CLEAN_BUNDLE=true ;;
-r|--reinstall) REINSTALL_PODS=true; REINSTALL_BUNDLE=true ;;
-i|--install) INSTALL_ONLY_PODS=true ;;
-I|--install-bundle) INSTALL_ONLY_BUNDLE=true ;;
*) echo -e "${RED}错误: 未知选项 $1${NC}" >&2; show_help; exit 1 ;;
esac
shift
done
fi
- 交互模式中,先展示菜单,解析选择后按 Enter 执行;设备与模拟器管理为一个独立子菜单。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
run_interactive_mode() {
while true; do
show_interactive_menu
read -r choice
if handle_interactive_choice "$choice"; then
echo -e "\n${BLUE}按 Enter 键开始执行...${NC}"
read -r
break
else
echo -e "\n${YELLOW}按 Enter 键继续...${NC}"
read -r
fi
done
}
2) 项目探测与 Scheme 获取
- 优先寻找 .xcworkspace,其次 .xcodeproj,并据此获取可用 Schemes;在 workspace 下先尝试同名 .xcodeproj 的共享 Schemes,再回退到 workspace 的共享 Schemes;若最终解析不到则回退为项目名。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
WORKSPACE_FILE=$(find . -maxdepth 1 -name "*.xcworkspace" -print -quit)
if [ -z "$WORKSPACE_FILE" ]; then
PROJECT_FILE=$(find . -maxdepth 1 -name "*.xcodeproj" -print -quit)
if [ -z "$PROJECT_FILE" ]; then
echo -e "${YELLOW}⚠️ 未找到 .xcworkspace 或 .xcodeproj 文件${NC}"
else
PROJECT_NAME=$(basename "$PROJECT_FILE" .xcodeproj)
USE_PROJECT=true; HAS_XCODE_PROJECT=true
fi
else
PROJECT_NAME=$(basename "$WORKSPACE_FILE" .xcworkspace)
USE_PROJECT=false; HAS_XCODE_PROJECT=true
fi
# 使用 xcodebuild -list -json 解析 Schemes,并做三阶段筛选(略,见脚本)
[ -z "$SCHEME" ] && SCHEME="$PROJECT_NAME"
3) Xcode 构建缓存清理
- 分为 xcodebuild clean、删除本地 build 目录、定向清理 DerivedData 三步,避免误删其他项目缓存。
1
2
3
4
5
6
7
8
9
10
11
12
# 清理构建
if [ "$USE_PROJECT" = true ]; then
xcodebuild clean -project "$PROJECT_FILE" -scheme "$SCHEME"
else
xcodebuild clean -workspace "$WORKSPACE_FILE" -scheme "$SCHEME"
fi
# 删除 build 目录
rm -rf ./build
# 清理当前项目相关 DerivedData
find ~/Library/Developer/Xcode/DerivedData -name "${PROJECT_NAME}-*" -type d -exec rm -rf {} +
4) CocoaPods 清理与重装流程
- 先删除 Pods 与 Podfile.lock,再根据是否使用 Bundler 选择安装路径;同时尝试清理
pod cache
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 删除 Pods 与锁文件
rm -rf Pods Podfile.lock
# 清理 CocoaPods 缓存(可选)
if command -v bundle >/dev/null 2>&1; then
bundle exec pod cache clean --all 2>/dev/null || pod cache clean --all 2>/dev/null
else
pod cache clean --all 2>/dev/null || true
fi
# 重新安装(带 Bundler)
if command -v bundle >/dev/null 2>&1; then
[ "$CLEAN_BUNDLE" = true ] && bundle config set --local path 'vendor/bundle'
bundle install && bundle exec pod install --clean-install
else
pod install --clean-install
fi
5) Bundler 清理与重装
- 清理 vendor/bundle 与 .bundle;
bundle clean --force
清理缓存;重装前确保本地 path 指向 vendor/bundle。仅安装 Pods 时若 .bundle/config 缺失,也会临时写入 path。
1
2
3
4
5
6
7
8
9
10
11
12
13
# 清理 Bundler 产物
rm -rf vendor/bundle .bundle
# 清理 Bundler 缓存
if command -v bundle >/dev/null 2>&1; then
bundle clean --force 2>/dev/null || true
fi
# 重新安装并恢复路径
if command -v bundle >/dev/null 2>&1; then
bundle config set --local path 'vendor/bundle'
bundle install
fi
6) 模拟器信息与空间占用
- 使用
simctl list devices --json
拉取所有模拟器,再结合本地目录体积评估空间占用,日志中显示数量与总占用。
1
# 获取 json 并统计空间占用(实现细节见脚本)
- 建议:一次性解析 JSON 并映射到目录,减少多次
du -sh
调用的开销。
7) Archives 与 DeviceSupport 清理
- 提示风险并二次确认后删除;统计数量和总占用给出直观反馈。
1
2
3
4
archives_dir="$HOME/Library/Developer/Xcode/Archives"
archive_count=$(find "$archives_dir" -name "*.xcarchive" | wc -l | tr -d ' ')
# 确认后删除
rm -rf "$archives_dir"/*
8) 任务收尾与摘要
- 清理完成后关闭 Xcode,最后打印各步骤的成功/失败摘要,便于快速排查。
1
2
3
4
osascript -e 'tell application "Xcode" to quit' 2>/dev/null || true
echo -e "${BLUE}📋 清理摘要:${NC}"
# 按选项与结果变量输出 ...
修复后的关键改动(What’s new)
- Scheme 选择更智能:精确匹配项目名 > 过滤测试/示例 Scheme > 回退第一个可用;并在 workspace 中优先读取同名 .xcodeproj 的共享 Schemes
- 日志更可验证:明确打印「使用共享的 Scheme: <名称>」与「最终 -scheme 传参」名称>
- Bundler 行为更安全:仅在需要时写入/重建 .bundle/config,且 path 始终固定为 vendor/bundle
- Pods 安装更稳健:在 Bundler 存在时一律 bundle exec;仅安装 Pods 且缺少 .bundle/config 时会做一次性路径配置
- 模拟器信息展示修复:解析 JSON、统一大小统计,避免文本解析误差
- 失败兜底提示更友好:网络/权限/环境问题时给出可操作建议
环境与兼容性(Ruby/CocoaPods/Xcode)
- 推荐使用 rbenv 安装 Ruby 3.3.x 或 3.4.x,并在项目根目录设置 .ruby-version 统一团队环境
- 如果遇到
pod install
期间 Ruby 扩展崩溃(例如 digest/sha2.bundle 相关),多半是老 Ruby 与新系统 ABI 不兼容,解决思路:- 安装新 Ruby:rbenv install 3.4.3 && rbenv local 3.4.3 && rbenv rehash
- 更新 gem 与 bundler:gem update –system && gem install bundler
- 清理并重装依赖:rm -rf vendor/bundle .bundle && bundle config set –local path ‘vendor/bundle’ && bundle install
- 重新安装 Pods:bundle exec pod install –clean-install(或直接 pod install)
- 确认 Xcode 命令行工具已选择到当前 Xcode(xcode-select -p)
验证清单(你可以这样自检)
- Scheme 选择:脚本输出应包含「使用共享的 Scheme: xxx」或与你项目名一致的 Scheme;xcodebuild 命令行中应看到
-scheme "xxx"
- Bundler 路径:执行
bundle config get path
,应显示vendor/bundle
;若你仅安装 Pods 且之前没有 .bundle/config,安装后应能看到该路径被写入 - Pods 安装:
pod install --clean-install
或bundle exec pod install --clean-install
能顺利完成,无 Ruby 扩展崩溃 - 清理范围:DerivedData 仅清理
${PROJECT_NAME}-*
前缀目录,避免误删其他项目
实战建议
- 建议在执行前手动关闭 Xcode(脚本也会在清理结束时尝试关闭)
- Archives 中如有发布用构建,删除前做好备份;DeviceSupport 删除后,首次连机会重新下载
- 网络不稳定时,重装 Pods/Bundler 失败较常见,可重试或切换镜像源
已实现的改进
1) Scheme 解析与包含空格的 Scheme 名
- 已改进:使用
xcodebuild -list -json
结合 Python 解析 JSON,正确获取包含空格的 Scheme 名称 - 增加了错误处理,确保解析失败时能回退到默认 Scheme
2) 交互式删除模拟器的设备名解析
- 已改进:使用
xcrun simctl list devices --json
结合 Python 解析 JSON,准确获取设备名称 - 不再依赖文本解析,提高了稳定性和准确性
3) 交互模式从「设备与模拟器管理」返回后的流程
- 已修复:从设备管理菜单返回时,现在会重新显示主菜单,而不是直接进入清理阶段
- 优化了用户体验,避免了无意中执行清理操作
4) 模拟器信息与空间占用
- 已优化:一次性获取所有模拟器目录大小,结合 JSON 解析,减少了多次
du -sh
调用 - 提高了性能和准确性
本文由作者按照 CC BY 4.0 进行授权