windows路径问题
(cherry picked from commit 9cefb1b9e009575ee7f6a5aef631cb344b6e1df8)
This commit is contained in:
parent
0067017ca6
commit
9c2f9be6c5
@ -177,37 +177,226 @@ class KRSingBoxImp {
|
||||
final workingDir =
|
||||
Platform.isAndroid ? await getExternalStorageDirectory() : baseDir;
|
||||
final tempDir = await getTemporaryDirectory();
|
||||
|
||||
// Windows 路径规范化:确保使用正确的路径分隔符
|
||||
Directory normalizePath(Directory dir) {
|
||||
if (Platform.isWindows) {
|
||||
final normalized = dir.path.replaceAll('/', '\\');
|
||||
if (normalized != dir.path) {
|
||||
KRLogUtil.kr_i('路径规范化: ${dir.path} -> $normalized', tag: 'SingBox');
|
||||
return Directory(normalized);
|
||||
}
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
kr_configDics = (
|
||||
baseDir: baseDir,
|
||||
workingDir: workingDir!,
|
||||
tempDir: tempDir,
|
||||
baseDir: normalizePath(baseDir),
|
||||
workingDir: normalizePath(workingDir!),
|
||||
tempDir: normalizePath(tempDir),
|
||||
);
|
||||
KRLogUtil.kr_i('其他平台路径初始化完成');
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i('开始创建目录');
|
||||
KRLogUtil.kr_i('baseDir: ${kr_configDics.baseDir.path}', tag: 'SingBox');
|
||||
KRLogUtil.kr_i('workingDir: ${kr_configDics.workingDir.path}', tag: 'SingBox');
|
||||
KRLogUtil.kr_i('tempDir: ${kr_configDics.tempDir.path}', tag: 'SingBox');
|
||||
|
||||
// 确保所有目录都存在
|
||||
if (!kr_configDics.baseDir.existsSync()) {
|
||||
await kr_configDics.baseDir.create(recursive: true);
|
||||
KRLogUtil.kr_i('已创建 baseDir', tag: 'SingBox');
|
||||
}
|
||||
if (!kr_configDics.workingDir.existsSync()) {
|
||||
await kr_configDics.workingDir.create(recursive: true);
|
||||
KRLogUtil.kr_i('已创建 workingDir', tag: 'SingBox');
|
||||
}
|
||||
if (!kr_configDics.tempDir.existsSync()) {
|
||||
await kr_configDics.tempDir.create(recursive: true);
|
||||
KRLogUtil.kr_i('已创建 tempDir', tag: 'SingBox');
|
||||
}
|
||||
|
||||
// 创建 libcore 数据库所需的 data 目录(在 workingDir 下)
|
||||
// 注意:libcore 的 Setup 会调用 os.Chdir(workingPath),所以 data 目录必须在 workingDir 下
|
||||
final dataDir = Directory(p.join(kr_configDics.workingDir.path, 'data'));
|
||||
|
||||
// 强制确保 data 目录存在(Windows 可能需要多次尝试)
|
||||
int retryCount = 0;
|
||||
const maxRetries = 5;
|
||||
while (!dataDir.existsSync() && retryCount < maxRetries) {
|
||||
try {
|
||||
await dataDir.create(recursive: true);
|
||||
// 等待文件系统同步(Windows 上可能需要一点时间)
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
// 验证目录确实创建成功
|
||||
if (dataDir.existsSync()) {
|
||||
KRLogUtil.kr_i('✅ 已创建 data 目录: ${dataDir.path}', tag: 'SingBox');
|
||||
break;
|
||||
} else {
|
||||
retryCount++;
|
||||
KRLogUtil.kr_i('⚠️ data 目录创建后验证失败,重试 $retryCount/$maxRetries', tag: 'SingBox');
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
}
|
||||
} catch (e) {
|
||||
retryCount++;
|
||||
KRLogUtil.kr_e('❌ 创建 data 目录失败 (尝试 $retryCount/$maxRetries): $e', tag: 'SingBox');
|
||||
if (retryCount >= maxRetries) {
|
||||
throw Exception('无法创建 libcore 数据库目录: ${dataDir.path},错误: $e');
|
||||
}
|
||||
final delayMs = 200 * retryCount;
|
||||
await Future.delayed(Duration(milliseconds: delayMs));
|
||||
}
|
||||
}
|
||||
|
||||
if (!dataDir.existsSync()) {
|
||||
final error = 'data 目录不存在: ${dataDir.path}';
|
||||
KRLogUtil.kr_e('❌ $error', tag: 'SingBox');
|
||||
throw Exception(error);
|
||||
}
|
||||
|
||||
// 验证目录权限(尝试创建一个测试文件)
|
||||
try {
|
||||
final testFile = File(p.join(dataDir.path, '.test_write'));
|
||||
await testFile.writeAsString('test');
|
||||
await testFile.delete();
|
||||
KRLogUtil.kr_i('✅ data 目录写入权限验证通过', tag: 'SingBox');
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('⚠️ data 目录写入权限验证失败: $e', tag: 'SingBox');
|
||||
// 不抛出异常,让 libcore 自己处理
|
||||
}
|
||||
|
||||
// 在 Windows 上额外等待,确保文件系统操作完成
|
||||
if (Platform.isWindows) {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
KRLogUtil.kr_i('⏳ Windows 文件系统同步等待完成', tag: 'SingBox');
|
||||
}
|
||||
|
||||
// 最终验证:在 setup() 之前再次确认 workingDir 和 data 目录都存在且可访问
|
||||
// libcore 的 Setup() 会调用 os.Chdir(workingPath),然后使用相对路径 "./data"
|
||||
// 如果 os.Chdir() 失败(路径不存在或权限问题),后续的相对路径访问会失败
|
||||
if (!kr_configDics.workingDir.existsSync()) {
|
||||
final error = '❌ workingDir 不存在,无法调用 setup(): ${kr_configDics.workingDir.path}';
|
||||
KRLogUtil.kr_e(error, tag: 'SingBox');
|
||||
throw Exception(error);
|
||||
}
|
||||
|
||||
// 验证 workingDir 可读可写
|
||||
try {
|
||||
final testWorkingFile = File(p.join(kr_configDics.workingDir.path, '.test_working_dir'));
|
||||
await testWorkingFile.writeAsString('test');
|
||||
await testWorkingFile.delete();
|
||||
KRLogUtil.kr_i('✅ workingDir 写入权限验证通过', tag: 'SingBox');
|
||||
} catch (e) {
|
||||
final error = '❌ workingDir 无写入权限: ${kr_configDics.workingDir.path}, 错误: $e';
|
||||
KRLogUtil.kr_e(error, tag: 'SingBox');
|
||||
throw Exception(error);
|
||||
}
|
||||
|
||||
final finalDataDir = Directory(p.join(kr_configDics.workingDir.path, 'data'));
|
||||
if (!finalDataDir.existsSync()) {
|
||||
KRLogUtil.kr_e('❌ 最终验证失败:data 目录不存在', tag: 'SingBox');
|
||||
KRLogUtil.kr_e('路径: ${finalDataDir.path}', tag: 'SingBox');
|
||||
KRLogUtil.kr_e('workingDir 是否存在: ${kr_configDics.workingDir.existsSync()}', tag: 'SingBox');
|
||||
if (kr_configDics.workingDir.existsSync()) {
|
||||
try {
|
||||
final workingDirContents = kr_configDics.workingDir.listSync();
|
||||
KRLogUtil.kr_e('workingDir 内容: ${workingDirContents.map((e) => e.path.split(Platform.pathSeparator).last).join(", ")}', tag: 'SingBox');
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('无法列出 workingDir 内容: $e', tag: 'SingBox');
|
||||
}
|
||||
}
|
||||
throw Exception('data 目录在 setup() 前验证失败: ${finalDataDir.path}');
|
||||
}
|
||||
|
||||
// 再次尝试写入测试,确保目录确实可用
|
||||
try {
|
||||
final verifyFile = File(p.join(finalDataDir.path, '.verify_setup'));
|
||||
await verifyFile.writeAsString('verify');
|
||||
await verifyFile.delete();
|
||||
KRLogUtil.kr_i('✅ setup() 前最终验证通过', tag: 'SingBox');
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('❌ setup() 前最终验证失败: $e', tag: 'SingBox');
|
||||
// 不抛出异常,让 setup() 自己处理
|
||||
}
|
||||
|
||||
if (!directory.existsSync()) {
|
||||
await directory.create(recursive: true);
|
||||
KRLogUtil.kr_i('已创建 configs 目录', tag: 'SingBox');
|
||||
}
|
||||
KRLogUtil.kr_i('目录创建完成', tag: 'SingBox');
|
||||
|
||||
KRLogUtil.kr_i('开始设置 SingBox', tag: 'SingBox');
|
||||
KRLogUtil.kr_i(' - baseDir: ${kr_configDics.baseDir.path}', tag: 'SingBox');
|
||||
KRLogUtil.kr_i(' - workingDir: ${kr_configDics.workingDir.path}', tag: 'SingBox');
|
||||
KRLogUtil.kr_i(' - tempDir: ${kr_configDics.tempDir.path}', tag: 'SingBox');
|
||||
KRLogUtil.kr_i(' - data 目录: ${p.join(kr_configDics.workingDir.path, "data")}', tag: 'SingBox');
|
||||
KRLogUtil.kr_i(' - data 目录存在: ${finalDataDir.existsSync()}', tag: 'SingBox');
|
||||
|
||||
// 在 Windows 上,列出 data 目录内容(如果有文件)
|
||||
if (Platform.isWindows && finalDataDir.existsSync()) {
|
||||
try {
|
||||
final dataContents = finalDataDir.listSync();
|
||||
if (dataContents.isNotEmpty) {
|
||||
KRLogUtil.kr_i(' - data 目录现有文件: ${dataContents.map((e) => e.path.split(Platform.pathSeparator).last).join(", ")}', tag: 'SingBox');
|
||||
} else {
|
||||
KRLogUtil.kr_i(' - data 目录为空', tag: 'SingBox');
|
||||
}
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e(' - 无法列出 data 目录内容: $e', tag: 'SingBox');
|
||||
}
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i(' - libcore 将通过 os.Chdir() 切换到: ${kr_configDics.workingDir.path}', tag: 'SingBox');
|
||||
KRLogUtil.kr_i(' - 然后使用相对路径 "./data" 访问数据库', tag: 'SingBox');
|
||||
|
||||
// Windows 特定:验证路径格式是否正确
|
||||
if (Platform.isWindows) {
|
||||
final workingPath = kr_configDics.workingDir.path;
|
||||
if (workingPath.contains('/')) {
|
||||
KRLogUtil.kr_e('⚠️ 警告:Windows 路径包含正斜杠,可能导致问题: $workingPath', tag: 'SingBox');
|
||||
}
|
||||
// 确保路径使用反斜杠(Windows 标准)
|
||||
final normalizedPath = workingPath.replaceAll('/', '\\');
|
||||
if (normalizedPath != workingPath) {
|
||||
KRLogUtil.kr_e('⚠️ 路径格式可能需要规范化: $workingPath -> $normalizedPath', tag: 'SingBox');
|
||||
}
|
||||
}
|
||||
KRLogUtil.kr_i('目录创建完成');
|
||||
|
||||
KRLogUtil.kr_i('开始设置 SingBox');
|
||||
await kr_singBox.setup(kr_configDics, false).map((r) {
|
||||
KRLogUtil.kr_i('SingBox 设置成功');
|
||||
KRLogUtil.kr_i('✅ SingBox setup() 调用成功', tag: 'SingBox');
|
||||
|
||||
// setup() 返回成功,但可能数据库初始化还在进行中
|
||||
// 在 Windows 上额外等待,确保 libcore 内部的服务初始化完成
|
||||
if (Platform.isWindows) {
|
||||
KRLogUtil.kr_i('⏳ Windows: 等待 libcore 服务初始化完成...', tag: 'SingBox');
|
||||
}
|
||||
return r;
|
||||
}).mapLeft((err) {
|
||||
KRLogUtil.kr_e('SingBox 设置失败: $err');
|
||||
KRLogUtil.kr_e('❌ SingBox setup() 调用失败: $err', tag: 'SingBox');
|
||||
KRLogUtil.kr_e('诊断信息:', tag: 'SingBox');
|
||||
KRLogUtil.kr_e(' - workingDir: ${kr_configDics.workingDir.path}', tag: 'SingBox');
|
||||
KRLogUtil.kr_e(' - workingDir 存在: ${kr_configDics.workingDir.existsSync()}', tag: 'SingBox');
|
||||
KRLogUtil.kr_e(' - data 目录绝对路径: ${p.join(kr_configDics.workingDir.path, "data")}', tag: 'SingBox');
|
||||
KRLogUtil.kr_e(' - data 目录存在: ${finalDataDir.existsSync()}', tag: 'SingBox');
|
||||
if (finalDataDir.existsSync()) {
|
||||
try {
|
||||
final files = finalDataDir.listSync();
|
||||
KRLogUtil.kr_e(' - data 目录文件数量: ${files.length}', tag: 'SingBox');
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e(' - 无法列出 data 目录: $e', tag: 'SingBox');
|
||||
}
|
||||
}
|
||||
throw err;
|
||||
}).run();
|
||||
|
||||
// setup() 成功后的额外等待(Windows 上数据库初始化可能需要时间)
|
||||
if (Platform.isWindows) {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
KRLogUtil.kr_i('⏳ Windows: libcore 初始化等待完成', tag: 'SingBox');
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i('开始更新 SingBox 选项');
|
||||
KRLogUtil.kr_i('📋 SingBox 配置选项: ${oOption.toJson()}', tag: 'SingBox');
|
||||
await kr_singBox.changeOptions(oOption)
|
||||
|
||||
@ -27,6 +27,13 @@ class KRSecureStorage {
|
||||
if (Platform.isMacOS || Platform.isWindows || Platform.isLinux) {
|
||||
final baseDir = await getApplicationSupportDirectory();
|
||||
KRLogUtil.kr_i('初始化 Hive,路径: ${baseDir.path}', tag: 'SecureStorage');
|
||||
|
||||
// 确保目录存在
|
||||
if (!baseDir.existsSync()) {
|
||||
await baseDir.create(recursive: true);
|
||||
KRLogUtil.kr_i('已创建 Hive 目录: ${baseDir.path}', tag: 'SecureStorage');
|
||||
}
|
||||
|
||||
await Hive.initFlutter(baseDir.path);
|
||||
} else {
|
||||
// Android 和 iOS 使用默认路径
|
||||
@ -39,6 +46,7 @@ class KRSecureStorage {
|
||||
KRLogUtil.kr_i('Hive 初始化成功', tag: 'SecureStorage');
|
||||
} catch (e, stackTrace) {
|
||||
KRLogUtil.kr_e('初始化 Hive 失败: $e', tag: 'SecureStorage');
|
||||
KRLogUtil.kr_e('错误类型: ${e.runtimeType}', tag: 'SecureStorage');
|
||||
KRLogUtil.kr_e('错误堆栈: $stackTrace', tag: 'SecureStorage');
|
||||
|
||||
// 对于 Windows 和 Linux,如果初始化失败,尝试删除旧文件并重试
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(BearVPN LANGUAGES CXX)
|
||||
|
||||
# 设置 CMake 策略以兼容旧版本插件
|
||||
# CMP0175: add_custom_command() 拒绝无效参数(用于兼容 flutter_inappwebview_windows 插件)
|
||||
if(POLICY CMP0175)
|
||||
cmake_policy(SET CMP0175 OLD)
|
||||
endif()
|
||||
|
||||
# 设置静态链接
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user