diff --git a/.github/workflows/build-android-apk.yml b/.github/workflows/build-android-apk.yml new file mode 100644 index 0000000..7db8a6a --- /dev/null +++ b/.github/workflows/build-android-apk.yml @@ -0,0 +1,319 @@ +name: Build Android APK + +on: + push: + branches: + - main + - develop + tags: + - 'v*' + pull_request: + branches: + - main + workflow_dispatch: # 允许手动触发 + inputs: + build_type: + description: '构建类型' + required: true + default: 'release' + type: choice + options: + - debug + - release + api_domain: + description: 'API 域名' + required: true + default: 'api.maodag.top' + type: string + oss_url_1: + description: 'OSS 配置地址 1' + required: true + default: 'https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt' + type: string + oss_url_2: + description: 'OSS 配置地址 2' + required: true + default: 'https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt' + type: string + oss_url_3: + description: 'OSS 配置地址 3' + required: true + default: 'https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt' + type: string + oss_url_4: + description: 'OSS 配置地址 4' + required: true + default: 'https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt' + type: string + +jobs: + build-libcore: + name: 编译 libcore.aar + runs-on: client-server + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Go 环境 + uses: actions/setup-go@v5 + with: + go-version: '1.23' + cache: true + cache-dependency-path: libcore/go.sum + + - name: 🔧 设置 Node.js 环境 + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: 🔧 设置 Java 环境 + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + + - name: 🔧 安装 gomobile + run: | + go install golang.org/x/mobile/cmd/gomobile@latest + gomobile init + + - name: 📦 编译 libcore.aar + working-directory: libcore + run: | + echo "🚀 开始编译 libcore..." + make android + + echo "✅ 编译完成,检查产物..." + ls -lh bin/ + + if [ -f "bin/libcore.aar" ]; then + echo "✅ libcore.aar 生成成功" + cp bin/libcore.aar ../android/app/libs/ + else + echo "❌ libcore.aar 未找到" + exit 1 + fi + + - name: 📤 上传 libcore.aar + uses: actions/upload-artifact@v4 + with: + name: libcore-aar + path: android/app/libs/libcore.aar + retention-days: 7 + + build-apk: + name: 编译 Android APK + needs: build-libcore + runs-on: ubuntu-latest + + strategy: + matrix: + build_type: [release] # 默认 release 构建 + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Java 环境 + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + + - name: 🔧 设置 Flutter 环境 + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.24.5' + channel: 'stable' + cache: true + + - name: 📥 下载 libcore.aar + uses: actions/download-artifact@v4 + with: + name: libcore-aar + path: android/app/libs/ + + - name: ⚙️ 配置 API 域名和 OSS 地址 + run: | + CONFIG_FILE="lib/app/common/app_config.dart" + + # 获取参数(手动触发时使用输入值,自动触发时使用默认值) + API_DOMAIN="${{ inputs.api_domain || 'api.maodag.top' }}" + OSS_URL_1="${{ inputs.oss_url_1 || 'https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt' }}" + OSS_URL_2="${{ inputs.oss_url_2 || 'https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt' }}" + OSS_URL_3="${{ inputs.oss_url_3 || 'https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt' }}" + OSS_URL_4="${{ inputs.oss_url_4 || 'https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt' }}" + + echo "🔧 配置构建参数:" + echo " API 域名: $API_DOMAIN" + echo " OSS 地址 1: $OSS_URL_1" + echo " OSS 地址 2: $OSS_URL_2" + echo " OSS 地址 3: $OSS_URL_3" + echo " OSS 地址 4: $OSS_URL_4" + + # 替换 API 域名 + sed -i "s|api\.maodag\.top|$API_DOMAIN|g" "$CONFIG_FILE" + + # 替换 OSS 地址 + sed -i "s|https://ppp2\.oss-cn-hongkong\.aliyuncs\.com/bear1\.txt|$OSS_URL_1|g" "$CONFIG_FILE" + sed -i "s|https://xgp3\.oss-ap-northeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_2|g" "$CONFIG_FILE" + sed -i "s|https://xpp4\.oss-ap-northeast-2\.aliyuncs\.com/bear1\.txt|$OSS_URL_3|g" "$CONFIG_FILE" + sed -i "s|https://xpp5\.oss-ap-southeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_4|g" "$CONFIG_FILE" + + echo "✅ 配置替换完成" + echo "" + echo "📄 查看修改后的配置:" + grep -A 15 "kr_baseDomains" "$CONFIG_FILE" || true + + - name: 📦 安装 Flutter 依赖 + run: | + flutter pub get + flutter pub run build_runner build --delete-conflicting-outputs + + - name: 🔨 构建 APK (Release) + run: | + flutter build apk --release --split-per-abi + + - name: 📋 生成构建信息 + id: build_info + run: | + BUILD_DATE=$(date '+%Y-%m-%d %H:%M:%S') + COMMIT_SHA=${GITHUB_SHA::7} + + echo "build_date=$BUILD_DATE" >> $GITHUB_OUTPUT + echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT + + echo "📊 构建信息:" + echo " - 日期: $BUILD_DATE" + echo " - 提交: $COMMIT_SHA" + echo " - 分支: ${GITHUB_REF#refs/heads/}" + + - name: 📦 重命名 APK 文件 + run: | + COMMIT_SHA=${{ steps.build_info.outputs.commit_sha }} + DATE=$(date '+%Y%m%d') + + cd build/app/outputs/flutter-apk/ + + for file in app-*-release.apk; do + if [ -f "$file" ]; then + # 提取架构名称 (arm64-v8a, armeabi-v7a, x86_64) + ARCH=$(echo "$file" | sed "s/app-\(.*\)-release.apk/\1/") + NEW_NAME="BearVPN-${ARCH}-release-${DATE}-${COMMIT_SHA}.apk" + + mv "$file" "$NEW_NAME" + + # 计算文件大小和 MD5 + SIZE=$(ls -lh "$NEW_NAME" | awk '{print $5}') + MD5=$(md5sum "$NEW_NAME" | awk '{print $1}') + + echo "✅ $NEW_NAME" + echo " 大小: $SIZE" + echo " MD5: $MD5" + fi + done + + ls -lh + + - name: 📤 上传 APK (arm64-v8a) + uses: actions/upload-artifact@v4 + with: + name: apk-arm64-v8a-release + path: build/app/outputs/flutter-apk/*arm64-v8a*.apk + retention-days: 30 + + - name: 📤 上传 APK (armeabi-v7a) + uses: actions/upload-artifact@v4 + with: + name: apk-armeabi-v7a-release + path: build/app/outputs/flutter-apk/*armeabi-v7a*.apk + retention-days: 30 + + - name: 📤 上传 APK (x86_64) + uses: actions/upload-artifact@v4 + with: + name: apk-x86_64-release + path: build/app/outputs/flutter-apk/*x86_64*.apk + retention-days: 30 + + create-release: + name: 创建 GitHub Release + needs: build-apk + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + + steps: + - name: 📥 下载所有 APK + uses: actions/download-artifact@v4 + with: + path: artifacts + pattern: apk-* + + - name: 📋 生成 Release 说明 + id: release_notes + run: | + cat > release_notes.md << 'EOF' + ## 🎉 BearVPN Android 版本发布 + + ### 📦 安装包说明 + + | 架构 | 适用设备 | 文件大小 | + |------|----------|----------| + | arm64-v8a | 64位 ARM 设备(推荐,现代手机) | ~40MB | + | armeabi-v7a | 32位 ARM 设备(老旧手机) | ~35MB | + | x86_64 | x86_64 模拟器 | ~45MB | + + ### ✨ 主要特性 + + - ✅ 支持 Shadowsocks/VLESS/Trojan/Hysteria2 等协议 + - ✅ 内置 sing-box 核心 + - ✅ 支持自定义路由规则 + - ✅ 支持 URL Test 节点延迟测试 + + ### 📥 下载建议 + + **不确定选哪个?** 下载 `arm64-v8a` 版本即可,适用于绝大多数现代 Android 手机。 + + ### 🔒 文件校验 + + 下载后请验证 MD5 以确保文件完整性(见下方 Assets 描述)。 + + --- + + **构建信息:** + - 提交: ${GITHUB_SHA::7} + - 构建时间: $(date '+%Y-%m-%d %H:%M:%S UTC') + - Flutter: 3.24.5 + - sing-box: latest + EOF + + echo "release_notes<> $GITHUB_OUTPUT + cat release_notes.md >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: 🚀 创建 GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: | + artifacts/apk-arm64-v8a-*/*.apk + artifacts/apk-armeabi-v7a-*/*.apk + artifacts/apk-x86_64-*/*.apk + body: ${{ steps.release_notes.outputs.release_notes }} + draft: false + prerelease: false + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: 📢 构建成功通知 + run: | + echo "✅ 构建完成!" + echo "📦 Release 已创建: ${{ github.ref }}" + echo "🔗 查看: https://github.com/${{ github.repository }}/releases" diff --git a/.github/workflows/build-clash-core.yml b/.github/workflows/build-clash-core.yml new file mode 100644 index 0000000..94e50e3 --- /dev/null +++ b/.github/workflows/build-clash-core.yml @@ -0,0 +1,142 @@ +name: Build Clash Core + +on: + push: + paths: + - 'core/**' + - '.github/workflows/build-clash-core.yml' + pull_request: + paths: + - 'core/**' + workflow_dispatch: # 允许手动触发 + +jobs: + build-android: + name: Build Android (${{ matrix.arch }}) + runs-on: client-server + + strategy: + fail-fast: false + matrix: + include: + - arch: arm64 + abi: arm64-v8a + cc: aarch64-linux-android29-clang + - arch: armv7 + abi: armeabi-v7a + cc: armv7a-linux-androideabi29-clang + - arch: x86_64 + abi: x86_64 + cc: x86_64-linux-android29-clang + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.20' + cache: true + cache-dependency-path: core/go.sum + + - name: Setup Android NDK + uses: nttld/setup-ndk@v1 + with: + ndk-version: r25c + add-to-path: true + + - name: Build Core + working-directory: core + run: make android-${{ matrix.arch }} + env: + ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} + + - name: Verify Build + run: | + echo "📦 检查编译产物..." + ls -lh android/app/src/main/jniLibs/${{ matrix.abi }}/libclash.so + file android/app/src/main/jniLibs/${{ matrix.abi }}/libclash.so + + echo "🔍 验证导出函数..." + nm -D android/app/src/main/jniLibs/${{ matrix.abi }}/libclash.so | grep -E "(quickStart|getAndroidVpnOptions|startTUN)" + + - name: Calculate MD5 + id: md5 + run: | + MD5=$(md5sum android/app/src/main/jniLibs/${{ matrix.abi }}/libclash.so | awk '{print $1}') + echo "md5=$MD5" >> $GITHUB_OUTPUT + echo "📋 MD5: $MD5" + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: libclash-${{ matrix.abi }} + path: android/app/src/main/jniLibs/${{ matrix.abi }}/libclash.so + retention-days: 30 + if-no-files-found: error + + - name: Comment Build Info + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const stats = fs.statSync('android/app/src/main/jniLibs/${{ matrix.abi }}/libclash.so'); + const sizeMB = (stats.size / 1024 / 1024).toFixed(2); + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `### 🔨 Clash Core 构建完成 (${{ matrix.abi }}) + + - **架构:** ${{ matrix.abi }} + - **大小:** ${sizeMB} MB + - **MD5:** ${{ steps.md5.outputs.md5 }} + - **提交:** ${context.sha.substring(0, 7)} + + [下载构建产物](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})` + }); + + create-release: + name: Create Release + needs: build-android + runs-on: client-server + if: startsWith(github.ref, 'refs/tags/v') + + steps: + - name: Download All Artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Create Release Archive + run: | + cd artifacts + tar -czf clash-core-android-all.tar.gz libclash-*/*.so + ls -lh clash-core-android-all.tar.gz + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + files: artifacts/clash-core-android-all.tar.gz + body: | + ## Clash Meta 核心 Android 构建 + + 此版本包含所有 Android 架构的预编译二进制文件: + - arm64-v8a (ARM64) + - armeabi-v7a (ARMv7) + - x86_64 (模拟器) + + **使用方法:** + ```bash + tar -xzf clash-core-android-all.tar.gz + cp libclash-*/libclash.so android/app/src/main/jniLibs/ + ``` + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/build-multiplatform.yml b/.github/workflows/build-multiplatform.yml new file mode 100644 index 0000000..b3510ac --- /dev/null +++ b/.github/workflows/build-multiplatform.yml @@ -0,0 +1,950 @@ +name: Build Multi-Platform + +on: + push: + branches: + - main + - develop + tags: + - 'v*' + pull_request: + branches: + - main + workflow_dispatch: + inputs: + build_type: + description: '构建类型' + required: true + default: 'release' + type: choice + options: + - debug + - release + api_domain: + description: 'API 域名' + required: true + default: 'api.maodag.top' + type: string + oss_url_1: + description: 'OSS 配置地址 1' + required: true + default: 'https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt' + type: string + oss_url_2: + description: 'OSS 配置地址 2' + required: true + default: 'https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt' + type: string + oss_url_3: + description: 'OSS 配置地址 3' + required: true + default: 'https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt' + type: string + oss_url_4: + description: 'OSS 配置地址 4' + required: true + default: 'https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt' + type: string + encryption_key: + description: '加密密钥' + required: true + default: 'c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx' + type: string + platforms: + description: '构建平台 (多选: android,windows,macos,linux,ios)' + required: true + default: 'windows' + type: string + +jobs: + # ==================== 编译 libcore (iOS/tvOS) ==================== + build-libcore-ios: + name: 编译 libcore (iOS/tvOS) + runs-on: client-server + if: ${{ github.event_name == 'workflow_dispatch' && contains(inputs.platforms, 'ios') }} + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Go 环境 + uses: actions/setup-go@v5 + with: + go-version: '1.23' + cache: true + cache-dependency-path: libcore/go.sum + + - name: 🔧 设置 Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: 📦 编译 libcore.xcframework (支持 iOS/tvOS) + working-directory: libcore + run: | + echo "🚀 开始编译 iOS/tvOS libcore..." + make ios-full + + if [ -d "bin/Libcore.xcframework" ]; then + echo "✅ iOS/tvOS libcore 编译成功" + ls -lh bin/ + else + echo "❌ iOS/tvOS libcore 编译失败" + exit 1 + fi + + - name: 📤 上传 iOS libcore + uses: actions/upload-artifact@v4 + with: + name: libcore-ios + path: libcore/bin/Libcore.xcframework + retention-days: 7 + + # ==================== 编译 libcore (Android) ==================== + build-libcore-android: + name: 编译 libcore (Android) + runs-on: ubuntu-latest + if: ${{ github.event_name == 'workflow_dispatch' && contains(inputs.platforms, 'android') }} + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Go 环境 + uses: actions/setup-go@v5 + with: + go-version: '1.23' + cache: true + cache-dependency-path: libcore/go.sum + + - name: 🔧 设置 Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: 🔧 设置 Java + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + + - name: 🔧 安装 gomobile + run: | + go install golang.org/x/mobile/cmd/gomobile@latest + gomobile init + + - name: 📦 编译 libcore.aar + working-directory: libcore + run: | + echo "🚀 开始编译 Android libcore..." + make android + + if [ -f "bin/libcore.aar" ]; then + echo "✅ libcore.aar 生成成功" + ls -lh bin/libcore.aar + else + echo "❌ libcore.aar 未找到" + exit 1 + fi + + - name: 📤 上传 libcore.aar + uses: actions/upload-artifact@v4 + with: + name: libcore-android + path: libcore/bin/libcore.aar + retention-days: 7 + + # ==================== 编译 libcore (Windows) ==================== + build-libcore-windows: + name: 编译 libcore (Windows) + runs-on: ubuntu-latest + if: ${{ github.event_name == 'workflow_dispatch' && contains(inputs.platforms, 'windows') || github.event_name != 'workflow_dispatch' }} + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Go 环境 + uses: actions/setup-go@v5 + with: + go-version: '1.23' + cache: true + cache-dependency-path: libcore/go.sum + + - name: 🔧 设置 Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: 🔧 安装 MinGW (交叉编译工具) + run: | + sudo apt-get update + sudo apt-get install -y mingw-w64 + + - name: 📦 编译 libcore.dll + working-directory: libcore + run: | + echo "🚀 开始编译 Windows libcore..." + make windows-amd64 + + if [ -f "bin/libcore.dll" ] && [ -f "bin/HiddifyCli.exe" ]; then + echo "✅ Windows libcore 编译成功" + ls -lh bin/libcore.dll bin/HiddifyCli.exe + else + echo "❌ Windows libcore 编译失败" + exit 1 + fi + + - name: 📤 上传 Windows libcore + uses: actions/upload-artifact@v4 + with: + name: libcore-windows + path: | + libcore/bin/libcore.dll + libcore/bin/HiddifyCli.exe + libcore/bin/webui/** + retention-days: 7 + + # ==================== 编译 libcore (macOS) ==================== + build-libcore-macos: + name: 编译 libcore (macOS) + runs-on: macos-latest + if: ${{ github.event_name == 'workflow_dispatch' && contains(inputs.platforms, 'macos') }} + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Go 环境 + uses: actions/setup-go@v5 + with: + go-version: '1.23' + cache: true + cache-dependency-path: libcore/go.sum + + - name: 🔧 设置 Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: 📦 编译 libcore.dylib + working-directory: libcore + run: | + echo "🚀 开始编译 macOS libcore..." + make macos-universal + + if [ -f "bin/libcore.dylib" ] && [ -f "bin/HiddifyCli" ]; then + echo "✅ macOS libcore 编译成功" + ls -lh bin/libcore.dylib bin/HiddifyCli + else + echo "❌ macOS libcore 编译失败" + exit 1 + fi + + - name: 📤 上传 macOS libcore + uses: actions/upload-artifact@v4 + with: + name: libcore-macos + path: | + libcore/bin/libcore.dylib + libcore/bin/HiddifyCli + retention-days: 7 + + # ==================== 编译 libcore (Linux) ==================== + build-libcore-linux: + name: 编译 libcore (Linux) + runs-on: ubuntu-latest + if: ${{ github.event_name == 'workflow_dispatch' && contains(inputs.platforms, 'linux') }} + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Go 环境 + uses: actions/setup-go@v5 + with: + go-version: '1.23' + cache: true + cache-dependency-path: libcore/go.sum + + - name: 🔧 设置 Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: 📦 编译 libcore.so + working-directory: libcore + run: | + echo "🚀 开始编译 Linux libcore..." + make linux-amd64 + + if [ -f "bin/lib/libcore.so" ] && [ -f "bin/HiddifyCli" ]; then + echo "✅ Linux libcore 编译成功" + ls -lh bin/lib/libcore.so bin/HiddifyCli + else + echo "❌ Linux libcore 编译失败" + exit 1 + fi + + - name: 📤 上传 Linux libcore + uses: actions/upload-artifact@v4 + with: + name: libcore-linux + path: | + libcore/bin/lib/libcore.so + libcore/bin/HiddifyCli + libcore/bin/webui/** + retention-days: 7 + + # ==================== Android 构建 ==================== + build-android: + name: 构建 Android APK + needs: build-libcore-android + runs-on: ubuntu-latest + if: ${{ github.event_name == 'workflow_dispatch' && contains(inputs.platforms, 'android') }} + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Java + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + + - name: 🔧 设置 Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.24.5' + channel: 'stable' + cache: true + + - name: 📥 下载 libcore.aar + uses: actions/download-artifact@v4 + with: + name: libcore-android + path: android/app/libs/ + + - name: ⚙️ 配置 API、OSS 和加密密钥 + run: | + CONFIG_FILE="lib/app/common/app_config.dart" + API_DOMAIN="${{ inputs.api_domain || 'api.maodag.top' }}" + OSS_URL_1="${{ inputs.oss_url_1 || 'https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt' }}" + OSS_URL_2="${{ inputs.oss_url_2 || 'https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt' }}" + OSS_URL_3="${{ inputs.oss_url_3 || 'https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt' }}" + OSS_URL_4="${{ inputs.oss_url_4 || 'https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt' }}" + ENCRYPTION_KEY="${{ inputs.encryption_key || 'c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx' }}" + + echo "🔧 配置参数:" + echo " API: $API_DOMAIN" + echo " OSS: $OSS_URL_1" + echo " 密钥: ${ENCRYPTION_KEY:0:10}..." + + # 转义密钥中的特殊字符(使用 perl 兼容所有平台) + ENCRYPTION_KEY_ESCAPED=$(echo "$ENCRYPTION_KEY" | perl -pe 's/([\[\].*^$()+?{|\\])/\\$1/g') + + sed -i "s|api\.maodag\.top|$API_DOMAIN|g" "$CONFIG_FILE" + sed -i "s|https://ppp2\.oss-cn-hongkong\.aliyuncs\.com/bear1\.txt|$OSS_URL_1|g" "$CONFIG_FILE" + sed -i "s|https://xgp3\.oss-ap-northeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_2|g" "$CONFIG_FILE" + sed -i "s|https://xpp4\.oss-ap-northeast-2\.aliyuncs\.com/bear1\.txt|$OSS_URL_3|g" "$CONFIG_FILE" + sed -i "s|https://xpp5\.oss-ap-southeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_4|g" "$CONFIG_FILE" + sed -i "s|c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx|$ENCRYPTION_KEY_ESCAPED|g" "$CONFIG_FILE" + + echo "✅ 配置完成" + + - name: 📦 安装 Flutter 依赖 + run: | + flutter pub get + flutter pub run build_runner build --delete-conflicting-outputs + + - name: 🔨 构建 APK (Release) + run: | + flutter build apk --release --split-per-abi + + - name: 📦 重命名 APK + run: | + COMMIT_SHA=${GITHUB_SHA::7} + DATE=$(date '+%Y%m%d') + cd build/app/outputs/flutter-apk/ + + for file in app-*-release.apk; do + if [ -f "$file" ]; then + ARCH=$(echo "$file" | sed "s/app-\(.*\)-release.apk/\1/") + NEW_NAME="BearVPN-android-${ARCH}-release-${DATE}-${COMMIT_SHA}.apk" + mv "$file" "$NEW_NAME" + echo "✅ $NEW_NAME" + fi + done + + - name: 📤 上传 APK + uses: actions/upload-artifact@v4 + with: + name: android-apk + path: build/app/outputs/flutter-apk/*.apk + retention-days: 30 + + # ==================== Windows 构建 ==================== + build-windows: + name: 构建 Windows + needs: build-libcore-windows + runs-on: windows-latest + if: ${{ github.event_name == 'workflow_dispatch' && contains(inputs.platforms, 'windows') || github.event_name != 'workflow_dispatch' }} + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.24.5' + channel: 'stable' + cache: true + + - name: 📥 下载 Windows libcore + uses: actions/download-artifact@v4 + with: + name: libcore-windows + path: libcore_windows_temp + + - name: 🔧 复制 libcore 文件到正确位置并重命名 + run: | + Write-Host "📋 开始复制 libcore 文件..." + + # 显示下载的文件结构 + Write-Host "🔍 检查下载的文件结构:" + Get-ChildItem -Recurse libcore_windows_temp -ErrorAction SilentlyContinue | Format-Table Name, FullName + + # 确保目标目录存在 + New-Item -ItemType Directory -Force -Path "libcore\bin" | Out-Null + + # 查找 libcore.dll(可能在 libcore_windows_temp/bin/ 或 libcore_windows_temp/libcore/bin/) + $dllFiles = Get-ChildItem -Path libcore_windows_temp -Recurse -Filter "libcore.dll" -ErrorAction SilentlyContinue + if ($dllFiles) { + $sourceDll = $dllFiles[0].FullName + Write-Host "✅ 找到 libcore.dll: $sourceDll" + Copy-Item $sourceDll "libcore\bin\libcore.dll" -Force + } else { + Write-Host "❌ 未找到 libcore.dll" + Write-Host "当前目录内容:" + Get-ChildItem -Path . -Recurse | Select-Object -First 20 | Format-Table Name, FullName + exit 1 + } + + # 查找并复制 HiddifyCli.exe,重命名为 BearVPNCli.exe + $exeFiles = Get-ChildItem -Path libcore_windows_temp -Recurse -Filter "HiddifyCli.exe" -ErrorAction SilentlyContinue + if ($exeFiles) { + $sourceExe = $exeFiles[0].FullName + Write-Host "✅ 找到 HiddifyCli.exe: $sourceExe" + Write-Host "📝 复制并重命名为 BearVPNCli.exe" + Copy-Item $sourceExe "libcore\bin\BearVPNCli.exe" -Force + Write-Host "✅ 重命名完成:HiddifyCli.exe → BearVPNCli.exe" + } else { + Write-Host "⚠️ 未找到 HiddifyCli.exe(这不是致命错误)" + } + + # 复制 webui 目录 + $webuiDir = Get-ChildItem -Path libcore_windows_temp -Recurse -Filter "webui" -Directory -ErrorAction SilentlyContinue + if ($webuiDir) { + Write-Host "✅ 找到 webui 目录: $($webuiDir[0].FullName)" + Copy-Item -Path $webuiDir[0].FullName -Destination "libcore\bin\webui" -Recurse -Force + } else { + Write-Host "⚠️ 未找到 webui 目录(这不是致命错误)" + } + + Write-Host "" + Write-Host "📄 验证复制后的文件结构:" + if (Test-Path "libcore\bin") { + Get-ChildItem libcore\bin\ -Recurse | Format-Table Name, FullName, Length + } else { + Write-Host "❌ libcore\bin 目录不存在" + } + + if (-not (Test-Path "libcore\bin\libcore.dll")) { + Write-Host "❌ libcore.dll 未正确复制到 libcore\bin\" + exit 1 + } + + Write-Host "✅ libcore 文件复制完成" + shell: pwsh + + - name: ⚙️ 配置 API、OSS 和加密密钥 + shell: bash + run: | + CONFIG_FILE="lib/app/common/app_config.dart" + API_DOMAIN="${{ inputs.api_domain || 'api.maodag.top' }}" + OSS_URL_1="${{ inputs.oss_url_1 || 'https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt' }}" + OSS_URL_2="${{ inputs.oss_url_2 || 'https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt' }}" + OSS_URL_3="${{ inputs.oss_url_3 || 'https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt' }}" + OSS_URL_4="${{ inputs.oss_url_4 || 'https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt' }}" + ENCRYPTION_KEY="${{ inputs.encryption_key || 'c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx' }}" + + ENCRYPTION_KEY_ESCAPED=$(echo "$ENCRYPTION_KEY" | perl -pe 's/([\[\].*^$()+?{|\\])/\\$1/g') + + sed -i "s|api\.maodag\.top|$API_DOMAIN|g" "$CONFIG_FILE" + sed -i "s|https://ppp2\.oss-cn-hongkong\.aliyuncs\.com/bear1\.txt|$OSS_URL_1|g" "$CONFIG_FILE" + sed -i "s|https://xgp3\.oss-ap-northeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_2|g" "$CONFIG_FILE" + sed -i "s|https://xpp4\.oss-ap-northeast-2\.aliyuncs\.com/bear1\.txt|$OSS_URL_3|g" "$CONFIG_FILE" + sed -i "s|https://xpp5\.oss-ap-southeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_4|g" "$CONFIG_FILE" + sed -i "s|c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx|$ENCRYPTION_KEY_ESCAPED|g" "$CONFIG_FILE" + + - name: 📦 安装 Flutter 依赖 + run: | + flutter pub get + + - name: 🔧 生成代码文件 (build_runner) + run: | + echo "🔧 开始运行 build_runner..." + flutter pub run build_runner build --delete-conflicting-outputs + + echo "" + echo "✅ build_runner 完成,检查生成的文件..." + + if (Test-Path "lib\singbox\model\singbox_status.freezed.dart") { + echo "✅ singbox_status.freezed.dart 已生成" + } else { + echo "❌ singbox_status.freezed.dart 未生成" + exit 1 + } + + if (Test-Path "lib\singbox\service\singbox_service_provider.g.dart") { + echo "✅ singbox_service_provider.g.dart 已生成" + } else { + echo "❌ singbox_service_provider.g.dart 未生成" + exit 1 + } + shell: pwsh + + - name: 🔧 验证 libcore 文件存在 + run: | + Write-Host "📋 验证 libcore 文件是否存在..." + + if (Test-Path "libcore\bin\libcore.dll") { + $dllInfo = Get-Item "libcore\bin\libcore.dll" + Write-Host "✅ libcore.dll 存在: $($dllInfo.FullName) - 大小: $($dllInfo.Length) bytes" + } else { + Write-Host "❌ libcore.dll 不存在" + Write-Host "当前 libcore\bin 目录内容:" + if (Test-Path "libcore\bin") { + Get-ChildItem "libcore\bin" | Format-Table Name, FullName, Length + } else { + Write-Host "libcore\bin 目录不存在" + } + exit 1 + } + + if (Test-Path "libcore\bin\BearVPNCli.exe") { + $exeInfo = Get-Item "libcore\bin\BearVPNCli.exe" + Write-Host "✅ BearVPNCli.exe 存在: $($exeInfo.FullName) - 大小: $($exeInfo.Length) bytes" + } else { + Write-Host "⚠️ BearVPNCli.exe 不存在" + } + shell: pwsh + + - name: 🔨 构建 Windows (Release) + run: | + flutter build windows --release + + - name: 🔍 验证 Windows 文件结构 + run: | + Write-Host "📋 检查 Release 目录文件结构..." + + $releaseDir = "build\windows\x64\runner\Release" + if (Test-Path $releaseDir) { + Write-Host "✅ Release 目录存在" + Write-Host "" + Write-Host "📄 文件列表:" + Get-ChildItem $releaseDir | Format-Table Name, Length, LastWriteTime + + # 检查关键文件 + if (Test-Path "$releaseDir\BearVPN.exe") { + Write-Host "✅ BearVPN.exe 存在" + } else { + Write-Host "❌ BearVPN.exe 不存在" + } + + if (Test-Path "$releaseDir\BearVPNCli.exe") { + Write-Host "✅ BearVPNCli.exe 存在" + } else { + Write-Host "⚠️ BearVPNCli.exe 不存在" + } + + if (Test-Path "$releaseDir\libcore.dll") { + Write-Host "✅ libcore.dll 存在" + } else { + Write-Host "❌ libcore.dll 不存在" + } + } else { + Write-Host "❌ Release 目录不存在" + } + shell: pwsh + + - name: 📦 打包 Windows + shell: bash + run: | + COMMIT_SHA=${GITHUB_SHA::7} + DATE=$(date '+%Y%m%d') + + cd build/windows/x64/runner/Release + 7z a -tzip "../../../../../BearVPN-windows-x64-release-${DATE}-${COMMIT_SHA}.zip" ./* + + - name: 📤 上传 Windows + uses: actions/upload-artifact@v4 + with: + name: windows-x64 + path: BearVPN-windows-*.zip + retention-days: 30 + + # ==================== macOS 构建 ==================== + build-macos: + name: 构建 macOS + needs: build-libcore-macos + runs-on: macos-latest + if: contains(inputs.platforms || 'macos', 'macos') + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.24.5' + channel: 'stable' + cache: true + + - name: 📥 下载 macOS libcore + uses: actions/download-artifact@v4 + with: + name: libcore-macos + path: libcore/bin/ + + - name: 🔧 设置 libcore 执行权限 + run: | + chmod +x libcore/bin/HiddifyCli + + - name: ⚙️ 配置 API、OSS 和加密密钥 + run: | + CONFIG_FILE="lib/app/common/app_config.dart" + API_DOMAIN="${{ inputs.api_domain || 'api.maodag.top' }}" + OSS_URL_1="${{ inputs.oss_url_1 || 'https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt' }}" + OSS_URL_2="${{ inputs.oss_url_2 || 'https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt' }}" + OSS_URL_3="${{ inputs.oss_url_3 || 'https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt' }}" + OSS_URL_4="${{ inputs.oss_url_4 || 'https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt' }}" + ENCRYPTION_KEY="${{ inputs.encryption_key || 'c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx' }}" + + # macOS 使用 BSD sed,转义特殊字符 + # 使用 perl 来转义特殊字符,更可靠 + ENCRYPTION_KEY_ESCAPED=$(echo "$ENCRYPTION_KEY" | perl -pe 's/([\[\].*^$()+?{|\\])/\\$1/g') + + echo "🔧 配置参数:" + echo " API: $API_DOMAIN" + echo " 密钥: ${ENCRYPTION_KEY:0:10}..." + + # macOS sed 需要使用 -i '' 和正确的语法 + sed -i '' "s|api\.maodag\.top|$API_DOMAIN|g" "$CONFIG_FILE" + sed -i '' "s|https://ppp2\.oss-cn-hongkong\.aliyuncs\.com/bear1\.txt|$OSS_URL_1|g" "$CONFIG_FILE" + sed -i '' "s|https://xgp3\.oss-ap-northeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_2|g" "$CONFIG_FILE" + sed -i '' "s|https://xpp4\.oss-ap-northeast-2\.aliyuncs\.com/bear1\.txt|$OSS_URL_3|g" "$CONFIG_FILE" + sed -i '' "s|https://xpp5\.oss-ap-southeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_4|g" "$CONFIG_FILE" + + # 使用不同的分隔符避免转义问题 + sed -i '' "s|c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx|$ENCRYPTION_KEY_ESCAPED|g" "$CONFIG_FILE" + + echo "✅ 配置完成" + + - name: 📦 安装 Flutter 依赖 + run: | + flutter pub get + flutter pub run build_runner build --delete-conflicting-outputs + + - name: 🔨 构建 macOS (Release) + run: | + flutter build macos --release + + - name: 📦 打包 macOS + run: | + COMMIT_SHA=${GITHUB_SHA::7} + DATE=$(date '+%Y%m%d') + + cd build/macos/Build/Products/Release + zip -r -y "../../../../../BearVPN-macos-release-${DATE}-${COMMIT_SHA}.zip" BearVPN.app + + - name: 📤 上传 macOS + uses: actions/upload-artifact@v4 + with: + name: macos-app + path: BearVPN-macos-*.zip + retention-days: 30 + + # ==================== Linux 构建 ==================== + build-linux: + name: 构建 Linux + needs: build-libcore-linux + runs-on: ubuntu-latest + if: contains(inputs.platforms || 'linux', 'linux') + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 安装 Linux 依赖 + run: | + sudo apt-get update + sudo apt-get install -y \ + clang \ + cmake \ + ninja-build \ + pkg-config \ + libgtk-3-dev \ + liblzma-dev \ + libstdc++-12-dev \ + libayatana-appindicator3-dev + + - name: 🔧 设置 Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.24.5' + channel: 'stable' + cache: true + + - name: 📥 下载 Linux libcore + uses: actions/download-artifact@v4 + with: + name: libcore-linux + path: libcore/bin/ + + - name: 🔧 设置 libcore 执行权限 + run: | + chmod +x libcore/bin/HiddifyCli + + - name: ⚙️ 配置 API、OSS 和加密密钥 + run: | + CONFIG_FILE="lib/app/common/app_config.dart" + API_DOMAIN="${{ inputs.api_domain || 'api.maodag.top' }}" + OSS_URL_1="${{ inputs.oss_url_1 || 'https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt' }}" + OSS_URL_2="${{ inputs.oss_url_2 || 'https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt' }}" + OSS_URL_3="${{ inputs.oss_url_3 || 'https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt' }}" + OSS_URL_4="${{ inputs.oss_url_4 || 'https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt' }}" + ENCRYPTION_KEY="${{ inputs.encryption_key || 'c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx' }}" + + ENCRYPTION_KEY_ESCAPED=$(echo "$ENCRYPTION_KEY" | perl -pe 's/([\[\].*^$()+?{|\\])/\\$1/g') + + sed -i "s|api\.maodag\.top|$API_DOMAIN|g" "$CONFIG_FILE" + sed -i "s|https://ppp2\.oss-cn-hongkong\.aliyuncs\.com/bear1\.txt|$OSS_URL_1|g" "$CONFIG_FILE" + sed -i "s|https://xgp3\.oss-ap-northeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_2|g" "$CONFIG_FILE" + sed -i "s|https://xpp4\.oss-ap-northeast-2\.aliyuncs\.com/bear1\.txt|$OSS_URL_3|g" "$CONFIG_FILE" + sed -i "s|https://xpp5\.oss-ap-southeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_4|g" "$CONFIG_FILE" + sed -i "s|c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx|$ENCRYPTION_KEY_ESCAPED|g" "$CONFIG_FILE" + + - name: 📦 安装 Flutter 依赖 + run: | + flutter pub get + flutter pub run build_runner build --delete-conflicting-outputs + + - name: 🔨 构建 Linux (Release) + run: | + flutter build linux --release + + - name: 📦 打包 Linux + run: | + COMMIT_SHA=${GITHUB_SHA::7} + DATE=$(date '+%Y%m%d') + + cd build/linux/x64/release/bundle + tar -czf "../../../../../BearVPN-linux-x64-release-${DATE}-${COMMIT_SHA}.tar.gz" ./* + + - name: 📤 上传 Linux + uses: actions/upload-artifact@v4 + with: + name: linux-x64 + path: BearVPN-linux-*.tar.gz + retention-days: 30 + + # ==================== iOS 构建 ==================== + build-ios: + name: 构建 iOS + needs: build-libcore-ios + runs-on: macos-latest + if: contains(inputs.platforms || 'ios', 'ios') + + steps: + - name: 📥 Checkout 代码 + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: 🔧 设置 Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.24.5' + channel: 'stable' + cache: true + + - name: 📥 下载 iOS libcore + uses: actions/download-artifact@v4 + with: + name: libcore-ios + path: ios/Frameworks/ + + - name: ⚙️ 配置 API、OSS 和加密密钥 + run: | + CONFIG_FILE="lib/app/common/app_config.dart" + API_DOMAIN="${{ inputs.api_domain || 'api.maodag.top' }}" + OSS_URL_1="${{ inputs.oss_url_1 || 'https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt' }}" + OSS_URL_2="${{ inputs.oss_url_2 || 'https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt' }}" + OSS_URL_3="${{ inputs.oss_url_3 || 'https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt' }}" + OSS_URL_4="${{ inputs.oss_url_4 || 'https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt' }}" + ENCRYPTION_KEY="${{ inputs.encryption_key || 'c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx' }}" + + # 使用 perl 转义特殊字符 + ENCRYPTION_KEY_ESCAPED=$(echo "$ENCRYPTION_KEY" | perl -pe 's/([\[\].*^$()+?{|\\])/\\$1/g') + + sed -i '' "s|api\.maodag\.top|$API_DOMAIN|g" "$CONFIG_FILE" + sed -i '' "s|https://ppp2\.oss-cn-hongkong\.aliyuncs\.com/bear1\.txt|$OSS_URL_1|g" "$CONFIG_FILE" + sed -i '' "s|https://xgp3\.oss-ap-northeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_2|g" "$CONFIG_FILE" + sed -i '' "s|https://xpp4\.oss-ap-northeast-2\.aliyuncs\.com/bear1\.txt|$OSS_URL_3|g" "$CONFIG_FILE" + sed -i '' "s|https://xpp5\.oss-ap-southeast-1\.aliyuncs\.com/bear1\.txt|$OSS_URL_4|g" "$CONFIG_FILE" + sed -i '' "s|c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx|$ENCRYPTION_KEY_ESCAPED|g" "$CONFIG_FILE" + + - name: 📦 安装 Flutter 依赖 + run: | + flutter pub get + flutter pub run build_runner build --delete-conflicting-outputs + + - name: 🔨 构建 iOS (Release) + run: | + flutter build ios --release --no-codesign + + - name: 📦 打包 iOS + run: | + COMMIT_SHA=${GITHUB_SHA::7} + DATE=$(date '+%Y%m%d') + + cd build/ios/iphoneos + + # 创建 Payload 目录 + mkdir -p Payload + cp -r Runner.app Payload/ + + # 创建 IPA 文件 + zip -r "../../../../BearVPN-ios-release-${DATE}-${COMMIT_SHA}.ipa" Payload + + echo "✅ iOS IPA 创建完成" + ls -lh BearVPN-ios-*.ipa + + - name: 📤 上传 iOS + uses: actions/upload-artifact@v4 + with: + name: ios-app + path: BearVPN-ios-*.ipa + retention-days: 30 + + # ==================== 创建 Release ==================== + create-release: + name: 创建 Release + needs: [build-android, build-windows, build-macos, build-linux, build-ios] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + + steps: + - name: 📥 下载所有构建产物 + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: 📋 生成 Release 说明 + id: release_notes + run: | + cat > release_notes.md << 'EOF' + ## 🎉 BearVPN 多平台版本发布 + + ### 📦 平台支持 + + | 平台 | 架构 | 文件 | + |-----|------|-----| + | **Android** | arm64-v8a | BearVPN-android-arm64-v8a-*.apk | + | **Android** | armeabi-v7a | BearVPN-android-armeabi-v7a-*.apk | + | **Android** | x86_64 | BearVPN-android-x86_64-*.apk | + | **iOS** | Universal | BearVPN-ios-*.ipa | + | **Windows** | x64 | BearVPN-windows-x64-*.zip | + | **macOS** | Universal | BearVPN-macos-*.zip | + | **Linux** | x64 | BearVPN-linux-x64-*.tar.gz | + + ### ✨ 主要特性 + + - ✅ 支持 Shadowsocks/VLESS/Trojan/Hysteria2 + - ✅ 内置 sing-box 核心 v3.1.7 + - ✅ 跨平台支持 + - ✅ 自定义路由规则 + + ### 📥 安装指南 + + **Android:** 下载 APK 直接安装 + **iOS:** 下载 IPA 使用 AltStore/Sideloadly 安装 + **Windows:** 解压 ZIP 运行 BearVPN.exe + **macOS:** 解压 ZIP 拖拽到应用程序 + **Linux:** 解压 tar.gz 运行可执行文件 + + --- + + **构建信息:** + - 提交: ${GITHUB_SHA::7} + - 时间: $(date '+%Y-%m-%d %H:%M:%S UTC') + - Flutter: 3.24.5 + - sing-box: v3.1.7 + EOF + + echo "release_notes<> $GITHUB_OUTPUT + cat release_notes.md >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: 🚀 创建 Release + uses: softprops/action-gh-release@v2 + with: + files: | + artifacts/android-apk/*.apk + artifacts/ios-app/*.ipa + artifacts/windows-x64/*.zip + artifacts/macos-app/*.zip + artifacts/linux-x64/*.tar.gz + body: ${{ steps.release_notes.outputs.release_notes }} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: 📢 构建完成 + run: | + echo "✅ 所有平台构建完成!" + echo "📦 Release: ${{ github.ref }}" + echo "🔗 https://github.com/${{ github.repository }}/releases"