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: Download Enigma Virtual Box shell: powershell run: | Write-Host "下载 Enigma Virtual Box..." $enigmaUrl = "https://enigmaprotector.com/assets/files/enigmavb.exe" $enigmaPath = "C:\enigmavb.exe" try { Invoke-WebRequest -Uri $enigmaUrl -OutFile $enigmaPath -UseBasicParsing Write-Host "✅ Enigma Virtual Box 下载成功" } catch { Write-Host "⚠️ 下载失败,跳过 Enigma 打包" } - name: Package Single EXE shell: powershell run: | Write-Host "=== 开始打包单文件 EXE ===" $buildPath = "build\windows\x64\runner\Release" $outputPath = "dist" $enigmaPath = "C:\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" if (-not (Test-Path $7zipPath)) { Write-Host "安装 7-Zip..." choco install 7zip -y $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!`nTitle=\"HostExecutor Windows Package\"`nBeginPrompt=\"正在解压 HostExecutor...\"`nExtractDialogText=\"请稍候,正在解压文件...\"`nExtractPathText=\"解压路径:\"`nExtractTitle=\"解压中\"`nFinishMessage=\"解压完成!\"`nGUIFlags=\"8\"`n;!@InstallEnd@!" $configFile = "$outputPath\config.txt" Set-Content -Path $configFile -Value $configContent -Encoding UTF8 # 创建压缩包 & $7zipPath a -sfx "$outputSfx" "$buildPath\*" -mmt=on -mx=9 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()