/install app-packager
APP 打包助手(带完成通知)
执行方式
方式一:命令行调用(推荐)
~/.openclaw/workspace/skills/app-packager/scripts/app-packager --branch develop --platform android --upload --api-key 你的API_KEY --desc "更新说明"
重要:所有打包都必须使用此脚本,不要手动执行 pgyer_all.sh!
参数选项:
| 参数 | 简写 | 说明 | 默认值 |
|---|---|---|---|
--branch |
-b |
Git 分支 | develop |
--platform |
-p |
平台 (android/ios/all) | all (双端打包) |
--type |
- | 构建类型 (debug/adhoc/release) | debug |
--upload |
-u |
上传到蒲公英 | 否 |
--api-key |
--key |
蒲公英 API_KEY | - |
--desc |
-d |
更新说明 | - |
方式二:自然语言触发
直接对我说:"在 develop 分支打包 Android" 或 "打包 iOS release 版"
When to Run
- 用户说“打包 APP”“生成安装包”“构建应用”
- 用户说“在 xx 分支上打包”“切到 xx 分支打包”
- 用户指定平台如“打包 iOS”“打安卓包”
- 用户指定类型如“打 debug 包”“打 release 包”
- 用户指定版本如“版本 1.2.3 打包”
- 用户指定 API_KEY 如“api_key: xxxxx”
- 用户说“打渠道包”
Pre-flight Check(执行前检查)
- 确认项目路径:
/Users/nuoyun/Desktop/package/NYLiveUser是否存在 - 确认打包脚本:
./pgyer_all.sh是否有执行权限 - 确认 Git 命令可用
Workflow
第一步:解析用户意图
从用户输入中提取所有参数,使用以下规则:
参数提取规则
- 分支 (branch): 匹配
在\s*([\w\-_\./]+)\s*分支或切到\s*([\w\-_\./]+)\s*分支或分支[::]\s*([\w\-_\./]+) - 版本号 (version): 匹配
版本[::]?\s*([\d\.]+)或version[::]?\s*([\d\.]+) - 构建类型 (build_type): 匹配
debug|测试包|测试版本→debug;adhoc|验收包|验收版本→adhoc;release|发布包|发布版本|商店包→release - 平台 (platform): 匹配
iOS|苹果|iphone→ios;安卓|android→android;渠道包|多渠道→channel; 未指定时 → ``(双端打包) - 是否上传 (upload): 匹配
上传|需要上传|要上传→yes;不上传|不需要上传|不用上传→no - API_KEY (api_key): 匹配
api_key[::]\s*([a-zA-Z0-9_\-]+)或API密钥[::]\s*([a-zA-Z0-9_\-]+)或蒲公英密钥[::]\s*([a-zA-Z0-9_\-]+) - 更新说明 (desc): 匹配
说明[::]\s*(.+?)(?=\.|$|,|。)或描述[::]\s*(.+?)(?=\.|$|,|。)或更新内容[::]\s*(.+?)(?=\.|$|,|。)
特殊判断
- 渠道包:如果
platform为channel,设置is_channel_package=true
第二步:参数处理规则
基本原则:每个参数独立判断,用户指定就用指定的值,否则用脚本默认值。
| 脚本提示 | 参数变量 | 用户指定时的映射 | 默认行为 |
|---|---|---|---|
| 版本号 | version |
直接填入用户输入的版本号 | 直接回车(脚本读取 pubspec.yaml) |
| 构建类型 | build_type |
debug→1, adhoc→2, release→3 |
直接回车(脚本默认) |
| 平台选择 | platform |
ios→1, android→2, 渠道包→3 |
直接回车(脚本默认:双端打包) |
| 是否上传 | upload |
yes→1, no→2 |
直接回车(默认:不上传) |
| API_KEY | api_key |
直接填入用户输入的 API_KEY | 直接回车(用脚本默认值) |
| 更新说明 | desc |
直接填入用户输入的说明 | 直接回车(空字符串) |
第三步:执行打包流程
# 进入项目目录
cd /Users/nuoyun/Desktop/package/NYLiveUser/ || {
reply "❌ 错误:项目路径 /Users/nuoyun/Desktop/package/NYLiveUser/ 不存在"
exit 1
}
# 检查脚本权限
if [ ! -x "./pgyer_all.sh" ]; then
reply "❌ 错误:打包脚本 pgyer_all.sh 无执行权限,请执行:chmod +x pgyer_all.sh"
exit 1
fi
# 切换分支(如果指定了分支)
branch_status=""
if [ -n "$branch" ]; then
reply "🔄 正在切换到分支: $branch ..."
# 先拉取最新代码
git fetch --all
# 检查分支是否存在
if git show-ref --verify --quiet refs/heads/"$branch"; then
# 本地分支存在
git checkout "$branch"
git pull origin "$branch"
branch_status="✅ 已切换到本地分支: $branch"
elif git ls-remote --exit-code --heads origin "$branch"; then
# 远程分支存在,创建本地分支并跟踪
git checkout -b "$branch" origin/"$branch"
branch_status="✅ 已切换到远程分支: $branch"
else
# 分支不存在
reply "❌ 错误:分支 '$branch' 不存在"
exit 1
fi
else
current_branch=$(git branch --show-current)
branch_status="📌 保持当前分支: $current_branch"
fi
# 显示当前分支状态
git status -sb
# 记录开始时间
start_time=$(date +%s)
# 告知用户开始打包
reply "🚀 开始打包,预计需要3-5分钟,完成后我会通知您~"
# 构建输入序列
inputs=()
# 1. 版本号
if [ -n "$version" ]; then
inputs+=("$version")
else
inputs+=("")
fi
# 2. 构建类型
if [ "$build_type" = "debug" ]; then
inputs+=("1")
elif [ "$build_type" = "adhoc" ]; then
inputs+=("2")
elif [ "$build_type" = "release" ]; then
inputs+=("3")
else
inputs+=("")
fi
# 3. 平台选择
if [ "$is_channel_package" = "true" ]; then
inputs+=("3")
else
if [ "$platform" = "ios" ]; then
inputs+=("1")
elif [ "$platform" = "android" ]; then
inputs+=("2")
else
inputs+=("")
fi
fi
# 4. 如果不是渠道包,才需要后续三个参数
if [ "$is_channel_package" != "true" ]; then
# 4.1 是否上传
if [ "$upload" = "yes" ]; then
inputs+=("1")
elif [ "$upload" = "no" ]; then
inputs+=("2")
else
inputs+=("2") # 默认不上传(对应脚本中的选项2)
fi
# 4.2 API_KEY - 接收用户输入,没有指定时用默认
if [ -n "$api_key" ]; then
inputs+=("$api_key")
else
inputs+=("") # 回车,使用脚本默认值
fi
# 4.3 更新说明
if [ -n "$desc" ]; then
inputs+=("$desc")
else
inputs+=("")
fi
fi
# 执行打包并捕获输出
temp_output=$(mktemp)
temp_error=$(mktemp)
# 构建输入字符串
input_string=""
for item in "${inputs[@]}"; do
input_string+="$item\
"
done
# 执行打包命令
echo -e "$input_string" | ./pgyer_all.sh > "$temp_output" 2> "$temp_error"
exit_code=$?
# 计算耗时
end_time=$(date +%s)
duration=$((end_time - start_time))
minutes=$((duration / 60))
seconds=$((duration % 60))
time_str="${minutes}分${seconds}秒"
# 读取输出内容
output_content=$(cat "$temp_output")
error_content=$(cat "$temp_error")
# 清理临时文件
rm -f "$temp_output" "$temp_error"
# 分析打包结果并生成反馈
if [ $exit_code -eq 0 ]; then
# 打包成功,提取生成的文件信息
apk_files=$(find /Users/nuoyun/Desktop/package/NYLiveUser/build -name "*.apk" -type f -mmin -5 2>/dev/null | head -3)
ipa_files=$(find /Users/nuoyun/Desktop/package/NYLiveUser/build -name "*.ipa" -type f -mmin -5 2>/dev/null | head -3)
# 提取蒲公英链接
pgyer_links=$(echo "$output_content" | grep -E "https?://[a-zA-Z0-9./-]+(pgyer|蒲公英)" | head -3)
# 构建成功消息
feedback="✅ 打包完成!\
\
"
feedback+="📂 分支信息:$branch_status\
"
feedback+="⏱️ 打包耗时:$time_str\
\
"
feedback+="📦 打包参数:\
"
# 版本号
if [ -n "$version" ]; then
feedback+="• 版本号:$version\
"
else
feedback+="• 版本号:默认(取自pubspec.yaml)\
"
fi
# 构建类型
if [ -n "$build_type" ]; then
feedback+="• 构建类型:$build_type\
"
else
feedback+="• 构建类型:默认(iOS debug/Android release)\
"
fi
# 平台
if [ "$is_channel_package" = "true" ]; then
feedback+="• 平台:渠道包(Android多渠道)\
"
elif [ -n "$platform" ]; then
feedback+="• 平台:$platform\
"
else
feedback+="• 平台:双端(iOS+Android)\
"
fi
# 上传
if [ "$is_channel_package" = "true" ]; then
feedback+="• 上传蒲公英:不适用(渠道包自动跳过)\
"
elif [ -n "$upload" ]; then
if [ "$upload" = "yes" ]; then
feedback+="• 上传蒲公英:是\
"
else
feedback+="• 上传蒲公英:否\
"
fi
else
feedback+="• 上传蒲公英:否(默认)\
"
fi
# API_KEY(只在用户指定或上传为是时显示)
if [ "$is_channel_package" != "true" ] && [ "$upload" = "yes" ]; then
if [ -n "$api_key" ]; then
feedback+="• API_KEY:$api_key\
"
else
feedback+="• API_KEY:使用默认值\
"
fi
fi
# 更新说明
if [ "$is_channel_package" = "true" ]; then
feedback+="• 更新说明:不适用\
"
elif [ -n "$desc" ]; then
feedback+="• 更新说明:$desc\
"
else
feedback+="• 更新说明:无\
"
fi
feedback+="\
📁 生成文件:\
"
# 添加APK文件
if [ -n "$apk_files" ]; then
while IFS= read -r apk; do
feedback+="📱 Android: \`$apk\`\
"
done \x3C\x3C\x3C "$apk_files"
fi
# 添加IPA文件
if [ -n "$ipa_files" ]; then
while IFS= read -r ipa; do
feedback+="🍎 iOS: \`$ipa\`\
"
done \x3C\x3C\x3C "$ipa_files"
fi
# 添加蒲公英链接
if [ -n "$pgyer_links" ] && [ "$upload" = "yes" ]; then
feedback+="\
📎 下载链接:\
"
while IFS= read -r link; do
feedback+="$link\
"
done \x3C\x3C\x3C "$pgyer_links"
fi
feedback+="\
💡 提示:文件保存在 build 目录下,可通过 Finder 访问。"
else
# 构建失败消息
error_summary=$(echo "$error_content" | tail -20)
feedback="❌ 打包失败\
\
"
feedback+="📂 分支信息:$branch_status\
"
feedback+="⏱️ 耗时:$time_str\
\
"
feedback+="❌ 错误信息:\
\`\`\`\
"
feedback+="$error_summary\
"
feedback+="\`\`\`\
\
"
feedback+="🔍 可能的原因:\
"
feedback+="1. 代码编译错误 - 检查 Flutter 环境\
"
feedback+="2. 依赖问题 - 尝试执行 \`flutter pub get\`\
"
feedback+="3. iOS 证书问题 - 检查证书配置\
"
feedback+="4. Android 签名问题 - 检查 keystore 配置\
\
"
feedback+="📋 完整日志:请查看项目目录下的 build.log 文件"
fi
# 发送反馈消息
reply "$feedback"
- Make sure OpenClaw is installed (local or Docker)
- Run the install command in chat:
/install app-packager - After installation, invoke the skill by name or use
/app-packager - Provide required inputs per the skill's parameter spec and get structured output
What is App Packager?
自动切换 Git 分支并执行 APP 打包脚本。支持指定分支、平台、构建类型、版本号、上传选项、API_KEY和更新说明。 打包完成后会自动通知用户结果。 Use when: 用户需要打包 APP、切换分支打包、构建应用、生成安装包。 NOT for: 代码合并、代码提交、单元测试、代码检查。 It is an AI Agent Skill for Claude Code / OpenClaw, with 164 downloads so far.
How do I install App Packager?
Run "/install app-packager" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.
Is App Packager free?
Yes, App Packager is completely free, licensed under MIT-0. You can download, install and use it at no cost.
Which platforms does App Packager support?
App Packager is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).
Who created App Packager?
It is built and maintained by Heigher (@heigher); the current version is v1.0.0.