fix+build(client/windows): 复查修缮——一键构建脚本 + 修 README dart-define 漏项 + 清 lint
- 新增 client/windows/build.ps1:拉内核→带 --dart-define 构建→出安装包一键串联, 规避 Release 漏 --dart-define 导致默认连 localhost、登录「网络请求失败」的坑。 - README:Release 命令补回 --dart-define 并加显式警告,指向一键脚本。 - 清 4 个 lint warning:desktop_vpn_bridge 多余 cast→pattern match、去多余非空断言; nav_sidebar 删未用 import;vpn_bridge_mock 加 killSwitchEnabled getter。 - 同步 window_manager/tray_manager/screen_retriever 插件注册生成文件(win+macos)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -213,8 +213,8 @@ class DesktopVpnBridge implements VpnBridge {
|
||||
_reconnectTimer = null;
|
||||
_kernelStatusSub?.cancel();
|
||||
_kernelStatusSub = null;
|
||||
if (_kernel is DesktopKernelProcess) {
|
||||
(_kernel as DesktopKernelProcess).dispose();
|
||||
if (_kernel case final DesktopKernelProcess k) {
|
||||
k.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ class DesktopVpnBridge implements VpnBridge {
|
||||
|
||||
Future<Directory> _resolveConfigDir() async {
|
||||
if (_configDirOverride != null) {
|
||||
return Directory(_configDirOverride!);
|
||||
return Directory(_configDirOverride);
|
||||
}
|
||||
return _defaultConfigDir();
|
||||
}
|
||||
|
||||
@@ -121,6 +121,9 @@ class VpnBridgeMock implements VpnBridge {
|
||||
_killSwitch = on;
|
||||
}
|
||||
|
||||
/// 测试可读:mock 记录的 kill-switch 状态。
|
||||
bool get killSwitchEnabled => _killSwitch;
|
||||
|
||||
@override
|
||||
Stream<VpnStatus> get statusStream => _statusCtrl.stream;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../pangolin_theme.dart';
|
||||
import '../state/app_providers.dart';
|
||||
import '../state/navigation_provider.dart';
|
||||
import 'pangolin_icons.dart';
|
||||
import 'pangolin_logo.dart';
|
||||
import 'plan_badge_card.dart';
|
||||
|
||||
|
||||
@@ -7,10 +7,16 @@ import Foundation
|
||||
|
||||
import flutter_secure_storage_macos
|
||||
import package_info_plus
|
||||
import screen_retriever_macos
|
||||
import shared_preferences_foundation
|
||||
import tray_manager
|
||||
import window_manager
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin"))
|
||||
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
||||
}
|
||||
|
||||
@@ -49,10 +49,23 @@ flutter run -d windows --dart-define=PANGOLIN_API_URL=http://<后端IP>:8080
|
||||
|
||||
## 打包(release)
|
||||
|
||||
**推荐:一键脚本**(拉内核 → 带 dart-define 构建 → 出安装包,自动避开漏 `--dart-define` 的坑):
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File client\windows\build.ps1 -ApiUrl http://<后端IP>:8080
|
||||
# 只构建不出安装包:加 -SkipInstaller
|
||||
```
|
||||
|
||||
或手动分步:
|
||||
|
||||
```powershell
|
||||
cd client
|
||||
flutter build windows
|
||||
# 必须带 --dart-define 指定后端,否则默认连 localhost:8080,登录会「网络请求失败」
|
||||
flutter build windows --dart-define=PANGOLIN_API_URL=http://<后端IP>:8080
|
||||
```
|
||||
> ⚠️ `kApiBaseUrl` 默认值是 `http://localhost:8080`(见 `lib/services/api_config.dart`)。
|
||||
> Release 包必须显式 `--dart-define=PANGOLIN_API_URL=...`,构建期烘进二进制;漏了会复现登录失败。
|
||||
|
||||
CMake 的 install 步骤会自动把 `app/kernel/dist/desktop/windows-*/{sing-box.exe, wintun.dll}`
|
||||
拷到 app `.exe` 同级目录(见 `windows/CMakeLists.txt` 的「Pangolin sing-box kernel」段)。
|
||||
**wintun.dll 必须与 sing-box.exe 同目录**,否则 sing-box 无法创建 TUN。
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Pangolin Windows 客户端一键构建脚本(拉内核 → 带 dart-define 构建 → 出安装包)。
|
||||
|
||||
.DESCRIPTION
|
||||
串起 client/windows/README.md 里的三步手动流程,避免漏掉 --dart-define
|
||||
(漏了会默认连 localhost:8080,登录「网络请求失败」)。
|
||||
|
||||
步骤:
|
||||
1. bash app/kernel/fetch-desktop-bin.sh windows <arch> (拉 sing-box.exe + wintun.dll,SHA 校验)
|
||||
2. flutter build windows --release --dart-define=PANGOLIN_API_URL=<ApiUrl>
|
||||
3. ISCC.exe installer\pangolin.iss (除非 -SkipInstaller)
|
||||
|
||||
.PARAMETER ApiUrl
|
||||
必填。后端地址,会在构建期烘进二进制,例:http://103.119.13.48:8080
|
||||
|
||||
.PARAMETER Arch
|
||||
CPU 架构,默认 amd64。
|
||||
|
||||
.PARAMETER SkipInstaller
|
||||
只构建,不出 Inno Setup 安装包。
|
||||
|
||||
.EXAMPLE
|
||||
powershell -ExecutionPolicy Bypass -File client\windows\build.ps1 -ApiUrl http://103.119.13.48:8080
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ApiUrl,
|
||||
|
||||
[string]$Arch = "amd64",
|
||||
|
||||
[switch]$SkipInstaller
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# 路径解析:本脚本在 client/windows/ 下
|
||||
$WindowsDir = $PSScriptRoot
|
||||
$ClientDir = Split-Path -Parent $WindowsDir
|
||||
$RepoRoot = Split-Path -Parent $ClientDir
|
||||
|
||||
function Step([string]$msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan }
|
||||
|
||||
# ── 1. 拉内核(sing-box.exe + wintun.dll)─────────────────────────────────────
|
||||
Step "拉取 sing-box.exe + wintun.dll (windows $Arch)"
|
||||
$bash = Get-Command bash -ErrorAction SilentlyContinue
|
||||
if (-not $bash) {
|
||||
throw "未找到 bash(fetch 脚本需 Git Bash)。请安装 Git for Windows 后重试。"
|
||||
}
|
||||
$fetchScript = Join-Path $RepoRoot "app/kernel/fetch-desktop-bin.sh"
|
||||
& $bash.Source $fetchScript windows $Arch
|
||||
if ($LASTEXITCODE -ne 0) { throw "内核拉取失败 (exit $LASTEXITCODE)" }
|
||||
|
||||
# ── 2. Flutter 构建(必须带 dart-define)──────────────────────────────────────
|
||||
Step "flutter build windows --release (PANGOLIN_API_URL=$ApiUrl)"
|
||||
Push-Location $ClientDir
|
||||
try {
|
||||
flutter build windows --release --dart-define=PANGOLIN_API_URL=$ApiUrl
|
||||
if ($LASTEXITCODE -ne 0) { throw "flutter build 失败 (exit $LASTEXITCODE)" }
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
$releaseDir = Join-Path $ClientDir "build\windows\x64\runner\Release"
|
||||
Write-Host "构建产物:$releaseDir" -ForegroundColor Green
|
||||
|
||||
# ── 3. 出安装包(Inno Setup)──────────────────────────────────────────────────
|
||||
if ($SkipInstaller) {
|
||||
Step "跳过安装包(-SkipInstaller)"
|
||||
return
|
||||
}
|
||||
|
||||
Step "编译 Inno Setup 安装包"
|
||||
$iscc = $null
|
||||
foreach ($p in @(
|
||||
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe",
|
||||
"C:\Program Files\Inno Setup 6\ISCC.exe")) {
|
||||
if (Test-Path $p) { $iscc = $p; break }
|
||||
}
|
||||
if (-not $iscc) {
|
||||
$cmd = Get-Command ISCC.exe -ErrorAction SilentlyContinue
|
||||
if ($cmd) { $iscc = $cmd.Source }
|
||||
}
|
||||
if (-not $iscc) {
|
||||
Write-Warning "未找到 ISCC.exe(Inno Setup 6 未安装)。已完成构建,跳过安装包。"
|
||||
Write-Warning "装好 Inno Setup 6 后可手动:ISCC.exe `"$WindowsDir\installer\pangolin.iss`""
|
||||
return
|
||||
}
|
||||
|
||||
$iss = Join-Path $WindowsDir "installer\pangolin.iss"
|
||||
& $iscc $iss
|
||||
if ($LASTEXITCODE -ne 0) { throw "ISCC 编译失败 (exit $LASTEXITCODE)" }
|
||||
|
||||
$output = Join-Path $WindowsDir "installer\Output"
|
||||
Write-Host "`n✓ 全部完成。安装包在:$output" -ForegroundColor Green
|
||||
@@ -7,8 +7,17 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>
|
||||
#include <tray_manager/tray_manager_plugin.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||
ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi"));
|
||||
TrayManagerPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("TrayManagerPlugin"));
|
||||
WindowManagerPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("WindowManagerPlugin"));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
flutter_secure_storage_windows
|
||||
screen_retriever_windows
|
||||
tray_manager
|
||||
window_manager
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
Reference in New Issue
Block a user