Compare commits
175 Commits
7a223d614b
...
re-main
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f429e5546 | |||
| 9563a81a6e | |||
| 3c0f1084b0 | |||
| c42bddb129 | |||
| 18e932e738 | |||
| 7740b46fa6 | |||
| 83d201b78d | |||
| 4f09267b4b | |||
| 8f347d9183 | |||
| 554d12193e | |||
| 801a77f942 | |||
| 05d2c71cd0 | |||
| 743631c4ce | |||
| 60de644637 | |||
| f888b772c2 | |||
| f70b32ec3f | |||
| ca913eb38f | |||
| dc5a5fc78a | |||
| 17860e333c | |||
| d63b3bfc3c | |||
| 4f6be35f61 | |||
| 56c7fd6921 | |||
| 24cf03d6ce | |||
| 5bd77511cc | |||
| 33b9cd34f1 | |||
| c87d5d4d38 | |||
| ce4abb7e01 | |||
| dbcdf8b8a4 | |||
| e82480b937 | |||
| 8e27ddeded | |||
| 961d419c4d | |||
| aa0fd94cb2 | |||
| 86687cac58 | |||
| 1b1b38aba5 | |||
| beae70edb7 | |||
| d2ea8436f9 | |||
| 95f8f3afbe | |||
| a17fa079bc | |||
| 9302764802 | |||
| c058c2cea6 | |||
| 55d7508807 | |||
| adcde623c7 | |||
| 83e742a9dc | |||
| 569f9f6d05 | |||
| 4fdf4da4f3 | |||
| b059d01556 | |||
| 909020654f | |||
| 1809c11473 | |||
| 343bb50c77 | |||
| 11afee1d6f | |||
| 96d1a107cf | |||
| 52f241a5a7 | |||
| 5dfb2b7432 | |||
| 85dc810421 | |||
| ee3fdd91fa | |||
| e537775e71 | |||
| f97a21be32 | |||
| d3f48e345e | |||
| ac8a04fd24 | |||
| a7df3a44a2 | |||
| 7956349c0a | |||
| becc03acfd | |||
| 9123d5f0e4 | |||
| 91185a593a | |||
| d6386ecfa9 | |||
| 62d1af8517 | |||
| 3b05d4ff72 | |||
| bcb4d17236 | |||
| d99f588a5b | |||
| 691dd6e1d6 | |||
| b442289b8a | |||
| 89d13e6237 | |||
| 8fd742a688 | |||
| 325a63d35f | |||
| 679c303457 | |||
| 59aa67d456 | |||
| 2a1ee3018d | |||
| 76e83e0135 | |||
| 89d6ec3c76 | |||
| 670eb7ebc9 | |||
| 46295f4543 | |||
| a47174df56 | |||
| 748ec6bee9 | |||
| a884e6c838 | |||
| 920b86e56a | |||
| a78b40c339 | |||
| 8ccfc6d272 | |||
| f526122f33 | |||
| b86d645acf | |||
| ef1f3bfb50 | |||
| 33917e774d | |||
| 78c20f9ae9 | |||
| 610eb4f20d | |||
| 8cc88be5f6 | |||
| 50f4237c74 | |||
| deac0adabd | |||
| 4f9d405c9f | |||
| 88091e84c0 | |||
| fafad1ff97 | |||
| fbcf5f7e61 | |||
| b21d189ca1 | |||
| 701acd561a | |||
| 3b419d1e24 | |||
| e3b9fea5b2 | |||
| 54dd4cbd35 | |||
| 77b721df4b | |||
| 8937024241 | |||
| 29c6e40940 | |||
| f75b109025 | |||
| eb4db67fa1 | |||
| 62d3157665 | |||
| 577327c40a | |||
| fed0b0e422 | |||
| ad5d0c9b7a | |||
| 9873f670fa | |||
| 8b8d29dd00 | |||
| 477d4086b2 | |||
| 7fc2a60e18 | |||
| 41e6ed433a | |||
| 8b055d9ee1 | |||
| 0808e2db10 | |||
| dcc9ad43fe | |||
| b47e0e984e | |||
| 51ed02de1a | |||
| e0b1cec87d | |||
| a9db68c29b | |||
| db7a776d2b | |||
| bfa3ec48d6 | |||
| ca74f9289e | |||
| f9ea310031 | |||
| 5d849c3b98 | |||
| b7be97f6c1 | |||
| 7212fd3132 | |||
| 067a715afe | |||
| ce969a6ad4 | |||
| cea406f660 | |||
| a09245cb3e | |||
| bbc1c03cca | |||
| b3935f8516 | |||
| 14b95b07b4 | |||
| 0e1c043e34 | |||
| cc5a732fa5 | |||
| 0e9d1bc157 | |||
| 6dfad4544d | |||
| 2eaa15cc8f | |||
| 5c1449155e | |||
| cc8744a188 | |||
| f72ffa6443 | |||
| 5e84fea7d0 | |||
| dce32e706b | |||
| 7e19e2cdb8 | |||
| 0e062a275a | |||
| 4cc3f98b0f | |||
| a6527d822b | |||
| aac7d84602 | |||
| f738ba9245 | |||
| 89e02cc707 | |||
| d1e45f0254 | |||
| dbf6175ad9 | |||
| 251564a5de | |||
| ef8bba71d5 | |||
| 961c655a92 | |||
| 4389770821 | |||
| 7c9b23edbd | |||
| 90fd476c45 | |||
| 7cd360e61e | |||
| 6e189671c7 | |||
| 4fbdb331d4 | |||
| 6131a80b2c | |||
| 33f45aa4a5 | |||
| 4dbcaff187 | |||
| 9e05a17fc4 | |||
| 1a9f0d79ac | |||
| c7b77c1ad8 | |||
| 7cd022093b |
@@ -0,0 +1,434 @@
|
||||
name: Build Windows
|
||||
run-name: 构建Win流程
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
# 先编译 libcore
|
||||
build-libcore:
|
||||
name: 编译 libcore (Windows)
|
||||
runs-on: client-server
|
||||
container:
|
||||
image: node:20
|
||||
strategy:
|
||||
matrix:
|
||||
# 只有node支持版本号别名
|
||||
node: ['20.15.1']
|
||||
|
||||
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: 🔧 安装 MinGW
|
||||
run: |
|
||||
# 在 GitHub 托管 runner(有 sudo)与 act/自托管容器(无 sudo)均可运行
|
||||
if command -v sudo >/dev/null 2>&1; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y mingw-w64
|
||||
else
|
||||
echo "sudo 不存在,按 root 用户直接执行 apt-get"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update || apt update
|
||||
apt-get install -y mingw-w64 || apt install -y mingw-w64
|
||||
fi
|
||||
|
||||
- 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/
|
||||
else
|
||||
echo "❌ Windows libcore 编译失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 📤 上传 Windows libcore
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: libcore-windows
|
||||
path: |
|
||||
libcore/bin/libcore.dll
|
||||
libcore/bin/HiddifyCli.exe
|
||||
libcore/bin/webui/**
|
||||
retention-days: 7
|
||||
|
||||
|
||||
# 构建 Windows 应用
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
needs: build-libcore
|
||||
steps:
|
||||
- name: 🔧 Add Git to PATH (Windows)
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
shell: powershell
|
||||
run: |
|
||||
$paths = @(
|
||||
'C:\Program Files\Git\cmd',
|
||||
'C:\Program Files\Git\bin',
|
||||
'C:\Program Files (x86)\Git\cmd',
|
||||
'C:\Program Files (x86)\Git\bin'
|
||||
)
|
||||
foreach ($p in $paths) {
|
||||
if (Test-Path $p) {
|
||||
Add-Content -Path $env:GITHUB_PATH -Value $p
|
||||
$env:PATH = "$p;$env:PATH"
|
||||
Write-Host ("Added to PATH: {0}" -f $p)
|
||||
}
|
||||
}
|
||||
$candidates = @(
|
||||
'C:\Program Files\Git\cmd\git.exe',
|
||||
'C:\Program Files\Git\bin\git.exe',
|
||||
'C:\Program Files (x86)\Git\cmd\git.exe',
|
||||
'C:\Program Files (x86)\Git\bin\git.exe'
|
||||
)
|
||||
$found = $false
|
||||
foreach ($g in $candidates) {
|
||||
if (Test-Path $g) {
|
||||
& $g --version
|
||||
$found = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (-not $found) {
|
||||
Write-Host "Git executable not found in common locations; continuing."
|
||||
}
|
||||
|
||||
- name: 📥 Checkout 代码
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 📥 下载 libcore
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: libcore-windows
|
||||
path: .
|
||||
|
||||
- name: 🔧 复制 libcore 文件到正确位置并重命名
|
||||
shell: cmd
|
||||
run: call copy_libcore.bat
|
||||
|
||||
- name: 🔍 Verify jq Installation (ACT)
|
||||
shell: powershell
|
||||
run: |
|
||||
# Check if jq is available
|
||||
$jqFound = $false
|
||||
try {
|
||||
$version = jq --version 2>&1
|
||||
if ($version -match 'jq-[\d\.]+') {
|
||||
Write-Host "jq is already installed: $version"
|
||||
$jqFound = $true
|
||||
}
|
||||
} catch {
|
||||
Write-Host "jq not installed or not in PATH"
|
||||
}
|
||||
if (-not $jqFound) {
|
||||
Write-Host "Preparing to install jq..."
|
||||
# Check if Chocolatey is available
|
||||
$chocoFound = $false
|
||||
try {
|
||||
choco --version 2>&1 | Out-Null
|
||||
$chocoFound = $true
|
||||
} catch {}
|
||||
if (-not $chocoFound) {
|
||||
Write-Host "Installing Chocolatey..."
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
|
||||
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
||||
# Refresh PATH
|
||||
$env:PATH = [System.Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('PATH', 'User')
|
||||
Write-Host "Chocolatey installed successfully"
|
||||
}
|
||||
Write-Host "Installing jq using Chocolatey..."
|
||||
choco install jq -y
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "jq installed successfully"
|
||||
# Verify again
|
||||
$version = jq --version 2>&1
|
||||
Write-Host "jq version: $version"
|
||||
} else {
|
||||
Write-Host "jq installation failed, exit code: $LASTEXITCODE"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
- name: Add jq to PATH
|
||||
shell: powershell
|
||||
run: |
|
||||
$jqPath = "C:\ProgramData\chocolatey\bin"
|
||||
if (Test-Path $jqPath) {
|
||||
Add-Content -Path $env:GITHUB_PATH -Value $jqPath
|
||||
$env:PATH = "$jqPath;$env:PATH"
|
||||
Write-Host "Added jq path to GITHUB_PATH and current PATH"
|
||||
} else {
|
||||
Write-Host "jq installation path not found"
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Add Flutter to PATH
|
||||
shell: powershell
|
||||
run: |
|
||||
# Add Flutter to PATH for current session and GitHub Actions
|
||||
$flutterPath = "C:\flutter\bin"
|
||||
if (Test-Path $flutterPath) {
|
||||
Write-Host "Adding Flutter to PATH: $flutterPath"
|
||||
$env:PATH = "$flutterPath;$env:PATH"
|
||||
Add-Content -Path $env:GITHUB_PATH -Value $flutterPath
|
||||
|
||||
# Verify Flutter is accessible
|
||||
$flutterVersion = flutter --version 2>&1
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "Flutter verified: $flutterVersion"
|
||||
} else {
|
||||
Write-Host "Flutter not found at $flutterPath"
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Host "ERROR: Flutter not found at C:\flutter\bin"
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Enable Windows desktop
|
||||
shell: powershell
|
||||
run: |
|
||||
$env:PATH = "C:\flutter\bin;$env:PATH"
|
||||
flutter config --enable-windows-desktop
|
||||
|
||||
- name: Get dependencies
|
||||
shell: powershell
|
||||
run: |
|
||||
$env:PATH = "C:\flutter\bin;$env:PATH"
|
||||
flutter pub get
|
||||
|
||||
- name: Generate code
|
||||
shell: powershell
|
||||
run: |
|
||||
$env:PATH = "C:\flutter\bin;$env:PATH"
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
- name: Install NuGet
|
||||
shell: powershell
|
||||
run: |
|
||||
Write-Host "Installing NuGet..."
|
||||
|
||||
# Check if NuGet is already available
|
||||
$nugetPath = Get-Command nuget -ErrorAction SilentlyContinue
|
||||
if ($nugetPath) {
|
||||
Write-Host "NuGet already installed: $($nugetPath.Source)"
|
||||
$nugetVersion = nuget help | Select-String -Pattern "NuGet Version" | Select-Object -First 1
|
||||
Write-Host "NuGet version: $nugetVersion"
|
||||
return
|
||||
}
|
||||
|
||||
# Use Chocolatey to install NuGet (proven to work)
|
||||
Write-Host "Installing NuGet via Chocolatey..."
|
||||
choco install nuget.commandline -y
|
||||
|
||||
# Update PATH to include Chocolatey
|
||||
$env:PATH = "C:\ProgramData\chocolatey\bin;$env:PATH"
|
||||
Add-Content -Path $env:GITHUB_PATH -Value "C:\ProgramData\chocolatey\bin"
|
||||
|
||||
# Verify installation
|
||||
if (Get-Command nuget -ErrorAction SilentlyContinue) {
|
||||
Write-Host "NuGet installed successfully via Chocolatey"
|
||||
$nugetVersion = nuget help | Select-String -Pattern "NuGet Version" | Select-Object -First 1
|
||||
Write-Host "NuGet version: $nugetVersion"
|
||||
} else {
|
||||
Write-Host "WARNING: NuGet installation may have failed, but continuing..."
|
||||
}
|
||||
|
||||
- name: Fix long paths
|
||||
shell: powershell
|
||||
run: |
|
||||
Write-Host "Enabling long path support..."
|
||||
|
||||
# Enable long paths in Windows
|
||||
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -Type DWORD -Force
|
||||
|
||||
# Also set for current user
|
||||
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\AppModel\StateRepository\Cache\Package\Data\" -Name "LongPathsEnabled" -Value 1 -Type DWORD -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "Long path support enabled"
|
||||
|
||||
- name: Clean build cache
|
||||
shell: powershell
|
||||
run: |
|
||||
$env:PATH = "C:\flutter\bin;$env:PATH"
|
||||
Write-Host "Cleaning build cache..."
|
||||
flutter clean
|
||||
|
||||
Write-Host "Removing old build directories..."
|
||||
if (Test-Path "build") {
|
||||
Remove-Item -Path "build" -Recurse -Force
|
||||
}
|
||||
if (Test-Path "windows") {
|
||||
Remove-Item -Path "windows" -Recurse -Force
|
||||
}
|
||||
|
||||
Write-Host "Recreating Windows project..."
|
||||
flutter create --platforms=windows .
|
||||
|
||||
- name: Build Windows Debug
|
||||
shell: powershell
|
||||
run: |
|
||||
$env:PATH = "C:\flutter\bin;C:\ProgramData\chocolatey\bin;$env:PATH"
|
||||
flutter build windows
|
||||
|
||||
- name: Build Windows Release
|
||||
shell: powershell
|
||||
run: |
|
||||
$env:PATH = "C:\flutter\bin;C:\ProgramData\chocolatey\bin;$env:PATH"
|
||||
flutter build windows --release
|
||||
|
||||
- name: Upload Debug build artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-debug-build
|
||||
path: build/windows/x64/runner/Debug/
|
||||
|
||||
- name: Upload Release build artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-release-build
|
||||
path: build/windows/x64/runner/Release/
|
||||
|
||||
- name: Install Build Tools
|
||||
shell: powershell
|
||||
run: |
|
||||
choco install 7zip -y
|
||||
choco install enigma-virtual-box -y
|
||||
|
||||
- name: Package Single EXE
|
||||
shell: powershell
|
||||
run: |
|
||||
Write-Host "=== 开始打包单文件 EXE ==="
|
||||
|
||||
$buildPath = "build\windows\x64\runner\Release"
|
||||
$outputPath = "dist"
|
||||
$enigmaPath = "C:\Program Files\Enigma Virtual Box\enigmavb.exe"
|
||||
|
||||
# 创建输出目录
|
||||
if (-not (Test-Path $outputPath)) {
|
||||
New-Item -ItemType Directory -Path $outputPath -Force | Out-Null
|
||||
}
|
||||
|
||||
# 获取主程序
|
||||
$exeFile = Get-ChildItem -Path $buildPath -Filter "*.exe" | Select-Object -First 1
|
||||
if (-not $exeFile) {
|
||||
Write-Host "❌ 未找到可执行文件"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$inputExe = $exeFile.FullName
|
||||
$outputExe = "$outputPath\$($exeFile.BaseName)_Single.exe"
|
||||
|
||||
Write-Host "主程序: $inputExe"
|
||||
Write-Host "输出: $outputExe"
|
||||
|
||||
# 尝试使用 Enigma Virtual Box
|
||||
if (Test-Path $enigmaPath) {
|
||||
Write-Host "使用 Enigma Virtual Box 打包..."
|
||||
|
||||
# 创建配置文件
|
||||
$configContent = "[Config]`nInputFile=$inputExe`nOutputFile=$outputExe`nFiles=%DEFAULT FOLDER%`nVirtualizationMode=Never Write To Disk`nCompression=Yes`nShareVirtualSystem=Yes`n`n[Files]`nFolder=$buildPath\*"
|
||||
|
||||
$configFile = "$outputPath\package_config.evb"
|
||||
Set-Content -Path $configFile -Value $configContent
|
||||
|
||||
# 执行打包
|
||||
$process = Start-Process -FilePath $enigmaPath -ArgumentList "/sf", $inputExe, "/lf", $outputExe, "/folder", $buildPath, "/compress" -Wait -PassThru -NoNewWindow
|
||||
|
||||
if ($process.ExitCode -eq 0) {
|
||||
Write-Host "✅ 单文件打包成功!"
|
||||
|
||||
# 显示压缩信息
|
||||
$originalSize = (Get-Item $inputExe).Length / 1MB
|
||||
$packedSize = (Get-Item $outputExe).Length / 1MB
|
||||
Write-Host "原始大小: $([math]::Round($originalSize, 2)) MB"
|
||||
Write-Host "打包大小: $([math]::Round($packedSize, 2)) MB"
|
||||
} else {
|
||||
Write-Host "⚠️ Enigma 打包失败,使用备选方案"
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Host "⚠️ Enigma 未找到,使用 7-Zip 自解压方案"
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Package with 7-Zip Alternative
|
||||
if: failure()
|
||||
shell: powershell
|
||||
run: |
|
||||
Write-Host "使用 7-Zip 自解压方案..."
|
||||
|
||||
$buildPath = "build\windows\x64\runner\Release"
|
||||
$outputPath = "dist"
|
||||
|
||||
# 检查 7-Zip
|
||||
$7zipPath = "C:\Program Files\7-Zip\7z.exe"
|
||||
|
||||
# 获取主程序名称
|
||||
$exeFile = Get-ChildItem -Path $buildPath -Filter "*.exe" | Select-Object -First 1
|
||||
$outputSfx = "$outputPath\$($exeFile.BaseName)_Package.exe"
|
||||
|
||||
Write-Host "创建自解压包..."
|
||||
|
||||
# 创建配置文件
|
||||
$configContent = @"
|
||||
;!@Install@!UTF-8!
|
||||
Title="HostExecutor Windows Package"
|
||||
BeginPrompt="正在解压 HostExecutor..."
|
||||
ExtractDialogText="请稍候,正在解压文件..."
|
||||
ExtractPathText="解压路径:"
|
||||
ExtractTitle="解压中"
|
||||
FinishMessage="解压完成!"
|
||||
GUIFlags="8"
|
||||
;!@InstallEnd@!
|
||||
"@
|
||||
|
||||
$configFile = "$outputPath\config.txt"
|
||||
Set-Content -Path $configFile -Value $configContent -Encoding UTF8
|
||||
|
||||
# 创建压缩包
|
||||
& $7zipPath a -sfx7z.sfx -r "$outputSfx" "$buildPath\*" -scsUTF-8 -y
|
||||
Copy-Item "$configFile" -Destination "$outputSfx" -Force
|
||||
|
||||
if (Test-Path $outputSfx) {
|
||||
Write-Host "✅ 7-Zip 自解压包创建成功!"
|
||||
Write-Host "输出文件: $outputSfx"
|
||||
|
||||
$size = (Get-Item $outputSfx).Length / 1MB
|
||||
Write-Host "文件大小: $([math]::Round($size, 2)) MB"
|
||||
} else {
|
||||
Write-Host "❌ 7-Zip 打包失败"
|
||||
}
|
||||
|
||||
- name: Upload Single EXE Package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-single-exe
|
||||
path: dist/*.exe
|
||||
if: always()
|
||||
@@ -1,311 +0,0 @@
|
||||
# 📖 GitHub Actions 构建完全指南
|
||||
|
||||
## 🎯 功能概述
|
||||
|
||||
本 workflow 支持:
|
||||
|
||||
✅ **自动编译 libcore.aar** - sing-box 核心库
|
||||
✅ **Release 构建** - 默认生成正式版 APK
|
||||
✅ **可配置 API 域名** - 支持自定义后端域名
|
||||
✅ **可配置 OSS 地址** - 支持自定义配置文件 CDN
|
||||
✅ **分架构打包** - 生成 arm64-v8a / armeabi-v7a / x86_64 版本
|
||||
✅ **自动创建 Release** - 推送标签自动发布
|
||||
|
||||
---
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
### 方法一:手动触发(推荐,支持自定义配置)
|
||||
|
||||
1. **打开 Actions 页面**
|
||||
- 进入 GitHub 仓库
|
||||
- 点击顶部 **Actions** 标签
|
||||
|
||||
2. **选择 Workflow**
|
||||
- 左侧选择 **Build Android APK**
|
||||
- 右侧点击 **Run workflow** 下拉框
|
||||
|
||||
3. **配置参数**
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
|-----|------|--------|
|
||||
| **构建类型** | debug 或 release | `release` |
|
||||
| **API 域名** | 后端 API 服务器域名 | `api.maodag.top` |
|
||||
| **OSS 地址 1** | 配置文件 CDN 地址(香港) | `https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt` |
|
||||
| **OSS 地址 2** | 配置文件 CDN 地址(东京) | `https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt` |
|
||||
| **OSS 地址 3** | 配置文件 CDN 地址(首尔) | `https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt` |
|
||||
| **OSS 地址 4** | 配置文件 CDN 地址(新加坡) | `https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt` |
|
||||
|
||||
4. **开始构建**
|
||||
- 点击绿色 **Run workflow** 按钮
|
||||
- 等待约 30 分钟完成
|
||||
|
||||
5. **下载 APK**
|
||||
- 构建完成后,在运行记录页面找到 **Artifacts** 区域
|
||||
- 下载对应架构的 APK
|
||||
|
||||
---
|
||||
|
||||
### 方法二:推送代码自动构建(使用默认配置)
|
||||
|
||||
```bash
|
||||
# 提交代码
|
||||
git add .
|
||||
git commit -m "feat: 新功能"
|
||||
|
||||
# 推送到 main 分支
|
||||
git push origin main
|
||||
```
|
||||
|
||||
**注意:** 自动触发的构建使用默认配置(`api.maodag.top` 和默认 OSS 地址)
|
||||
|
||||
---
|
||||
|
||||
### 方法三:创建 Release 版本
|
||||
|
||||
```bash
|
||||
# 1. 打标签(必须以 v 开头)
|
||||
git tag v1.0.0
|
||||
|
||||
# 2. 推送标签
|
||||
git push origin v1.0.0
|
||||
|
||||
# 3. 自动触发构建并创建 Release
|
||||
# 访问 https://github.com/你的用户名/LighthouseApp/releases 查看
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 构建产物
|
||||
|
||||
### APK 命名规则
|
||||
|
||||
```
|
||||
BearVPN-{架构}-{类型}-{日期}-{提交哈希}.apk
|
||||
```
|
||||
|
||||
**示例:**
|
||||
```
|
||||
BearVPN-arm64-v8a-release-20251027-abc1234.apk
|
||||
BearVPN-armeabi-v7a-release-20251027-abc1234.apk
|
||||
BearVPN-x86_64-release-20251027-abc1234.apk
|
||||
```
|
||||
|
||||
### 架构说明
|
||||
|
||||
| 架构 | 适用设备 | 推荐度 |
|
||||
|------|---------|-------|
|
||||
| **arm64-v8a** | 2017年后的现代手机 | ⭐⭐⭐⭐⭐ |
|
||||
| **armeabi-v7a** | 2012-2017年的老旧手机 | ⭐⭐ |
|
||||
| **x86_64** | Android 模拟器 | ⭐⭐⭐ |
|
||||
|
||||
**大多数用户应下载 `arm64-v8a` 版本**
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置示例
|
||||
|
||||
### 示例 1:修改 API 域名
|
||||
|
||||
如果你的后端部署在 `api.example.com`:
|
||||
|
||||
1. 手动触发 workflow
|
||||
2. 将 **API 域名** 改为 `api.example.com`
|
||||
3. OSS 地址保持默认
|
||||
4. 点击 Run workflow
|
||||
|
||||
### 示例 2:使用自己的 CDN
|
||||
|
||||
如果你有自己的配置文件 CDN:
|
||||
|
||||
1. 手动触发 workflow
|
||||
2. API 域名保持默认
|
||||
3. 修改 **OSS 地址 1-4** 为你的 CDN 地址,例如:
|
||||
- OSS 地址 1: `https://cdn1.example.com/config.txt`
|
||||
- OSS 地址 2: `https://cdn2.example.com/config.txt`
|
||||
- OSS 地址 3: `https://cdn3.example.com/config.txt`
|
||||
- OSS 地址 4: `https://cdn4.example.com/config.txt`
|
||||
4. 点击 Run workflow
|
||||
|
||||
### 示例 3:完全自定义配置
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
API 域名: api.mycompany.com
|
||||
OSS 地址 1: https://config.mycdn.com/v1/nodes.txt
|
||||
OSS 地址 2: https://backup1.mycdn.com/v1/nodes.txt
|
||||
OSS 地址 3: https://backup2.mycdn.com/v1/nodes.txt
|
||||
OSS 地址 4: https://backup3.mycdn.com/v1/nodes.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间
|
||||
|
||||
| 阶段 | 时间 |
|
||||
|-----|------|
|
||||
| 编译 libcore.aar | 10-15 分钟 |
|
||||
| 编译 Flutter APK | 15-20 分钟 |
|
||||
| **总计** | **约 30 分钟** |
|
||||
|
||||
---
|
||||
|
||||
## 🔍 查看构建日志
|
||||
|
||||
1. 打开 Actions 页面
|
||||
2. 点击对应的运行记录
|
||||
3. 点击具体的 job(如 "编译 Android APK")
|
||||
4. 展开步骤查看详细日志
|
||||
|
||||
**关键步骤:**
|
||||
- `⚙️ 配置 API 域名和 OSS 地址` - 查看配置是否正确替换
|
||||
- `🔨 构建 APK` - 查看编译过程
|
||||
- `📦 重命名 APK 文件` - 查看生成的文件名和 MD5
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q1: 如何验证配置是否生效?
|
||||
|
||||
**A:** 查看 `⚙️ 配置 API 域名和 OSS 地址` 步骤的日志:
|
||||
|
||||
```
|
||||
🔧 配置构建参数:
|
||||
API 域名: api.example.com
|
||||
OSS 地址 1: https://cdn1.example.com/config.txt
|
||||
...
|
||||
|
||||
✅ 配置替换完成
|
||||
|
||||
📄 查看修改后的配置:
|
||||
static List<String> kr_baseDomains = ["api.example.com","api.example.com"];
|
||||
static String kr_currentDomain = "api.example.com";
|
||||
```
|
||||
|
||||
如果看到你设置的域名,说明配置成功。
|
||||
|
||||
---
|
||||
|
||||
### Q2: Release 构建和 Debug 构建有什么区别?
|
||||
|
||||
| 特性 | Debug | Release |
|
||||
|-----|-------|---------|
|
||||
| **文件大小** | 较大 | 较小(优化后) |
|
||||
| **性能** | 较慢 | 快 |
|
||||
| **调试信息** | 包含 | 移除 |
|
||||
| **代码混淆** | 无 | 有 |
|
||||
| **适用场景** | 开发测试 | 正式发布 |
|
||||
|
||||
**推荐:** 生产环境使用 **release** 构建
|
||||
|
||||
---
|
||||
|
||||
### Q3: 如何使用环境变量配置(不想每次手动输入)?
|
||||
|
||||
在仓库 **Settings → Secrets and variables → Actions → Variables** 添加:
|
||||
|
||||
| 变量名 | 值 |
|
||||
|-------|---|
|
||||
| `DEFAULT_API_DOMAIN` | `api.example.com` |
|
||||
| `DEFAULT_OSS_URL_1` | `https://cdn1.example.com/config.txt` |
|
||||
| `DEFAULT_OSS_URL_2` | `https://cdn2.example.com/config.txt` |
|
||||
| `DEFAULT_OSS_URL_3` | `https://cdn3.example.com/config.txt` |
|
||||
| `DEFAULT_OSS_URL_4` | `https://cdn4.example.com/config.txt` |
|
||||
|
||||
然后修改 workflow 文件,将默认值改为:
|
||||
|
||||
```yaml
|
||||
default: ${{ vars.DEFAULT_API_DOMAIN || 'api.maodag.top' }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Q4: 构建失败 - "libcore.aar not found"
|
||||
|
||||
**原因:** libcore 编译失败
|
||||
|
||||
**解决:**
|
||||
1. 检查 `build-libcore` job 的日志
|
||||
2. 确认 Go 环境和 gomobile 安装成功
|
||||
3. 确认 libcore 子模块已正确初始化
|
||||
|
||||
---
|
||||
|
||||
### Q5: 如何配置签名(Release 构建必需)?
|
||||
|
||||
详见主文档 `.github/workflows/README.md` 的签名配置章节。
|
||||
|
||||
---
|
||||
|
||||
## 💡 高级技巧
|
||||
|
||||
### 技巧 1:同时构建多个版本
|
||||
|
||||
修改 `build-apk` job:
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
matrix:
|
||||
build_type: [debug, release]
|
||||
api_domain: ['api.maodag.top', 'api.example.com']
|
||||
```
|
||||
|
||||
这样会生成 4 个 APK(2种类型 × 2个域名)
|
||||
|
||||
---
|
||||
|
||||
### 技巧 2:添加构建完成通知
|
||||
|
||||
在 workflow 最后添加:
|
||||
|
||||
```yaml
|
||||
- name: 📢 发送 Telegram 通知
|
||||
if: success()
|
||||
run: |
|
||||
curl -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
||||
-d chat_id=${{ secrets.TELEGRAM_CHAT_ID }} \
|
||||
-d text="✅ BearVPN 构建成功!下载: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||
```
|
||||
|
||||
需要先配置 `TELEGRAM_BOT_TOKEN` 和 `TELEGRAM_CHAT_ID` Secrets。
|
||||
|
||||
---
|
||||
|
||||
### 技巧 3:缓存加速构建
|
||||
|
||||
workflow 已配置 Go 和 Flutter 缓存,首次构建约 30 分钟,后续构建可缩短至 15-20 分钟。
|
||||
|
||||
---
|
||||
|
||||
## 📊 构建状态徽章
|
||||
|
||||
在 README.md 中添加:
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
效果:
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关文件
|
||||
|
||||
- **主 Workflow:** `.github/workflows/build-android-apk.yml`
|
||||
- **配置文件:** `lib/app/common/app_config.dart`
|
||||
- **libcore 源码:** `libcore/` 子模块
|
||||
|
||||
---
|
||||
|
||||
## 📞 需要帮助?
|
||||
|
||||
- 查看 [GitHub Actions 文档](https://docs.github.com/actions)
|
||||
- 查看构建日志排查问题
|
||||
- 提交 Issue 到仓库
|
||||
|
||||
---
|
||||
|
||||
**生成时间:** 2025-10-27
|
||||
**作者:** Claude Code
|
||||
**版本:** 1.0.0
|
||||
@@ -1,366 +0,0 @@
|
||||
# 🎯 如何在 GitHub 上构建你的应用
|
||||
|
||||
## 📋 前提条件
|
||||
|
||||
✅ 已将配置推送到 GitHub
|
||||
✅ 有 GitHub 账号访问权限
|
||||
|
||||
---
|
||||
|
||||
## 🚀 方法一:手动触发构建(推荐新手)
|
||||
|
||||
### 步骤 1: 访问 GitHub Actions 页面
|
||||
|
||||
1. 打开浏览器,访问你的仓库:
|
||||
```
|
||||
https://github.com/你的用户名/LighthouseApp
|
||||
```
|
||||
|
||||
2. 点击顶部导航栏的 **Actions** 标签
|
||||
```
|
||||
Code Issues Pull requests Actions Projects Wiki Security Insights
|
||||
↑ 点这里
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 2: 选择 Workflow
|
||||
|
||||
在左侧栏看到可用的 workflows:
|
||||
|
||||
```
|
||||
All workflows
|
||||
├── Build Android APK ← 仅构建 Android
|
||||
├── Build Multi-Platform ← 构建所有平台 ⭐推荐
|
||||
└── Build Clash Core
|
||||
```
|
||||
|
||||
**选择建议:**
|
||||
- 🟢 **首次测试:** 选择 **Build Android APK**(快速)
|
||||
- 🔵 **正式发布:** 选择 **Build Multi-Platform**(全平台)
|
||||
|
||||
---
|
||||
|
||||
### 步骤 3: 运行 Workflow
|
||||
|
||||
1. 点击选择的 workflow 名称
|
||||
|
||||
2. 右侧出现 **"Run workflow"** 下拉按钮
|
||||
```
|
||||
[Run workflow ▼]
|
||||
```
|
||||
|
||||
3. 点击下拉按钮,展开配置面板
|
||||
|
||||
---
|
||||
|
||||
### 步骤 4: 配置参数
|
||||
|
||||
#### 如果选择 "Build Android APK":
|
||||
|
||||
```yaml
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Run workflow │
|
||||
├─────────────────────────────────────────┤
|
||||
│ Use workflow from │
|
||||
│ Branch: main [▼] │
|
||||
│ │
|
||||
│ 构建类型 │
|
||||
│ ○ debug │
|
||||
│ ● release │
|
||||
│ │
|
||||
│ API 域名 │
|
||||
│ [api.maodag.top________________] │
|
||||
│ │
|
||||
│ OSS 配置地址 1 │
|
||||
│ [https://ppp2.oss-cn-hongkong...] │
|
||||
│ │
|
||||
│ OSS 配置地址 2 │
|
||||
│ [https://xgp3.oss-ap-northeast-1...] │
|
||||
│ │
|
||||
│ OSS 配置地址 3 │
|
||||
│ [https://xpp4.oss-ap-northeast-2...] │
|
||||
│ │
|
||||
│ OSS 配置地址 4 │
|
||||
│ [https://xpp5.oss-ap-southeast-1...] │
|
||||
│ │
|
||||
│ [Cancel] [Run workflow] │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**配置说明:**
|
||||
- **构建类型:** 选择 `release`(生产环境)
|
||||
- **API 域名:** 填写你的后端域名(默认 `api.maodag.top`)
|
||||
- **OSS 地址:** 保持默认或填写你的 CDN 地址
|
||||
|
||||
#### 如果选择 "Build Multi-Platform":
|
||||
|
||||
额外多一个参数:
|
||||
```yaml
|
||||
│ 构建平台 │
|
||||
│ [android,windows,macos,linux______] │
|
||||
```
|
||||
|
||||
**选项:**
|
||||
- `android` - 仅 Android
|
||||
- `windows` - 仅 Windows
|
||||
- `macos` - 仅 macOS
|
||||
- `linux` - 仅 Linux
|
||||
- `android,windows` - Android + Windows
|
||||
- `android,windows,macos,linux` - 全部平台 ⭐
|
||||
|
||||
---
|
||||
|
||||
### 步骤 5: 开始构建
|
||||
|
||||
1. 检查所有参数是否正确
|
||||
|
||||
2. 点击绿色的 **"Run workflow"** 按钮
|
||||
|
||||
3. 页面刷新,顶部出现黄色进度条:
|
||||
```
|
||||
⚠️ Build Android APK #1
|
||||
Queued - This workflow is in queue waiting to run
|
||||
```
|
||||
|
||||
4. 几秒后变为蓝色(运行中):
|
||||
```
|
||||
🔵 Build Android APK #1
|
||||
In progress - This workflow is currently running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 6: 监控构建进度
|
||||
|
||||
1. 点击运行记录(蓝色行)
|
||||
|
||||
2. 看到构建阶段:
|
||||
```
|
||||
编译 libcore.aar 🔵 Running (15分钟)
|
||||
编译 Android APK ⏸️ Pending
|
||||
```
|
||||
|
||||
3. 可以展开查看实时日志:
|
||||
```
|
||||
▼ 编译 libcore.aar
|
||||
▼ 📦 编译 libcore.aar
|
||||
🚀 开始编译 libcore...
|
||||
[gomobile] installing...
|
||||
✅ libcore.aar 生成成功
|
||||
```
|
||||
|
||||
4. 等待所有阶段完成(约 30-85 分钟)
|
||||
|
||||
---
|
||||
|
||||
### 步骤 7: 下载构建产物
|
||||
|
||||
构建成功后:
|
||||
|
||||
1. 向下滚动到 **Artifacts** 区域
|
||||
```
|
||||
📦 Artifacts
|
||||
|
||||
Produced during runtime
|
||||
|
||||
Name Size Expires
|
||||
apk-arm64-v8a-release 42.5 MB in 30 days [Download]
|
||||
apk-armeabi-v7a-release 38.2 MB in 30 days [Download]
|
||||
apk-x86_64-release 45.1 MB in 30 days [Download]
|
||||
```
|
||||
|
||||
2. 点击 **[Download]** 下载对应文件
|
||||
|
||||
3. 下载的是 ZIP 文件,解压后得到 APK:
|
||||
```
|
||||
apk-arm64-v8a-release.zip
|
||||
└── BearVPN-android-arm64-v8a-release-20251027-abc1234.apk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ 方法二:推送标签自动构建
|
||||
|
||||
这种方式会自动构建并创建 GitHub Release。
|
||||
|
||||
### 步骤 1: 在本地打标签
|
||||
|
||||
```bash
|
||||
cd /Users/mac/Project/Dart/LighthouseApp
|
||||
|
||||
# 创建标签(版本号必须以 v 开头)
|
||||
git tag v1.0.0
|
||||
|
||||
# 查看标签
|
||||
git tag
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 2: 推送标签到 GitHub
|
||||
|
||||
```bash
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
**输出:**
|
||||
```
|
||||
Enumerating objects: 1, done.
|
||||
Counting objects: 100% (1/1), done.
|
||||
Writing objects: 100% (1/1), 160 bytes | 160.00 KiB/s, done.
|
||||
Total 1 (delta 0), reused 0 (delta 0)
|
||||
To github.com:你的用户名/LighthouseApp.git
|
||||
* [new tag] v1.0.0 -> v1.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 3: 自动触发构建
|
||||
|
||||
1. 推送标签后,GitHub 自动检测到标签
|
||||
2. 触发 **Build Multi-Platform** workflow
|
||||
3. 使用默认配置构建所有平台
|
||||
|
||||
---
|
||||
|
||||
### 步骤 4: 查看构建进度
|
||||
|
||||
1. 访问 Actions 页面
|
||||
2. 看到自动创建的构建任务:
|
||||
```
|
||||
🔵 Build Multi-Platform
|
||||
v1.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 5: 下载 Release
|
||||
|
||||
构建成功后:
|
||||
|
||||
1. 访问 **Releases** 页面:
|
||||
```
|
||||
https://github.com/你的用户名/LighthouseApp/releases
|
||||
```
|
||||
|
||||
2. 看到新创建的 Release:
|
||||
```
|
||||
📦 v1.0.0
|
||||
|
||||
Latest Pre-release
|
||||
|
||||
🎉 BearVPN 多平台版本发布
|
||||
|
||||
Assets (7)
|
||||
├── BearVPN-android-arm64-v8a-release-*.apk 42.5 MB
|
||||
├── BearVPN-android-armeabi-v7a-release-*.apk 38.2 MB
|
||||
├── BearVPN-android-x86_64-release-*.apk 45.1 MB
|
||||
├── BearVPN-windows-x64-release-*.zip 52.3 MB
|
||||
├── BearVPN-macos-release-*.zip 48.7 MB
|
||||
├── BearVPN-linux-x64-release-*.tar.gz 45.9 MB
|
||||
└── Source code (zip)
|
||||
```
|
||||
|
||||
3. 直接下载需要的文件
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间参考
|
||||
|
||||
| Workflow | 平台 | 时间 |
|
||||
|---------|------|------|
|
||||
| Build Android APK | Android | 30 分钟 |
|
||||
| Build Multi-Platform | Android | 35 分钟 |
|
||||
| Build Multi-Platform | Windows | 30 分钟 |
|
||||
| Build Multi-Platform | macOS | 35 分钟 |
|
||||
| Build Multi-Platform | Linux | 30 分钟 |
|
||||
| Build Multi-Platform | 全部平台 | **60-85 分钟** |
|
||||
|
||||
**提示:** 平台是并行构建的,不是累加时间。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 推荐流程
|
||||
|
||||
### 首次测试(验证流程)
|
||||
|
||||
```
|
||||
1. 选择 "Build Android APK"
|
||||
2. 使用默认配置
|
||||
3. 运行构建
|
||||
4. 等待 30 分钟
|
||||
5. 下载 arm64-v8a APK
|
||||
6. 安装测试
|
||||
```
|
||||
|
||||
### 正式发布(生产环境)
|
||||
|
||||
```
|
||||
1. 确保代码已测试
|
||||
2. 本地打标签: git tag v1.0.0
|
||||
3. 推送标签: git push origin v1.0.0
|
||||
4. 等待 60-85 分钟
|
||||
5. 在 Releases 页面下载所有平台
|
||||
6. 分发给用户
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q1: 找不到 "Run workflow" 按钮
|
||||
|
||||
**原因:** 可能还在查看历史运行记录
|
||||
|
||||
**解决:**
|
||||
1. 点击左侧的 workflow 名称
|
||||
2. 确保在 workflow 主页面
|
||||
3. 右侧会出现 "Run workflow" 按钮
|
||||
|
||||
---
|
||||
|
||||
### Q2: 构建失败
|
||||
|
||||
**排查步骤:**
|
||||
1. 点击失败的运行记录
|
||||
2. 展开红色的步骤
|
||||
3. 查看错误日志
|
||||
4. 常见错误:
|
||||
- libcore 编译失败 → 检查 Go 环境
|
||||
- APK 构建失败 → 检查 Flutter 依赖
|
||||
|
||||
---
|
||||
|
||||
### Q3: Artifacts 下载后是空的
|
||||
|
||||
**原因:** 构建可能失败
|
||||
|
||||
**解决:**
|
||||
1. 检查构建日志
|
||||
2. 确保所有步骤都是绿色 ✅
|
||||
3. 重新运行构建
|
||||
|
||||
---
|
||||
|
||||
### Q4: 如何修改 API 域名
|
||||
|
||||
**方法 1:** 手动触发时修改参数
|
||||
|
||||
**方法 2:** 修改代码中的默认值
|
||||
```dart
|
||||
// lib/app/common/app_config.dart
|
||||
static String kr_currentDomain = "api.example.com";
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 需要帮助?
|
||||
|
||||
- **查看详细文档:** `.github/workflows/INDEX.md`
|
||||
- **快速开始:** `.github/workflows/QUICKSTART.md`
|
||||
- **问题反馈:** GitHub Issues
|
||||
|
||||
---
|
||||
|
||||
**准备好了吗?立即开始构建!** 🚀
|
||||
@@ -1,318 +0,0 @@
|
||||
# 📚 GitHub Actions 构建系统总览
|
||||
|
||||
## 🎯 快速导航
|
||||
|
||||
| 文档 | 用途 | 适合人群 |
|
||||
|-----|------|---------|
|
||||
| **[QUICKSTART.md](./QUICKSTART.md)** | 3步快速开始 | 新手 |
|
||||
| **[README.md](./README.md)** | 基础说明 | 所有人 |
|
||||
| **[BUILD_GUIDE.md](./BUILD_GUIDE.md)** | Android 详细指南 | Android 开发者 |
|
||||
| **[MULTIPLATFORM_GUIDE.md](./MULTIPLATFORM_GUIDE.md)** | 多平台构建指南 | 全平台开发者 |
|
||||
|
||||
---
|
||||
|
||||
## 📋 可用的 Workflows
|
||||
|
||||
### 1. `build-android-apk.yml` - Android 专用构建
|
||||
|
||||
**功能:**
|
||||
- ✅ 编译 libcore.aar
|
||||
- ✅ 构建 Android APK (arm64/armv7/x86_64)
|
||||
- ✅ 配置 API 域名和 OSS 地址
|
||||
- ✅ Release 构建
|
||||
|
||||
**触发条件:**
|
||||
- 推送到 main/develop 分支
|
||||
- 创建 v* 标签
|
||||
- 手动触发
|
||||
|
||||
**文档:** [BUILD_GUIDE.md](./BUILD_GUIDE.md)
|
||||
|
||||
---
|
||||
|
||||
### 2. `build-multiplatform.yml` - 多平台构建 ⭐推荐
|
||||
|
||||
**功能:**
|
||||
- ✅ Android APK
|
||||
- ✅ Windows 可执行文件
|
||||
- ✅ macOS 应用
|
||||
- ✅ Linux 可执行文件
|
||||
- ✅ 可选择构建平台
|
||||
- ✅ 统一配置管理
|
||||
|
||||
**触发条件:**
|
||||
- 推送到 main/develop 分支
|
||||
- 创建 v* 标签
|
||||
- 手动触发
|
||||
|
||||
**文档:** [MULTIPLATFORM_GUIDE.md](./MULTIPLATFORM_GUIDE.md)
|
||||
|
||||
---
|
||||
|
||||
### 3. `build-clash-core.yml` - Clash 核心编译
|
||||
|
||||
**功能:**
|
||||
- 编译 Clash Meta 核心
|
||||
- 支持多架构 (arm64/armv7/x86_64)
|
||||
|
||||
**触发条件:**
|
||||
- core/ 目录变更
|
||||
- 手动触发
|
||||
|
||||
---
|
||||
|
||||
## 🚀 使用建议
|
||||
|
||||
### 场景 1: 日常开发(仅 Android)
|
||||
|
||||
**使用:** `build-android-apk.yml`
|
||||
```bash
|
||||
# 推送代码自动触发
|
||||
git push origin main
|
||||
```
|
||||
|
||||
**时间:** 约 30 分钟
|
||||
**产物:** 3 个 Android APK
|
||||
|
||||
---
|
||||
|
||||
### 场景 2: 正式发布(所有平台)
|
||||
|
||||
**使用:** `build-multiplatform.yml`
|
||||
```bash
|
||||
# 1. 打标签
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
|
||||
# 2. 自动构建所有平台并创建 Release
|
||||
```
|
||||
|
||||
**时间:** 约 60-85 分钟(并行)
|
||||
**产物:** Android + Windows + macOS + Linux
|
||||
|
||||
---
|
||||
|
||||
### 场景 3: 测试特定平台
|
||||
|
||||
**使用:** `build-multiplatform.yml` 手动触发
|
||||
```yaml
|
||||
构建平台: android,windows # 只构建这两个
|
||||
```
|
||||
|
||||
**时间:** 约 35 分钟
|
||||
**产物:** 指定平台
|
||||
|
||||
---
|
||||
|
||||
## 📦 构建产物对比
|
||||
|
||||
### Android 专用构建
|
||||
|
||||
```
|
||||
BearVPN-android-arm64-v8a-release-20251027-abc1234.apk
|
||||
BearVPN-android-armeabi-v7a-release-20251027-abc1234.apk
|
||||
BearVPN-android-x86_64-release-20251027-abc1234.apk
|
||||
```
|
||||
|
||||
### 多平台构建
|
||||
|
||||
```
|
||||
# Android
|
||||
BearVPN-android-arm64-v8a-release-20251027-abc1234.apk
|
||||
BearVPN-android-armeabi-v7a-release-20251027-abc1234.apk
|
||||
BearVPN-android-x86_64-release-20251027-abc1234.apk
|
||||
|
||||
# Windows
|
||||
BearVPN-windows-x64-release-20251027-abc1234.zip
|
||||
|
||||
# macOS
|
||||
BearVPN-macos-release-20251027-abc1234.zip
|
||||
|
||||
# Linux
|
||||
BearVPN-linux-x64-release-20251027-abc1234.tar.gz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 配置参数说明
|
||||
|
||||
### 所有 Workflow 通用参数
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|-----|-------|------|
|
||||
| **构建类型** | `release` | debug 或 release |
|
||||
| **API 域名** | `api.maodag.top` | 后端服务器地址 |
|
||||
| **OSS 地址 1** | 香港 CDN | 配置文件源 |
|
||||
| **OSS 地址 2** | 东京 CDN | 备用配置源 |
|
||||
| **OSS 地址 3** | 首尔 CDN | 备用配置源 |
|
||||
| **OSS 地址 4** | 新加坡 CDN | 备用配置源 |
|
||||
|
||||
### 多平台专用参数
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|-----|-------|------|
|
||||
| **构建平台** | `android,windows,macos,linux` | 选择构建的平台 |
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间对比
|
||||
|
||||
| Workflow | 单平台 | 全平台 |
|
||||
|---------|-------|-------|
|
||||
| **Android 专用** | 30分钟 | - |
|
||||
| **多平台** | 30-40分钟 | 60-85分钟 |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 选择 Workflow 的建议
|
||||
|
||||
### 选择 `build-android-apk.yml` 如果:
|
||||
|
||||
- ✅ 只需要 Android 版本
|
||||
- ✅ 快速迭代开发
|
||||
- ✅ CI/CD 自动触发
|
||||
|
||||
### 选择 `build-multiplatform.yml` 如果:
|
||||
|
||||
- ✅ 需要桌面版本
|
||||
- ✅ 正式版本发布
|
||||
- ✅ 需要灵活选择平台
|
||||
|
||||
---
|
||||
|
||||
## 🔧 环境配置
|
||||
|
||||
### 必需的 Secrets(用于 Release 签名)
|
||||
|
||||
**Android:**
|
||||
```
|
||||
KEYSTORE_BASE64
|
||||
KEYSTORE_PASSWORD
|
||||
KEY_ALIAS
|
||||
KEY_PASSWORD
|
||||
```
|
||||
|
||||
**macOS:**
|
||||
```
|
||||
MACOS_CERTIFICATE_BASE64
|
||||
MACOS_CERTIFICATE_PASSWORD
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
WINDOWS_CERTIFICATE_BASE64
|
||||
WINDOWS_CERTIFICATE_PASSWORD
|
||||
```
|
||||
|
||||
**说明:** 如果不配置签名,可以使用 debug 构建。
|
||||
|
||||
---
|
||||
|
||||
## 📊 构建流程图
|
||||
|
||||
### Android 专用
|
||||
|
||||
```
|
||||
Checkout 代码
|
||||
↓
|
||||
编译 libcore.aar (15min)
|
||||
↓
|
||||
配置 API/OSS
|
||||
↓
|
||||
构建 APK (20min)
|
||||
↓
|
||||
上传产物
|
||||
```
|
||||
|
||||
### 多平台
|
||||
|
||||
```
|
||||
Checkout 代码
|
||||
↓
|
||||
编译 libcore.aar (15min)
|
||||
↓
|
||||
├─→ Android (20min) ─┐
|
||||
├─→ Windows (15min) ─┤
|
||||
├─→ macOS (20min) ─┼─→ 创建 Release
|
||||
└─→ Linux (15min) ─┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 故障排查
|
||||
|
||||
### 问题 1: libcore 编译失败
|
||||
|
||||
**检查:**
|
||||
1. Go 环境是否正常
|
||||
2. gomobile 是否安装
|
||||
3. 网络连接(下载依赖)
|
||||
|
||||
**日志位置:** `build-libcore` job
|
||||
|
||||
---
|
||||
|
||||
### 问题 2: Android 构建失败
|
||||
|
||||
**常见原因:**
|
||||
- libcore.aar 未生成
|
||||
- Gradle 依赖问题
|
||||
- 签名配置错误
|
||||
|
||||
**解决:** 查看 `build-android` job 日志
|
||||
|
||||
---
|
||||
|
||||
### 问题 3: macOS 构建失败
|
||||
|
||||
**常见原因:**
|
||||
- 签名证书未配置
|
||||
- Xcode 版本不兼容
|
||||
|
||||
**解决:**
|
||||
- 使用 debug 构建
|
||||
- 或配置签名证书
|
||||
|
||||
---
|
||||
|
||||
## 💡 高级用法
|
||||
|
||||
### 1. 定时构建
|
||||
|
||||
添加到 workflow:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # 每天UTC 2:00
|
||||
```
|
||||
|
||||
### 2. PR 自动构建
|
||||
|
||||
已配置:推送 PR 到 main 分支自动触发
|
||||
|
||||
### 3. 构建通知
|
||||
|
||||
可集成 Telegram/Slack/钉钉通知
|
||||
|
||||
---
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
- **查看文档:** 本目录下的 Markdown 文件
|
||||
- **查看日志:** GitHub Actions 页面
|
||||
- **提交问题:** Issues 页面
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关链接
|
||||
|
||||
- [GitHub Actions 文档](https://docs.github.com/actions)
|
||||
- [Flutter CI/CD](https://docs.flutter.dev/deployment/cd)
|
||||
- [sing-box 文档](https://sing-box.sagernet.org/)
|
||||
|
||||
---
|
||||
|
||||
**版本:** 1.0.0
|
||||
**更新:** 2025-10-27
|
||||
**作者:** Claude Code
|
||||
@@ -1,407 +0,0 @@
|
||||
# 🌐 多平台构建完全指南
|
||||
|
||||
## 📋 支持的平台
|
||||
|
||||
✅ **Android** - arm64-v8a / armeabi-v7a / x86_64
|
||||
✅ **Windows** - x64
|
||||
✅ **macOS** - Universal (Intel + Apple Silicon)
|
||||
✅ **Linux** - x64
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 方法 1: 构建所有平台(推荐)
|
||||
|
||||
1. 打开 GitHub Actions 页面
|
||||
2. 选择 **Build Multi-Platform**
|
||||
3. 点击 **Run workflow**
|
||||
4. 配置参数:
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
API 域名: api.maodag.top
|
||||
OSS 地址 1-4: 使用默认值
|
||||
构建平台: android,windows,macos,linux # 构建所有平台
|
||||
```
|
||||
|
||||
5. 点击 **Run workflow** 开始
|
||||
|
||||
---
|
||||
|
||||
### 方法 2: 仅构建指定平台
|
||||
|
||||
**场景:** 只需要 Android 和 Windows 版本
|
||||
|
||||
```yaml
|
||||
构建平台: android,windows # 只构建这两个平台
|
||||
```
|
||||
|
||||
**可选值:**
|
||||
- `android` - 仅 Android
|
||||
- `windows` - 仅 Windows
|
||||
- `macos` - 仅 macOS
|
||||
- `linux` - 仅 Linux
|
||||
- `android,windows` - Android + Windows
|
||||
- `android,windows,macos,linux` - 全部平台
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间估算
|
||||
|
||||
| 平台 | 时间 | 说明 |
|
||||
|-----|------|-----|
|
||||
| **libcore** | 10-15分钟 | Android 依赖 |
|
||||
| **Android** | 15-20分钟 | 3个架构APK |
|
||||
| **Windows** | 10-15分钟 | x64可执行文件 |
|
||||
| **macOS** | 15-20分钟 | Universal应用 |
|
||||
| **Linux** | 10-15分钟 | x64可执行文件 |
|
||||
| **总计(全平台)** | **60-85分钟** | 并行构建 |
|
||||
|
||||
---
|
||||
|
||||
## 📦 构建产物
|
||||
|
||||
### Android
|
||||
|
||||
```
|
||||
BearVPN-android-arm64-v8a-release-20251027-abc1234.apk (推荐)
|
||||
BearVPN-android-armeabi-v7a-release-20251027-abc1234.apk (老设备)
|
||||
BearVPN-android-x86_64-release-20251027-abc1234.apk (模拟器)
|
||||
```
|
||||
|
||||
**安装:** 直接点击APK安装
|
||||
|
||||
---
|
||||
|
||||
### Windows
|
||||
|
||||
```
|
||||
BearVPN-windows-x64-release-20251027-abc1234.zip
|
||||
```
|
||||
|
||||
**内容结构:**
|
||||
```
|
||||
BearVPN.exe # 主程序
|
||||
flutter_windows.dll # Flutter运行时
|
||||
data/ # 资源文件
|
||||
```
|
||||
|
||||
**运行:**
|
||||
1. 解压 ZIP 文件
|
||||
2. 双击 `BearVPN.exe` 运行
|
||||
3. 如提示缺少依赖,安装 [VC++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe)
|
||||
|
||||
---
|
||||
|
||||
### macOS
|
||||
|
||||
```
|
||||
BearVPN-macos-release-20251027-abc1234.zip
|
||||
```
|
||||
|
||||
**内容:**
|
||||
```
|
||||
BearVPN.app # 应用程序包(Universal)
|
||||
```
|
||||
|
||||
**安装:**
|
||||
1. 解压 ZIP 文件
|
||||
2. 将 `BearVPN.app` 拖到 **应用程序** 文件夹
|
||||
3. 首次运行右键点击 → 打开(绕过 Gatekeeper)
|
||||
|
||||
**支持架构:**
|
||||
- Intel (x86_64)
|
||||
- Apple Silicon (arm64)
|
||||
|
||||
---
|
||||
|
||||
### Linux
|
||||
|
||||
```
|
||||
BearVPN-linux-x64-release-20251027-abc1234.tar.gz
|
||||
```
|
||||
|
||||
**内容结构:**
|
||||
```
|
||||
bearvpn # 可执行文件
|
||||
lib/ # 共享库
|
||||
data/ # 资源文件
|
||||
```
|
||||
|
||||
**运行:**
|
||||
```bash
|
||||
# 1. 解压
|
||||
tar -xzf BearVPN-linux-x64-release-*.tar.gz
|
||||
cd bundle
|
||||
|
||||
# 2. 添加执行权限
|
||||
chmod +x bearvpn
|
||||
|
||||
# 3. 运行
|
||||
./bearvpn
|
||||
```
|
||||
|
||||
**依赖要求:**
|
||||
- GTK+ 3
|
||||
- libstdc++12
|
||||
|
||||
**安装依赖(Ubuntu/Debian):**
|
||||
```bash
|
||||
sudo apt-get install libgtk-3-0 libstdc++6
|
||||
```
|
||||
|
||||
**安装依赖(Fedora/RHEL):**
|
||||
```bash
|
||||
sudo dnf install gtk3 libstdc++
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置说明
|
||||
|
||||
### 所有平台通用配置
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|-----|-------|------|
|
||||
| **构建类型** | `release` | debug 或 release |
|
||||
| **API 域名** | `api.maodag.top` | 后端服务器 |
|
||||
| **OSS 地址 1** | 香港 CDN | 配置文件源 |
|
||||
| **OSS 地址 2** | 东京 CDN | 备用源 |
|
||||
| **OSS 地址 3** | 首尔 CDN | 备用源 |
|
||||
| **OSS 地址 4** | 新加坡 CDN | 备用源 |
|
||||
| **构建平台** | `android,windows,macos,linux` | 选择平台 |
|
||||
|
||||
---
|
||||
|
||||
## 📥 下载构建产物
|
||||
|
||||
### 从 Actions 页面下载
|
||||
|
||||
1. 打开运行记录
|
||||
2. 滚动到 **Artifacts** 区域
|
||||
3. 下载对应平台:
|
||||
- `android-apk` - Android APK (所有架构)
|
||||
- `windows-x64` - Windows 可执行程序
|
||||
- `macos-app` - macOS 应用
|
||||
- `linux-x64` - Linux 可执行程序
|
||||
|
||||
### 从 Releases 下载(推送标签时)
|
||||
|
||||
1. 访问 Releases 页面
|
||||
2. 选择版本
|
||||
3. 在 Assets 中下载对应平台文件
|
||||
|
||||
---
|
||||
|
||||
## 🎯 使用场景
|
||||
|
||||
### 场景 1: 开发测试(仅 Android)
|
||||
|
||||
```yaml
|
||||
构建类型: debug
|
||||
构建平台: android
|
||||
API 域名: api.test.com
|
||||
```
|
||||
|
||||
**优点:** 快速,约20分钟
|
||||
|
||||
---
|
||||
|
||||
### 场景 2: 正式发布(全平台)
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
构建平台: android,windows,macos,linux
|
||||
API 域名: api.maodag.top
|
||||
```
|
||||
|
||||
**优点:** 一次构建,覆盖所有用户
|
||||
|
||||
---
|
||||
|
||||
### 场景 3: 仅桌面平台
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
构建平台: windows,macos,linux
|
||||
```
|
||||
|
||||
**用途:** 桌面版更新
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q1: Windows 构建失败 - "7z command not found"
|
||||
|
||||
**原因:** Windows runner 默认有 7z
|
||||
|
||||
**解决:** 检查构建日志,可能是其他错误
|
||||
|
||||
---
|
||||
|
||||
### Q2: macOS 构建失败 - "Code signing required"
|
||||
|
||||
**原因:** Release 构建需要签名
|
||||
|
||||
**解决方案:**
|
||||
|
||||
**方法 1:** 使用 debug 构建(测试用)
|
||||
|
||||
**方法 2:** 配置签名证书(生产用)
|
||||
```yaml
|
||||
# 在 Secrets 中添加
|
||||
MACOS_CERTIFICATE_BASE64
|
||||
MACOS_CERTIFICATE_PASSWORD
|
||||
MACOS_KEYCHAIN_PASSWORD
|
||||
PROVISIONING_PROFILE_BASE64
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Q3: Linux 运行时提示缺少库
|
||||
|
||||
**错误:**
|
||||
```
|
||||
error while loading shared libraries: libgtk-3.so.0
|
||||
```
|
||||
|
||||
**解决:**
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install libgtk-3-0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Q4: 如何只更新某个平台?
|
||||
|
||||
**方法 1:** 手动触发指定平台
|
||||
```yaml
|
||||
构建平台: android # 只构建 Android
|
||||
```
|
||||
|
||||
**方法 2:** 创建平台专用 workflow(推荐)
|
||||
|
||||
---
|
||||
|
||||
### Q5: 构建时间太长怎么办?
|
||||
|
||||
**优化方案:**
|
||||
|
||||
1. **仅构建需要的平台**
|
||||
```yaml
|
||||
构建平台: android # 而不是全部
|
||||
```
|
||||
|
||||
2. **使用缓存**(已配置)
|
||||
- Flutter SDK 缓存
|
||||
- Gradle 缓存
|
||||
- Go modules 缓存
|
||||
|
||||
3. **分批构建**
|
||||
- 白天构建 Android/Windows
|
||||
- 晚上构建 macOS/Linux
|
||||
|
||||
---
|
||||
|
||||
## 💡 高级用法
|
||||
|
||||
### 技巧 1: 矩阵构建多个配置
|
||||
|
||||
修改 workflow:
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
matrix:
|
||||
api_domain: ['api.prod.com', 'api.test.com']
|
||||
platform: ['android', 'windows', 'macos', 'linux']
|
||||
```
|
||||
|
||||
**效果:** 生成 8 个版本(2域名 × 4平台)
|
||||
|
||||
---
|
||||
|
||||
### 技巧 2: 定时自动构建
|
||||
|
||||
添加到 workflow:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # 每天凌晨2点(UTC)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 技巧 3: 构建完成通知
|
||||
|
||||
添加 Telegram 通知:
|
||||
|
||||
```yaml
|
||||
- name: 📢 通知
|
||||
run: |
|
||||
curl -X POST "https://api.telegram.org/bot${{ secrets.TG_BOT_TOKEN }}/sendMessage" \
|
||||
-d chat_id=${{ secrets.TG_CHAT_ID }} \
|
||||
-d text="✅ 多平台构建完成!"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 构建并行示意图
|
||||
|
||||
```
|
||||
libcore (15min)
|
||||
↓
|
||||
├─→ Android (20min) ─┐
|
||||
├─→ Windows (15min) ─┤
|
||||
├─→ macOS (20min) ─┼─→ Release (2min)
|
||||
└─→ Linux (15min) ─┘
|
||||
|
||||
总时间: 约 35-40分钟(并行)
|
||||
如果串行: 约 85分钟
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 安全建议
|
||||
|
||||
### Release 版本签名
|
||||
|
||||
**Android:**
|
||||
```yaml
|
||||
# Secrets 配置
|
||||
KEYSTORE_BASE64
|
||||
KEYSTORE_PASSWORD
|
||||
KEY_ALIAS
|
||||
KEY_PASSWORD
|
||||
```
|
||||
|
||||
**macOS:**
|
||||
```yaml
|
||||
# Secrets 配置
|
||||
MACOS_CERTIFICATE_BASE64
|
||||
MACOS_CERTIFICATE_PASSWORD
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```yaml
|
||||
# Secrets 配置
|
||||
WINDOWS_CERTIFICATE_BASE64
|
||||
WINDOWS_CERTIFICATE_PASSWORD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 需要帮助?
|
||||
|
||||
- 查看 [GitHub Actions 文档](https://docs.github.com/actions)
|
||||
- 查看 [Flutter 桌面支持](https://docs.flutter.dev/desktop)
|
||||
- 提交 Issue
|
||||
|
||||
---
|
||||
|
||||
**版本:** 1.0.0
|
||||
**更新:** 2025-10-27
|
||||
**作者:** Claude Code
|
||||
@@ -1,78 +0,0 @@
|
||||
# 🚀 GitHub Actions 快速开始
|
||||
|
||||
## 📋 3 步开始使用
|
||||
|
||||
### 步骤 1: 推送配置文件
|
||||
|
||||
```bash
|
||||
cd /Users/mac/Project/Dart/LighthouseApp
|
||||
|
||||
git add .github/workflows/
|
||||
git commit -m "feat: 添加 GitHub Actions 自动构建配置"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### 步骤 2: 手动触发构建
|
||||
|
||||
1. 打开 GitHub 仓库页面
|
||||
2. 点击 **Actions** 标签
|
||||
3. 左侧选择 **Build Android APK**
|
||||
4. 右侧点击 **Run workflow** 下拉按钮
|
||||
5. 配置参数(可以使用默认值):
|
||||
|
||||
```
|
||||
构建类型: release
|
||||
API 域名: api.maodag.top
|
||||
OSS 地址 1-4: 使用默认值
|
||||
```
|
||||
|
||||
6. 点击绿色 **Run workflow** 按钮
|
||||
|
||||
### 步骤 3: 下载 APK
|
||||
|
||||
- 等待约 30 分钟
|
||||
- 在构建记录页面找到 **Artifacts**
|
||||
- 下载 `apk-arm64-v8a-release`(推荐)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 自定义配置示例
|
||||
|
||||
### 场景 1: 更换 API 域名
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
API 域名: api.example.com ← 修改这里
|
||||
OSS 地址: 保持默认
|
||||
```
|
||||
|
||||
### 场景 2: 使用自己的 CDN
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
API 域名: api.maodag.top
|
||||
OSS 地址 1: https://your-cdn.com/config1.txt ← 修改这里
|
||||
OSS 地址 2: https://your-cdn.com/config2.txt ← 修改这里
|
||||
OSS 地址 3: https://your-cdn.com/config3.txt ← 修改这里
|
||||
OSS 地址 4: https://your-cdn.com/config4.txt ← 修改这里
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 详细文档
|
||||
|
||||
- **完整指南:** [BUILD_GUIDE.md](./BUILD_GUIDE.md)
|
||||
- **基础说明:** [README.md](./README.md)
|
||||
|
||||
---
|
||||
|
||||
## ✅ 核心功能
|
||||
|
||||
✅ **Release 构建** - 生产环境优化版本
|
||||
✅ **可配置域名** - 支持自定义 API 和 CDN
|
||||
✅ **分架构打包** - arm64/armv7/x86_64
|
||||
✅ **自动 Release** - 推送标签自动发布
|
||||
|
||||
---
|
||||
|
||||
**需要帮助?** 查看 [BUILD_GUIDE.md](./BUILD_GUIDE.md)
|
||||
@@ -1,90 +0,0 @@
|
||||
# GitHub Actions 构建说明
|
||||
|
||||
## 📋 工作流概览
|
||||
|
||||
### `build-android-apk.yml` - Android APK 自动构建
|
||||
|
||||
**触发条件:**
|
||||
- ✅ 推送到 `main` 或 `develop` 分支
|
||||
- ✅ 打 `v*` 标签时自动创建 Release
|
||||
- ✅ 手动触发(Actions 页面点击 "Run workflow")
|
||||
|
||||
**构建产物:**
|
||||
- `libcore.aar` - sing-box 核心库
|
||||
- `BearVPN-arm64-v8a-*.apk` - 64位 ARM 版本(推荐)
|
||||
- `BearVPN-armeabi-v7a-*.apk` - 32位 ARM 版本
|
||||
- `BearVPN-x86_64-*.apk` - 模拟器版本
|
||||
|
||||
---
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
### 方法一:推送代码自动构建
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: 新功能"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### 方法二:手动触发
|
||||
|
||||
1. 打开仓库 **Actions** 页面
|
||||
2. 点击 **Build Android APK**
|
||||
3. 点击 **Run workflow**
|
||||
|
||||
### 方法三:创建 Release
|
||||
|
||||
```bash
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 下载构建产物
|
||||
|
||||
- **Actions 页面:** 点击运行记录 → Artifacts 区域下载
|
||||
- **Releases 页面:** 选择版本 → Assets 下载
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置 Release 签名(可选)
|
||||
|
||||
1. 生成密钥:
|
||||
```bash
|
||||
keytool -genkey -v -keystore release.keystore -alias bearvpn -keyalg RSA -keysize 2048 -validity 10000
|
||||
```
|
||||
|
||||
2. 转换为 Base64:
|
||||
```bash
|
||||
base64 release.keystore > keystore.base64.txt
|
||||
```
|
||||
|
||||
3. 在 GitHub 仓库 **Settings → Secrets** 添加:
|
||||
- `KEYSTORE_BASE64`
|
||||
- `KEYSTORE_PASSWORD`
|
||||
- `KEY_ALIAS`
|
||||
- `KEY_PASSWORD`
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间
|
||||
|
||||
- libcore.aar: 10-15 分钟
|
||||
- Flutter APK: 15-20 分钟
|
||||
- **总计: 约 30 分钟**
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
**Q: 构建失败 "libcore.aar not found"**
|
||||
A: 检查 libcore 子模块是否正确初始化
|
||||
|
||||
**Q: Release 未创建**
|
||||
A: 标签必须以 `v` 开头,如 `v1.0.0`
|
||||
|
||||
---
|
||||
|
||||
生成时间: 2025-10-27
|
||||
@@ -1,319 +0,0 @@
|
||||
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: ubuntu-latest
|
||||
|
||||
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"
|
||||
@@ -1,142 +0,0 @@
|
||||
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: ubuntu-latest
|
||||
|
||||
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: ubuntu-latest
|
||||
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 }}
|
||||
@@ -1,950 +0,0 @@
|
||||
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: 'android,windows,macos,linux'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
# ==================== 编译 libcore (iOS/tvOS) ====================
|
||||
build-libcore-ios:
|
||||
name: 编译 libcore (iOS/tvOS)
|
||||
runs-on: macos-latest
|
||||
if: contains(inputs.platforms || 'ios', '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: contains(inputs.platforms || 'android', '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: contains(inputs.platforms || 'windows', 'windows')
|
||||
|
||||
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: contains(inputs.platforms || 'macos', '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: contains(inputs.platforms || 'linux', '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: contains(inputs.platforms || 'android', '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: contains(inputs.platforms || 'windows', 'windows')
|
||||
|
||||
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"
|
||||
@@ -1,145 +0,0 @@
|
||||
name: Build Windows
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
# 先编译 libcore
|
||||
build-libcore:
|
||||
name: 编译 libcore (Windows)
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
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/
|
||||
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
|
||||
|
||||
# 构建 Windows 应用
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
needs: build-libcore
|
||||
|
||||
steps:
|
||||
- name: 📥 Checkout 代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 📥 下载 libcore
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: libcore-windows
|
||||
path: .
|
||||
|
||||
- name: 🔧 复制 libcore 文件到正确位置并重命名
|
||||
run: |
|
||||
Write-Host "📋 复制 libcore 文件..."
|
||||
|
||||
# 创建目标目录
|
||||
New-Item -ItemType Directory -Force -Path libcore\bin
|
||||
|
||||
# 查找并复制 HiddifyCli.exe,重命名为 BearVPNCli.exe
|
||||
$exeFiles = Get-ChildItem -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
|
||||
Write-Host "✅ 重命名完成:HiddifyCli.exe → BearVPNCli.exe"
|
||||
} else {
|
||||
Write-Host "⚠️ 未找到 HiddifyCli.exe"
|
||||
}
|
||||
|
||||
# 复制 libcore.dll
|
||||
$dllFiles = Get-ChildItem -Recurse -Filter "libcore.dll" -ErrorAction SilentlyContinue
|
||||
if ($dllFiles) {
|
||||
$sourceDll = $dllFiles[0].FullName
|
||||
Write-Host "✅ 找到 libcore.dll: $sourceDll"
|
||||
Copy-Item $sourceDll libcore\bin\libcore.dll
|
||||
} else {
|
||||
Write-Host "⚠️ 未找到 libcore.dll"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "📄 验证文件:"
|
||||
if (Test-Path libcore\bin) {
|
||||
Get-ChildItem libcore\bin\ -ErrorAction SilentlyContinue | Format-Table Name, Length
|
||||
}
|
||||
|
||||
- name: Setup Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: '3.24.5'
|
||||
channel: 'stable'
|
||||
|
||||
- name: Enable Windows desktop
|
||||
run: flutter config --enable-windows-desktop
|
||||
|
||||
- name: Get dependencies
|
||||
run: flutter pub get
|
||||
|
||||
- name: Generate code
|
||||
run: dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
- name: Build Windows Debug
|
||||
run: flutter build windows
|
||||
|
||||
- name: Build Windows Release
|
||||
run: flutter build windows --release
|
||||
|
||||
- name: Upload Debug build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-debug-build
|
||||
path: build/windows/runner/Debug/
|
||||
|
||||
- name: Upload Release build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-release-build
|
||||
path: build/windows/runner/Release/
|
||||
@@ -1,3 +1,4 @@
|
||||
[submodule "libcore"]
|
||||
path = libcore
|
||||
url = https://github.com/hiddify/hiddify-next-core
|
||||
path = libcore
|
||||
url = https://github.com/hiddify/hiddify-next-core
|
||||
branch = main
|
||||
|
||||
@@ -12,6 +12,10 @@ ifeq ($(OS),Windows_NT)
|
||||
endif
|
||||
endif
|
||||
|
||||
APP_NAME=HiFastVPN
|
||||
VERSION_NAME=$(shell grep '^version:' pubspec.yaml | sed 's/version: //;s/+.*//;s/[^0-9.]//g')
|
||||
VERSION_BUILD=$(shell grep '^version:' pubspec.yaml | sed 's/.*+//;s/[^0-9]//g')
|
||||
|
||||
|
||||
BINDIR=libcore$(SEP)bin
|
||||
ANDROID_OUT=android$(SEP)app$(SEP)libs
|
||||
@@ -54,7 +58,7 @@ gen:
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
translate:
|
||||
dart run slang
|
||||
dart run slang --overwrite
|
||||
|
||||
|
||||
|
||||
@@ -152,6 +156,21 @@ gen_translations: #generating missing translations using google translate
|
||||
|
||||
android-release: android-apk-release
|
||||
|
||||
android-rename:
|
||||
@FULL_VER=$(VERSION_NAME).$(VERSION_BUILD); \
|
||||
OUT_DIR=build/app/outputs/flutter-apk; \
|
||||
echo "Renaming APKs in $$OUT_DIR to $(APP_NAME)-$$FULL_VER-<ABI>.apk"; \
|
||||
for SRC in "$$OUT_DIR"/app-*-release.apk; do \
|
||||
if [ -f "$$SRC" ]; then \
|
||||
FILENAME=$$(basename "$$SRC"); \
|
||||
TGT="$$OUT_DIR/$(APP_NAME)-$$FULL_VER-$${FILENAME#app-}"; \
|
||||
echo "Renaming $$SRC -> $$TGT"; \
|
||||
mv -v "$$SRC" "$$TGT"; \
|
||||
else \
|
||||
echo "Skip $$SRC, file not found"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
android-apk-release:
|
||||
echo flutter build apk --target $(TARGET) $(BUILD_ARGS) --target-platform android-arm,android-arm64,android-x64 --split-per-abi --verbose
|
||||
flutter build apk --target $(TARGET) $(BUILD_ARGS) --target-platform android-arm,android-arm64,android-x64 --verbose
|
||||
@@ -169,7 +188,7 @@ linux-release:
|
||||
flutter_distributor package --flutter-build-args=verbose --platform linux --targets deb,rpm,appimage $(DISTRIBUTOR_ARGS)
|
||||
|
||||
macos-release:
|
||||
flutter_distributor package --platform macos --targets dmg,pkg $(DISTRIBUTOR_ARGS)
|
||||
flutter_distributor package --platform macos --targets dmg $(DISTRIBUTOR_ARGS)
|
||||
|
||||
ios-release: #not tested
|
||||
flutter_distributor package --platform ios --targets ipa --build-export-options-plist ios/exportOptions.plist $(DISTRIBUTOR_ARGS)
|
||||
|
||||
@@ -57,7 +57,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId "app.hifastvpn.com"
|
||||
minSdkVersion flutter.minSdkVersion
|
||||
targetSdkVersion 36
|
||||
targetSdkVersion 34
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
multiDexEnabled true
|
||||
@@ -105,8 +105,8 @@ android {
|
||||
debugSymbolLevel 'FULL'
|
||||
}
|
||||
// 禁用代码混淆和资源压缩,解决VPN连接问题
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
@@ -148,6 +148,7 @@ dependencies {
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.0"
|
||||
implementation "androidx.annotation:annotation:1.7.1"
|
||||
implementation 'com.google.android.material:material:1.9.0'
|
||||
constraints {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.0") {
|
||||
because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib")
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<!-- 如果 targetSdkVersion >= 33 -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<application
|
||||
android:name=".Application"
|
||||
android:banner="@mipmap/ic_banner"
|
||||
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 24 KiB |
@@ -14,7 +14,7 @@ class ActiveGroupsChannel(private val scope: CoroutineScope) : FlutterPlugin,
|
||||
CommandClient.Handler {
|
||||
companion object {
|
||||
const val TAG = "A/ActiveGroupsChannel"
|
||||
const val CHANNEL = "com.baer.app/active-groups"
|
||||
const val CHANNEL = "com.hi.app/active-groups"
|
||||
val gson = Gson()
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ class EventHandler : FlutterPlugin {
|
||||
|
||||
companion object {
|
||||
const val TAG = "A/EventHandler"
|
||||
const val SERVICE_STATUS = "com.baer.app/service.status"
|
||||
const val SERVICE_ALERTS = "com.baer.app/service.alerts"
|
||||
const val SERVICE_STATUS = "com.hi.app/service.status"
|
||||
const val SERVICE_ALERTS = "com.hi.app/service.alerts"
|
||||
}
|
||||
|
||||
private var statusChannel: EventChannel? = null
|
||||
|
||||
@@ -12,7 +12,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
class GroupsChannel(private val scope: CoroutineScope) : FlutterPlugin, CommandClient.Handler {
|
||||
companion object {
|
||||
const val TAG = "A/GroupsChannel"
|
||||
const val CHANNEL = "com.baer.app/groups"
|
||||
const val CHANNEL = "com.hi.app/groups"
|
||||
val gson = Gson()
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class LogHandler : FlutterPlugin {
|
||||
|
||||
companion object {
|
||||
const val TAG = "A/LogHandler"
|
||||
const val SERVICE_LOGS = "com.baer.app/service.logs"
|
||||
const val SERVICE_LOGS = "com.hi.app/service.logs"
|
||||
}
|
||||
|
||||
private lateinit var logsChannel: EventChannel
|
||||
|
||||
@@ -21,7 +21,7 @@ class MethodHandler(private val scope: CoroutineScope) : FlutterPlugin,
|
||||
|
||||
companion object {
|
||||
const val TAG = "A/MethodHandler"
|
||||
const val channelName = "com.baer.app/method"
|
||||
const val channelName = "com.hi.app/method"
|
||||
|
||||
enum class Trigger(val method: String) {
|
||||
Setup("setup"),
|
||||
|
||||
@@ -33,7 +33,7 @@ class PlatformSettingsHandler : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
private lateinit var ignoreRequestResult: MethodChannel.Result
|
||||
|
||||
companion object {
|
||||
const val channelName = "com.baer.app/platform"
|
||||
const val channelName = "com.hi.app/platform"
|
||||
|
||||
const val REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = 44
|
||||
val gson = Gson()
|
||||
|
||||
@@ -11,7 +11,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
class StatsChannel(private val scope: CoroutineScope) : FlutterPlugin, CommandClient.Handler{
|
||||
companion object {
|
||||
const val TAG = "A/StatsChannel"
|
||||
const val STATS_CHANNEL = "com.baer.app/stats"
|
||||
const val STATS_CHANNEL = "com.hi.app/stats"
|
||||
}
|
||||
|
||||
private val commandClient =
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.hiddify.hiddify.constant
|
||||
|
||||
object Action {
|
||||
const val SERVICE = "com.baer.app.SERVICE"
|
||||
const val SERVICE_CLOSE = "com.baer.app.SERVICE_CLOSE"
|
||||
const val SERVICE_RELOAD = "com.baer.app.sfa.SERVICE_RELOAD"
|
||||
const val SERVICE = "com.hi.app.SERVICE"
|
||||
const val SERVICE_CLOSE = "com.hi.app.SERVICE_CLOSE"
|
||||
const val SERVICE_RELOAD = "com.hi.app.sfa.SERVICE_RELOAD"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 5.4 KiB |
@@ -1,21 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<style name="LaunchTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
|
||||
<item name="android:windowSplashScreenBackground">@drawable/launch_background</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<style name="NormalTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,22 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<style name="LaunchTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<style name="NormalTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,21 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<style name="LaunchTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
|
||||
<item name="android:windowSplashScreenBackground">#ffffff</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<style name="NormalTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,22 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<style name="LaunchTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<style name="NormalTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,10 +1,10 @@
|
||||
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_7_8207)">
|
||||
<path d="M13.0955 0.715332C13.4845 0.715332 13.7984 1.02021 13.7986 1.39795V11.4146C13.7986 11.7924 13.4846 12.0972 13.0955 12.0972H2.54565C2.02987 12.0972 1.60718 12.5075 1.60718 13.0083C1.60725 13.5091 2.02991 13.9185 2.54565 13.9185H13.0955C13.4846 13.9185 13.7986 14.2242 13.7986 14.6021C13.7984 14.9798 13.4845 15.2847 13.0955 15.2847H2.54565C1.25155 15.2847 0.201002 14.2648 0.200928 13.0083V2.9917C0.200975 1.73514 1.25153 0.715332 2.54565 0.715332H13.0955ZM2.54565 2.08154C2.0299 2.08154 1.60722 2.49092 1.60718 2.9917V10.9233C1.8932 10.8004 2.21274 10.7319 2.54565 10.7319H12.3923V2.08154H2.54565ZM6.50269 8.8833C6.76525 8.62836 7.23892 8.62839 7.49683 8.8833C7.76876 9.1519 7.7734 9.57952 7.49683 9.84814C7.22018 10.1168 6.77465 10.1122 6.50269 9.84814C6.22637 9.57955 6.22628 9.14729 6.50269 8.8833ZM5.64526 3.24268C6.12353 2.85115 6.75603 2.69168 7.37964 2.79639C8.23303 2.94208 8.93174 3.6201 9.08179 4.44873C9.23652 5.31833 8.80996 6.1884 8.02222 6.61182C7.8301 6.71198 7.70784 6.94816 7.70776 7.20752V7.31689C7.70776 7.69478 7.39381 7.9995 7.00464 7.99951C6.61545 7.99951 6.30151 7.69479 6.30151 7.31689V7.20752C6.3016 6.44273 6.70021 5.755 7.34253 5.41357C7.54404 5.30419 7.7597 5.04906 7.69409 4.68506C7.64706 4.41659 7.41202 4.18955 7.1355 4.14404C6.91992 4.10318 6.71359 4.15758 6.54956 4.28955C6.38559 4.42158 6.29663 4.61275 6.29663 4.81299C6.29661 5.19077 5.98255 5.49547 5.59351 5.49561C5.20434 5.49561 4.89041 5.19086 4.89038 4.81299C4.89038 4.2029 5.16699 3.63423 5.64526 3.24268Z" fill="#0F2C53"/>
|
||||
<path d="M12.8945 0C13.2836 0 13.5975 0.304873 13.5977 0.682617V10.6992C13.5977 11.0771 13.2837 11.3818 12.8945 11.3818H2.34473C1.82894 11.3818 1.40625 11.7921 1.40625 12.293C1.40632 12.7937 1.82899 13.2031 2.34473 13.2031H12.8945C13.2837 13.2031 13.5977 13.5088 13.5977 13.8867C13.5975 14.2644 13.2836 14.5693 12.8945 14.5693H2.34473C1.05062 14.5693 7.38806e-05 13.5495 0 12.293V2.27637C4.67804e-05 1.0198 1.0506 0 2.34473 0H12.8945ZM2.34473 1.36621C1.82897 1.36621 1.4063 1.77559 1.40625 2.27637V10.208C1.69228 10.0851 2.01181 10.0166 2.34473 10.0166H12.1914V1.36621H2.34473ZM6.30176 8.16797C6.56432 7.91302 7.03799 7.91306 7.2959 8.16797C7.56783 8.43657 7.57247 8.86419 7.2959 9.13281C7.01925 9.40143 6.57372 9.39688 6.30176 9.13281C6.02544 8.86422 6.02536 8.43196 6.30176 8.16797ZM5.44434 2.52734C5.9226 2.13582 6.5551 1.97635 7.17871 2.08105C8.0321 2.22675 8.73081 2.90477 8.88086 3.7334C9.03559 4.603 8.60903 5.47307 7.82129 5.89648C7.62917 5.99665 7.50691 6.23283 7.50684 6.49219V6.60156C7.50684 6.97945 7.19289 7.28417 6.80371 7.28418C6.41453 7.28418 6.10059 6.97945 6.10059 6.60156V6.49219C6.10067 5.7274 6.49928 5.03967 7.1416 4.69824C7.34312 4.58886 7.55877 4.33373 7.49316 3.96973C7.44613 3.70126 7.2111 3.47422 6.93457 3.42871C6.719 3.38785 6.51266 3.44225 6.34863 3.57422C6.18467 3.70625 6.0957 3.89742 6.0957 4.09766C6.09568 4.47544 5.78162 4.78013 5.39258 4.78027C5.00341 4.78027 4.68948 4.47553 4.68945 4.09766C4.68945 3.48757 4.96606 2.91889 5.44434 2.52734Z" fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7_8207">
|
||||
<rect width="13.598" height="14.5693" fill="white" transform="translate(0.200928 0.715332)"/>
|
||||
<rect width="13.598" height="14.5693" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1,3 +1,3 @@
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.96265 11.3523C3.78265 11.3523 4.44975 12.0196 4.44995 12.8396V13.6902C4.44977 14.0426 4.16566 14.3267 3.81323 14.3269H0.838623C0.486039 14.3269 0.201112 14.0427 0.200928 13.6902V12.8396C0.201128 12.0196 0.868226 11.3523 1.68823 11.3523H2.96265ZM12.3113 11.3523C13.1313 11.3523 13.7984 12.0196 13.7986 12.8396V13.6902C13.7984 14.0426 13.5143 14.3267 13.1619 14.3269H10.1873C9.83467 14.3269 9.54974 14.0427 9.54956 13.6902V12.8396C9.54976 12.0196 10.2169 11.3523 11.0369 11.3523H12.3113ZM6.99976 8.37769C7.3524 8.37769 7.63737 8.66275 7.63745 9.01538V10.8767L8.72534 11.9646C8.97586 12.2152 8.97571 12.6143 8.72534 12.865C8.47463 13.1157 8.07469 13.1157 7.82397 12.865L6.99976 12.0408L6.17554 12.865C5.92482 13.1157 5.52586 13.1157 5.27515 12.865C5.02444 12.6143 5.02444 12.2153 5.27515 11.9646L6.36206 10.8767V9.01538C6.36214 8.66281 6.64719 8.37778 6.99976 8.37769ZM1.68823 12.6277C1.56938 12.6277 1.47554 12.725 1.47534 12.8396V13.0525H3.17554V12.8396C3.17534 12.725 3.0815 12.6277 2.96265 12.6277H1.68823ZM11.0369 12.6277C10.918 12.6277 10.8242 12.725 10.824 12.8396V13.0525H12.5242V12.8396C12.524 12.725 12.4301 12.6277 12.3113 12.6277H11.0369ZM2.32593 7.31616C3.26485 7.31633 4.02507 8.07644 4.02515 9.01538C4.02515 9.95439 3.2649 10.7154 2.32593 10.7156C1.38682 10.7156 0.625732 9.95449 0.625732 9.01538C0.625813 8.07634 1.38687 7.31616 2.32593 7.31616ZM11.6746 7.31616C12.6135 7.31633 13.3737 8.07644 13.3738 9.01538C13.3738 9.95439 12.6135 10.7154 11.6746 10.7156C10.7354 10.7156 9.97437 9.95449 9.97437 9.01538C9.97445 8.07634 10.7355 7.31616 11.6746 7.31616ZM2.32593 8.59058C2.09226 8.59058 1.9012 8.78173 1.90112 9.01538C1.90112 9.2491 2.09221 9.44019 2.32593 9.44019C2.5595 9.44001 2.75073 9.24899 2.75073 9.01538C2.75065 8.78184 2.55945 8.59075 2.32593 8.59058ZM11.6746 8.59058C11.4409 8.59058 11.2498 8.78173 11.2498 9.01538C11.2498 9.2491 11.4408 9.44019 11.6746 9.44019C11.9081 9.44001 12.0994 9.24899 12.0994 9.01538C12.0993 8.78184 11.9081 8.59075 11.6746 8.59058ZM8.27515 4.55347C9.09503 4.55369 9.76235 5.22087 9.76245 6.04077V7.10327C9.76245 7.45592 9.47739 7.74089 9.12476 7.74097H4.87476C4.52228 7.74071 4.23804 7.45581 4.23804 7.10327V6.04077C4.23814 5.22073 4.90528 4.55347 5.72534 4.55347H8.27515ZM5.72534 5.82886C5.60643 5.82886 5.51256 5.92612 5.51245 6.04077V6.46558H8.48706V6.04077C8.48695 5.92625 8.39387 5.82908 8.27515 5.82886H5.72534ZM6.99976 0.729248C7.93887 0.729248 8.69995 1.49033 8.69995 2.42944C8.69971 3.36835 7.93872 4.12866 6.99976 4.12866C6.06087 4.12857 5.30078 3.36829 5.30054 2.42944C5.30054 1.49039 6.06072 0.729342 6.99976 0.729248ZM6.99976 2.00366C6.76612 2.00376 6.57495 2.19579 6.57495 2.42944C6.57519 2.6629 6.76627 2.85415 6.99976 2.85425C7.23332 2.85425 7.42432 2.66296 7.42456 2.42944C7.42456 2.19573 7.23347 2.00366 6.99976 2.00366Z" fill="#0F2C53"/>
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.76172 10.623C3.58173 10.623 4.24882 11.2904 4.24902 12.1104V12.9609C4.24884 13.3134 3.96473 13.5975 3.6123 13.5977H0.637695C0.285111 13.5977 0.000183976 13.3135 0 12.9609V12.1104C0.000199964 11.2904 0.667298 10.623 1.4873 10.623H2.76172ZM12.1104 10.623C12.9304 10.623 13.5975 11.2904 13.5977 12.1104V12.9609C13.5975 13.3134 13.3134 13.5975 12.9609 13.5977H9.98633C9.63374 13.5977 9.34882 13.3135 9.34863 12.9609V12.1104C9.34883 11.2904 10.0159 10.623 10.8359 10.623H12.1104ZM6.79883 7.64844C7.15148 7.64844 7.43644 7.9335 7.43652 8.28613V10.1475L8.52441 11.2354C8.77494 11.486 8.77478 11.885 8.52441 12.1357C8.2737 12.3865 7.87376 12.3865 7.62305 12.1357L6.79883 11.3115L5.97461 12.1357C5.7239 12.3865 5.32493 12.3865 5.07422 12.1357C4.82351 11.885 4.82351 11.4861 5.07422 11.2354L6.16113 10.1475V8.28613C6.16121 7.93356 6.44626 7.64853 6.79883 7.64844ZM1.4873 11.8984C1.36845 11.8984 1.27461 11.9958 1.27441 12.1104V12.3232H2.97461V12.1104C2.97441 11.9958 2.88057 11.8984 2.76172 11.8984H1.4873ZM10.8359 11.8984C10.7171 11.8984 10.6232 11.9958 10.623 12.1104V12.3232H12.3232V12.1104C12.323 11.9958 12.2292 11.8984 12.1104 11.8984H10.8359ZM2.125 6.58691C3.06392 6.58708 3.82414 7.34719 3.82422 8.28613C3.82422 9.22514 3.06397 9.98616 2.125 9.98633C1.18589 9.98633 0.424805 9.22524 0.424805 8.28613C0.424885 7.34709 1.18594 6.58691 2.125 6.58691ZM11.4736 6.58691C12.4125 6.58709 13.1728 7.3472 13.1729 8.28613C13.1729 9.22514 12.4126 9.98616 11.4736 9.98633C10.5345 9.98633 9.77344 9.22524 9.77344 8.28613C9.77352 7.34709 10.5346 6.58691 11.4736 6.58691ZM2.125 7.86133C1.89133 7.86133 1.70028 8.05249 1.7002 8.28613C1.7002 8.51985 1.89128 8.71094 2.125 8.71094C2.35857 8.71077 2.5498 8.51974 2.5498 8.28613C2.54972 8.05259 2.35852 7.8615 2.125 7.86133ZM11.4736 7.86133C11.24 7.86133 11.0489 8.05249 11.0488 8.28613C11.0488 8.51985 11.2399 8.71094 11.4736 8.71094C11.7072 8.71076 11.8984 8.51974 11.8984 8.28613C11.8984 8.05259 11.7072 7.8615 11.4736 7.86133ZM8.07422 3.82422C8.8941 3.82444 9.56142 4.49162 9.56152 5.31152V6.37402C9.56152 6.72668 9.27646 7.01164 8.92383 7.01172H4.67383C4.32135 7.01146 4.03711 6.72656 4.03711 6.37402V5.31152C4.03722 4.49148 4.70435 3.82422 5.52441 3.82422H8.07422ZM5.52441 5.09961C5.4055 5.09961 5.31163 5.19688 5.31152 5.31152V5.73633H8.28613V5.31152C8.28603 5.19701 8.19294 5.09983 8.07422 5.09961H5.52441ZM6.79883 0C7.73794 0 8.49902 0.761083 8.49902 1.7002C8.49878 2.6391 7.73779 3.39941 6.79883 3.39941C5.85994 3.39932 5.09985 2.63904 5.09961 1.7002C5.09961 0.761141 5.8598 9.36506e-05 6.79883 0ZM6.79883 1.27441C6.56519 1.27451 6.37402 1.46654 6.37402 1.7002C6.37427 1.93365 6.56534 2.12491 6.79883 2.125C7.0324 2.125 7.22339 1.93371 7.22363 1.7002C7.22363 1.46648 7.03254 1.27441 6.79883 1.27441Z" fill="black"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.8 KiB |
@@ -1,10 +1,10 @@
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_7_8212)">
|
||||
<path d="M13.1619 0.616089C13.5144 0.616273 13.7986 0.9012 13.7986 1.25378V9.75183C13.7986 10.1044 13.5144 10.3893 13.1619 10.3895H4.92651L1.28882 14.0272C0.889453 14.4265 0.201204 14.1462 0.200928 13.577V1.25378C0.200928 0.901086 0.485925 0.616089 0.838623 0.616089H13.1619ZM1.47534 12.038L4.21265 9.30164C4.33161 9.1828 4.49298 9.11511 4.66284 9.11511H12.5242V1.8905H1.47534V12.038ZM6.36206 5.078C6.36206 4.23663 7.63745 4.23663 7.63745 5.078V7.83972C7.63745 8.19242 7.35245 8.47742 6.99976 8.47742C6.64714 8.47732 6.36206 8.19236 6.36206 7.83972V5.078ZM6.54956 2.72839C6.78327 2.49043 7.21198 2.49045 7.44995 2.72839C7.70066 2.97911 7.69641 3.38232 7.44995 3.62878C7.20347 3.8751 6.80022 3.87945 6.54956 3.62878C6.30316 3.38237 6.299 2.97911 6.54956 2.72839Z" fill="#0F2C53"/>
|
||||
<path d="M12.9609 0C13.3135 0.000183671 13.5977 0.285111 13.5977 0.637695V9.13574C13.5977 9.48833 13.3135 9.77325 12.9609 9.77344H4.72559L1.08789 13.4111C0.688525 13.8105 0.000275843 13.5301 0 12.9609V0.637695C0 0.284997 0.284997 0 0.637695 0H12.9609ZM1.27441 11.4219L4.01172 8.68555C4.13068 8.56671 4.29205 8.49902 4.46191 8.49902H12.3232V1.27441H1.27441V11.4219ZM6.16113 4.46191C6.16113 3.62054 7.43652 3.62054 7.43652 4.46191V7.22363C7.43652 7.57633 7.15153 7.86133 6.79883 7.86133C6.44621 7.86124 6.16113 7.57627 6.16113 7.22363V4.46191ZM6.34863 2.1123C6.58234 1.87435 7.01105 1.87436 7.24902 2.1123C7.49974 2.36302 7.49549 2.76623 7.24902 3.0127C7.00255 3.25902 6.5993 3.26336 6.34863 3.0127C6.10224 2.76628 6.09807 2.36302 6.34863 2.1123Z" fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7_8212">
|
||||
<rect width="13.598" height="13.598" fill="white" transform="translate(0.200928 0.616089)"/>
|
||||
<rect width="13.598" height="13.598" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1012 B |
@@ -1,3 +1,3 @@
|
||||
<svg width="38" height="45" viewBox="0 0 38 45" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24.9375 26.0625H33.75V30.2812H23.75V45H14.6562V30.2812H4.71875V26.0625H13.4688L10.0625 19.25H3.40625V15H8L0.5 0.28125H11.0938L19.4062 19.75L27.3125 0.28125H37.4688L30.3438 15H34.8125V19.25H28.2812L24.9375 26.0625Z" fill="black"/>
|
||||
<svg width="32" height="58" viewBox="0 0 32 58" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 29.7812C8.02083 28.6146 5.20833 26.9896 3.5625 24.9062C1.9375 22.8229 1.125 20.3125 1.125 17.375C1.125 15.4375 1.4375 13.6771 2.0625 12.0938C2.70833 10.5104 3.60417 9.14583 4.75 8C6.22917 6.52083 7.875 5.5 9.6875 4.9375C10.7917 4.58333 12.4062 4.32292 14.5312 4.15625V0H17.5V4.21875C20.8958 4.48958 23.5625 5.32292 25.5 6.71875C29.0208 8.94792 30.8438 12.5625 30.9688 17.5625H22.75C22.5833 15.7083 22.2708 14.3542 21.8125 13.5C21.0208 12.0208 19.5833 11.2083 17.5 11.0625V22.9688C22.4583 24.6771 25.7917 26.1875 27.5 27.5C30.3125 29.6875 31.7188 32.7708 31.7188 36.75C31.7188 42 29.7917 45.8125 25.9375 48.1875C23.5833 49.6458 20.7917 50.5 17.5625 50.75V57.0312H14.5312V50.8125C10.4271 50.3542 7.36458 49.4583 5.34375 48.125C1.78125 45.7292 0.03125 41.6458 0.09375 35.875H8.53125C8.82292 38.5 9.22917 40.2604 9.75 41.1562C10.5625 42.5521 12.1562 43.4583 14.5312 43.875V30.5312L12 29.7812ZM17.5 31.5625V43.7812C19.1458 43.5729 20.3438 43.1979 21.0938 42.6562C22.4062 41.6979 23.0625 40.0417 23.0625 37.6875C23.0625 35.8958 22.4479 34.4792 21.2188 33.4375C20.4896 32.8333 19.25 32.2083 17.5 31.5625ZM14.5312 22.0938V11.125C12.7188 11.1667 11.375 11.6562 10.5 12.5938C9.625 13.5104 9.1875 14.7708 9.1875 16.375C9.1875 18.125 9.84375 19.5104 11.1562 20.5312C11.8854 21.0938 13.0104 21.6146 14.5312 22.0938Z" fill="black"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 343 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 835 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 279 B |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 759 B |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 724 B |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 935 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 1001 B |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 571 B |
|
Before Width: | Height: | Size: 333 B |