ci: 添加多平台构建工作流
Some checks failed
Build Android APK / 编译 Android APK (release) (push) Has been skipped
Build Clash Core / Build Android (arm64) (push) Failing after 7s
Build Multi-Platform / 编译 libcore (iOS/tvOS) (push) Has been skipped
Build Android APK / 编译 libcore.aar (push) Failing after 10s
Build Clash Core / Build Android (armv7) (push) Failing after 7s
Build Clash Core / Build Android (x86_64) (push) Failing after 8s
Build Clash Core / Create Release (push) Has been skipped
Build Multi-Platform / 编译 libcore (Android) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Windows) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (macOS) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Linux) (push) Has been cancelled
Build Multi-Platform / 构建 Android APK (push) Has been cancelled
Build Multi-Platform / 构建 macOS (push) Has been cancelled
Build Multi-Platform / 构建 Linux (push) Has been cancelled
Build Multi-Platform / 构建 iOS (push) Has been cancelled
Build Multi-Platform / 构建 Windows (push) Has been skipped
Build Android APK / 创建 GitHub Release (push) Has been cancelled
Build Multi-Platform / 创建 Release (push) Has been cancelled

添加三个 GitHub Actions 工作流文件:
1. build-clash-core.yml - 构建 Android 核心库
2. build-android-apk.yml - 构建 Android APK
3. build-multiplatform.yml - 支持多平台构建(Android/iOS/Windows/macOS/Linux)

工作流支持自动触发和手动触发,包含构建、测试、打包和发布功能
This commit is contained in:
shanshanzhong 2025-11-06 17:27:25 -08:00
parent 2eaa15cc8f
commit 6dfad4544d
3 changed files with 1411 additions and 0 deletions

319
.github/workflows/build-android-apk.yml vendored Normal file
View File

@ -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<<EOF" >> $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"

142
.github/workflows/build-clash-core.yml vendored Normal file
View File

@ -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 }}

View File

@ -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<<EOF" >> $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"