初始化

This commit is contained in:
谢宇宁
2026-09-15 15:44:13 +07:00
commit a23ba685e9
1065 changed files with 101122 additions and 0 deletions
Executable
+238
View File
@@ -0,0 +1,238 @@
#!/bin/bash
# 出错即停
set -e
# 自动使用 .fvmrc 中指定的 Flutter 版本(避免使用 PATH 里的系统 flutter 导致依赖冲突)
if [ -f "./.fvmrc" ]; then
FVM_VERSION=$(grep -o '"flutter"[[:space:]]*:[[:space:]]*"[^"]*"' .fvmrc | sed -E 's/.*"([^"]+)"$/\1/')
if [ -n "$FVM_VERSION" ] && [ -x "$HOME/fvm/versions/$FVM_VERSION/bin/flutter" ]; then
export PATH="$HOME/fvm/versions/$FVM_VERSION/bin:$PATH"
echo "🔧 使用 FVM Flutter 版本: $FVM_VERSION"
fi
fi
# 参数说明
if [ $# -lt 1 ]; then
printf -- "Build hgdj release package.\n\n"
printf -- "Usage: $0 <target> [mode] [export_method] [export_options_plist] [sign_mode]\n"
printf -- " target : a(android) | i(ios) | all\n"
printf -- " mode : release(默认) | debug | profile\n"
printf -- " export_method (iOS) : app-store(默认) | ad-hoc | development | enterprise\n"
printf -- " export_options_plist : ExportOptions.plist 路径(iOS 可选,留空用默认)\n"
printf -- " sign_mode (iOS) : codesign(默认) | nocodesign\n\n"
printf -- "Examples:\n"
printf -- " $0 a # Android release\n"
printf -- " $0 a debug # Android debug\n"
printf -- " $0 i # iOS release + app-store\n"
printf -- " $0 i release ad-hoc # iOS release + ad-hoc\n"
printf -- " $0 i release app-store ios/ExportOptions.plist\n"
printf -- " $0 i release app-store \"\" nocodesign # iOS 不签名出包\n"
printf -- " $0 all # Android + iOS release\n"
exit 1
fi
TARGET=$1
MODE=${2:-release}
EXPORT_METHOD=${3:-app-store}
EXPORT_OPTIONS_PLIST=${4:-}
SIGN_MODE=${5:-codesign}
# 参数校验
if [ "$TARGET" != "a" ] && [ "$TARGET" != "i" ] && [ "$TARGET" != "all" ]; then
echo "❌ 参数错误:target 只支持 a | i | all,你传的是 '$TARGET'"
exit 1
fi
if [ "$MODE" != "release" ] && [ "$MODE" != "debug" ] && [ "$MODE" != "profile" ]; then
echo "❌ 参数错误:mode 只支持 release | debug | profile,你传的是 '$MODE'"
exit 1
fi
case "$EXPORT_METHOD" in
app-store|ad-hoc|development|enterprise) ;;
*)
echo "❌ 参数错误:export_method 只支持 app-store | ad-hoc | development | enterprise,你传的是 '$EXPORT_METHOD'"
exit 1
;;
esac
if [ "$SIGN_MODE" != "codesign" ] && [ "$SIGN_MODE" != "nocodesign" ]; then
echo "❌ 参数错误:sign_mode 只支持 codesign | nocodesign,你传的是 '$SIGN_MODE'"
exit 1
fi
if [ -n "$EXPORT_OPTIONS_PLIST" ] && [ ! -f "$EXPORT_OPTIONS_PLIST" ]; then
echo "❌ 未找到 ExportOptions.plist$EXPORT_OPTIONS_PLIST"
exit 1
fi
# 项目根路径校验
if [ ! -f "./pubspec.yaml" ]; then
echo "❌ 请在项目根目录下执行此脚本"
exit 1
fi
PROJECT_PATH=$(pwd)
PUBSPEC_FILE="pubspec.yaml"
# 提取项目信息
APP_NAME=$(grep '^name:' "$PUBSPEC_FILE" | awk '{print $2}')
RAW_VERSION=$(grep '^version:' "$PUBSPEC_FILE" | awk '{print $2}')
SAFE_VERSION=${RAW_VERSION//+/_}
TIME_TAG=$(date +"%m%d-%H%M")
# 读取应用内 Config.isDebuglib/config/config.dart),决定产物命名标识:
# isDebug=true → 命名标识固定为 debug(如 hgdj_debug_xxxx),方便区分内测包
# isDebug=false → 正式环境,命名沿用构建模式(release/profile),保持不变
CONFIG_FILE="lib/config/config.dart"
CONFIG_DEBUG=$(grep -E 'static[[:space:]]+const[[:space:]]+isDebug[[:space:]]*=' "$CONFIG_FILE" 2>/dev/null | grep -oE 'true|false' | head -1)
if [ "$CONFIG_DEBUG" = "true" ]; then
BUILD_TAG="debug"
elif [ "$CONFIG_DEBUG" = "false" ]; then
BUILD_TAG="$MODE"
else
echo "⚠️ 未能从 $CONFIG_FILE 解析 Config.isDebug,命名回退为构建模式:$MODE"
BUILD_TAG="$MODE"
fi
DIST_DIR="./dist"
mkdir -p "$DIST_DIR"
# 打印信息并二次确认
echo "=========================================="
echo "📦 准备打包"
echo "📌 项目名: $APP_NAME"
echo "📌 版本号: $RAW_VERSION"
echo "📌 目标平台: $TARGET"
echo "📌 构建模式: $MODE"
echo "📌 Config.isDebug: ${CONFIG_DEBUG:-未知} → 命名标识: $BUILD_TAG"
if [ "$TARGET" = "i" ] || [ "$TARGET" = "all" ]; then
echo "📌 iOS 导出: $EXPORT_METHOD"
echo "📌 iOS 签名: $SIGN_MODE"
if [ -n "$EXPORT_OPTIONS_PLIST" ]; then
echo "📌 ExportOptions.plist: $EXPORT_OPTIONS_PLIST"
fi
fi
echo "📌 工程路径: $PROJECT_PATH"
echo "=========================================="
echo "确认无误?(按回车继续,Ctrl+C 取消)"
read -r CONFIRM
# Android 构建
build_android() {
echo "▶️ 开始构建 Android $MODE 包..."
if [ "$MODE" = "release" ]; then
flutter build apk --release --target-platform android-arm64
APK_SOURCE="build/app/outputs/flutter-apk/app-release.apk"
elif [ "$MODE" = "profile" ]; then
flutter build apk --profile --target-platform android-arm64
APK_SOURCE="build/app/outputs/flutter-apk/app-profile.apk"
else
flutter build apk --debug --target-platform android-arm64
APK_SOURCE="build/app/outputs/flutter-apk/app-debug.apk"
fi
if [ ! -f "$APK_SOURCE" ]; then
echo "❌ 构建失败,未找到 APK$APK_SOURCE"
exit 1
fi
APK_NAME="${APP_NAME}_${BUILD_TAG}_${SAFE_VERSION}_${TIME_TAG}.apk"
APK_DEST="${DIST_DIR}/${APK_NAME}"
cp "$APK_SOURCE" "$APK_DEST"
APK_SIZE=$(du -h "$APK_DEST" | awk '{print $1}')
echo "✅ Android 构建成功!"
echo "📁 输出路径: $APK_DEST"
echo "📏 文件大小: $APK_SIZE"
LAST_BUILT_FILE="$APK_DEST"
}
# iOS 构建(基于 flutter build ipa,一步出 ipa
build_ios() {
echo "▶️ 开始构建 iOS $MODE 包..."
if [ "$MODE" = "debug" ]; then
echo "⚠️ iOS 不支持 debug 模式打包,请使用 release 或 profiledebug 建议直接 flutter run"
exit 1
fi
IPA_OUTPUT_DIR="build/ios/ipa"
ARCHIVE_OUTPUT_DIR="build/ios/archive"
if [ "$MODE" = "release" ]; then
if [ "$SIGN_MODE" = "nocodesign" ]; then
flutter build ipa --release --no-codesign
elif [ -n "$EXPORT_OPTIONS_PLIST" ]; then
flutter build ipa --release --export-options-plist="$EXPORT_OPTIONS_PLIST"
else
flutter build ipa --release --export-method "$EXPORT_METHOD"
fi
else
if [ "$SIGN_MODE" = "nocodesign" ]; then
flutter build ipa --profile --no-codesign
elif [ -n "$EXPORT_OPTIONS_PLIST" ]; then
flutter build ipa --profile --export-options-plist="$EXPORT_OPTIONS_PLIST"
else
flutter build ipa --profile --export-method "$EXPORT_METHOD"
fi
fi
# 查找产物 ipa
IPA_SOURCE=""
for candidate in "$IPA_OUTPUT_DIR"/*.ipa; do
if [ -f "$candidate" ]; then
IPA_SOURCE="$candidate"
break
fi
done
if [ -z "$IPA_SOURCE" ]; then
if [ "$SIGN_MODE" = "nocodesign" ]; then
if [ -d "$ARCHIVE_OUTPUT_DIR" ]; then
echo "⚠️ 未签名模式下 Flutter 通常不会导出可安装的 IPA"
echo "✅ 未签名构建产物目录:$ARCHIVE_OUTPUT_DIR"
echo "📌 如需可安装/可上传的 IPA,请在 Xcode 配好 Team 和证书后用 codesign 模式重新打包"
LAST_BUILT_FILE=""
return
fi
echo "❌ 未签名构建完成,但未找到 archive 目录:$ARCHIVE_OUTPUT_DIR"
exit 1
fi
echo "❌ 构建结束,但未找到 IPA 文件:$IPA_OUTPUT_DIR/*.ipa"
echo "📌 通常是签名证书、Provisioning Profile 或 ExportOptions 配置有问题"
echo "📌 可以先试不签名出包:$0 i $MODE $EXPORT_METHOD \"$EXPORT_OPTIONS_PLIST\" nocodesign"
exit 1
fi
# 与 apk 命名对齐:去掉冗余的 ios 标识(后缀已区分平台),导出方式去连字符(ad-hoc→adhoc)
IPA_NAME="${APP_NAME}_${BUILD_TAG}_${EXPORT_METHOD//-/}_${SAFE_VERSION}_${TIME_TAG}.ipa"
IPA_DEST="${DIST_DIR}/${IPA_NAME}"
cp "$IPA_SOURCE" "$IPA_DEST"
IPA_SIZE=$(du -h "$IPA_DEST" | awk '{print $1}')
echo "✅ iOS 构建成功!"
echo "📁 输出路径: $IPA_DEST"
echo "📏 文件大小: $IPA_SIZE"
LAST_BUILT_FILE="$IPA_DEST"
}
# 分发
case "$TARGET" in
a) build_android ;;
i) build_ios ;;
all) build_android; build_ios ;;
esac
# 自动在 Finder 中打开并选中产物(仅 macOS)
if [[ "$OSTYPE" == "darwin"* ]]; then
if [ -n "$LAST_BUILT_FILE" ] && [ -f "$LAST_BUILT_FILE" ]; then
open -R "$LAST_BUILT_FILE"
else
open "$DIST_DIR"
fi
fi
echo "🎉 完成"