#!/bin/bash # Memory App 发布脚本 # 功能:自动递增版本号、编译 APK、上传到 R2、更新服务器版本信息 set -e # ============ 配置区域 ============ # R2 配置 R2_ACCOUNT_ID="ebf33b5ee4eb26f32af0c6e06102e000" R2_ACCESS_KEY_ID="8acbc8a9386d60d0e8dac6bd8165c618" R2_ACCESS_KEY_SECRET="72935e23b5b4be8fda99008e75285e8ac778f8926656c42780b25785bb149443" R2_BUCKET_NAME="memory" R2_PUBLIC_URL="https://cdn.amos.us.kg" # API 配置 API_BASE_URL="https://x.amos.us.kg/api" # 服务器配置 SERVER_HOST="95.181.190.226" SERVER_PORT="33" SERVER_USER="root" SERVER_PASSWORD="xiaobiao." SERVER_PROJECT_PATH="/amos/memory" # 签名配置 KEYSTORE_FILE="release.keystore" KEYSTORE_PASSWORD="memory123" KEY_ALIAS="memory" KEY_PASSWORD="memory123" # ============ 函数定义 ============ # 获取当前版本号 get_current_version() { grep "versionName" android/app/build.gradle.kts | head -1 | sed 's/.*"\(.*\)".*/\1/' } # 获取当前版本代码 get_current_version_code() { grep "versionCode" android/app/build.gradle.kts | head -1 | sed 's/[^0-9]*//g' } # 递增版本号 (1.1.9 -> 1.2.0, 1.1.0 -> 1.1.1) increment_version() { local version=$1 local major=$(echo $version | cut -d. -f1) local minor=$(echo $version | cut -d. -f2) local patch=$(echo $version | cut -d. -f3) patch=$((patch + 1)) if [ $patch -ge 10 ]; then patch=0 minor=$((minor + 1)) if [ $minor -ge 10 ]; then minor=0 major=$((major + 1)) fi fi echo "${major}.${minor}.${patch}" } # 更新 build.gradle.kts 中的版本号 update_version_in_gradle() { local new_version=$1 local new_code=$2 sed -i '' "s/versionCode = [0-9]*/versionCode = ${new_code}/" android/app/build.gradle.kts sed -i '' "s/versionName = \"[^\"]*\"/versionName = \"${new_version}\"/" android/app/build.gradle.kts sed -i '' "s/VERSION_CODE\", \"[0-9]*\"/VERSION_CODE\", \"${new_code}\"/" android/app/build.gradle.kts } # 编译 Docker 镜像并导出 build_docker() { echo "🐳 编译 Docker 镜像..." cd server docker build --platform linux/amd64 -t memory-server:latest . docker save memory-server:latest -o memory-server.tar cd .. echo "✅ Docker 镜像已导出到 server/memory-server.tar" } # 部署 Docker 镜像到服务器 deploy_docker() { echo "🚀 部署 Docker 镜像到服务器..." # 上传镜像到服务器 echo "📤 上传镜像文件..." sshpass -p "${SERVER_PASSWORD}" scp -P ${SERVER_PORT} -o StrictHostKeyChecking=no server/memory-server.tar ${SERVER_USER}@${SERVER_HOST}:${SERVER_PROJECT_PATH}/ # 在服务器上加载镜像并重启 echo "🔄 加载镜像并重启服务..." sshpass -p "${SERVER_PASSWORD}" ssh -p ${SERVER_PORT} -o StrictHostKeyChecking=no ${SERVER_USER}@${SERVER_HOST} << EOF cd ${SERVER_PROJECT_PATH} docker load -i memory-server.tar docker compose down docker compose up -d # 清理旧镜像 echo "🧹 清理旧镜像..." docker image prune -f # 删除镜像文件 rm -f memory-server.tar echo "✅ 服务已重启" EOF echo "✅ 部署完成!" } # 编译 APK build_apk() { echo "📦 编译 APK..." cd android KEYSTORE_FILE=$KEYSTORE_FILE \ KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD \ KEY_ALIAS=$KEY_ALIAS \ KEY_PASSWORD=$KEY_PASSWORD \ gradle assembleRelease --quiet cd .. } # 上传到 R2 upload_to_r2() { local version=$1 local apk_path="android/app/build/outputs/apk/release/app-release.apk" local remote_path="releases/memory-${version}.apk" echo "☁️ 上传到 R2..." # 使用 AWS CLI 上传 (需要配置 AWS CLI) AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID \ AWS_SECRET_ACCESS_KEY=$R2_ACCESS_KEY_SECRET \ aws s3 cp "$apk_path" "s3://${R2_BUCKET_NAME}/${remote_path}" \ --endpoint-url "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com" \ --content-type "application/vnd.android.package-archive" echo "${R2_PUBLIC_URL}/${remote_path}" } # 清理旧版本 APK,只保留最新的 3 个 cleanup_old_apks() { echo "🧹 清理旧版本 APK..." # 列出所有 APK 文件,按时间倒序排列 local apk_list=$(AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID \ AWS_SECRET_ACCESS_KEY=$R2_ACCESS_KEY_SECRET \ aws s3 ls "s3://${R2_BUCKET_NAME}/releases/" \ --endpoint-url "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com" \ | grep "memory-.*\.apk" \ | sort -r \ | awk '{print $4}') # 跳过前 3 个(最新的),删除其余的 local count=0 for apk in $apk_list; do count=$((count + 1)) if [ $count -gt 3 ]; then echo " 删除: $apk" AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID \ AWS_SECRET_ACCESS_KEY=$R2_ACCESS_KEY_SECRET \ aws s3 rm "s3://${R2_BUCKET_NAME}/releases/${apk}" \ --endpoint-url "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com" fi done if [ $count -le 3 ]; then echo " 无需清理,当前共 ${count} 个版本" else echo "✅ 已清理 $((count - 3)) 个旧版本" fi } # 更新服务器版本信息,返回 0 成功,1 失败 update_server_version() { local version_code=$1 local version_name=$2 local download_url=$3 local update_log=$4 echo "🔄 更新服务器版本信息..." echo " version_code: ${version_code}" echo " version_name: ${version_name}" echo " download_url: ${download_url}" # 使用 printf 构建正确的 JSON local json_data=$(printf '{"version_code":%d,"version_name":"%s","download_url":"%s","update_log":"%s","force_update":false}' \ "$version_code" "$version_name" "$download_url" "$update_log") local response=$(curl -s -w "\n%{http_code}" -X POST "${API_BASE_URL}/version" \ -H "Content-Type: application/json" \ -d "$json_data") local http_code=$(echo "$response" | tail -n1) local body=$(echo "$response" | sed '$d') if [ "$http_code" = "200" ]; then echo "✅ 服务器版本信息已更新" return 0 else echo "❌ 更新服务器版本失败 (HTTP $http_code)" echo " 响应: $body" return 1 fi } # ============ 主流程 ============ echo "🚀 Memory App 发布脚本" echo "========================" # 选择发布内容 echo "" echo "请选择要发布的内容:" echo " 1) 只发布 APK" echo " 2) 只部署后端" echo " 3) 发布 APK + 部署后端" echo "" read -p "请选择 (1/2/3): " choice BUILD_APK=false DEPLOY_BACKEND=false case $choice in 1) BUILD_APK=true ;; 2) DEPLOY_BACKEND=true ;; 3) BUILD_APK=true DEPLOY_BACKEND=true ;; *) echo "❌ 无效选择" exit 1 ;; esac # APK 发布流程 if [ "$BUILD_APK" = true ]; then # 获取当前版本 current_version=$(get_current_version) current_code=$(get_current_version_code) echo "" echo "📌 当前版本: v${current_version} (code: ${current_code})" # 计算新版本 new_version=$(increment_version $current_version) new_code=$((current_code + 1)) echo "📌 新版本: v${new_version} (code: ${new_code})" # 获取更新日志 echo "" read -p "📝 请输入更新日志: " update_log if [ -z "$update_log" ]; then update_log="Bug 修复和性能优化" fi echo "" echo "📋 发布信息:" echo " 版本: v${new_version} (code: ${new_code})" echo " 更新日志: ${update_log}" echo "" # 更新版本号 echo "📝 更新版本号..." update_version_in_gradle $new_version $new_code # 编译 build_apk # 先更新服务器版本信息,成功后再上传 APK download_url="${R2_PUBLIC_URL}/releases/memory-${new_version}.apk" if update_server_version $new_code "$new_version" "$download_url" "$update_log"; then # 上传 APK upload_to_r2 $new_version echo "✅ 上传完成: $download_url" # 清理旧版本 cleanup_old_apks echo "" echo "🎉 APK 发布完成!" echo " 版本: v${new_version}" echo " 下载: ${download_url}" else echo "" echo "❌ 服务器版本更新失败,APK 未上传" exit 1 fi fi # 后端部署流程 if [ "$DEPLOY_BACKEND" = true ]; then echo "" build_docker deploy_docker echo "" echo "🎉 后端部署完成!" fi echo "" echo "✨ 全部完成!"