From 5f2fb90bb287a6a23757850ffe527a99aee71e94 Mon Sep 17 00:00:00 2001 From: speakeloudest Date: Fri, 9 Jan 2026 06:57:28 -0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=B2=BE=E7=AE=80=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- debug_connection_status.dart | 74 ------ docs/CLASH_ARCHITECTURE.md | 255 ------------------- docs/CLASH_BUILD_GUIDE.md | 345 -------------------------- docs/CLASH_TROUBLESHOOTING.md | 441 --------------------------------- docs/README.md | 269 -------------------- docs/go修复.md | 318 ------------------------ scripts/DATA_CLEANUP_README.md | 302 ---------------------- scripts/clean_build_cache.sh | 90 ------- test_singbox_url_test.dart | 41 --- test_trojan_connection.dart | 42 ---- 10 files changed, 2177 deletions(-) delete mode 100644 debug_connection_status.dart delete mode 100644 docs/CLASH_ARCHITECTURE.md delete mode 100644 docs/CLASH_BUILD_GUIDE.md delete mode 100644 docs/CLASH_TROUBLESHOOTING.md delete mode 100644 docs/README.md delete mode 100644 docs/go修复.md delete mode 100644 scripts/DATA_CLEANUP_README.md delete mode 100755 scripts/clean_build_cache.sh delete mode 100755 test_singbox_url_test.dart delete mode 100755 test_trojan_connection.dart diff --git a/debug_connection_status.dart b/debug_connection_status.dart deleted file mode 100644 index 47d1f99..0000000 --- a/debug_connection_status.dart +++ /dev/null @@ -1,74 +0,0 @@ -// 连接状态调试工具 -// 用于诊断连接后一直显示 connecting 的问题 - -import 'package:get/get.dart'; -import 'package:kaer_with_panels/app/services/singbox_imp/kr_sing_box_imp.dart'; -import 'package:kaer_with_panels/app/modules/kr_home/controllers/kr_home_controller.dart'; -import 'package:kaer_with_panels/app/localization/app_translations.dart'; - -class ConnectionStatusDebugger { - static void debugConnectionStatus() { - print('🔍 === 连接状态调试信息 ==='); - - // 1. 检查 SingBox 状态 - final singboxStatus = KRSingBoxImp.instance.kr_status.value; - print('📊 SingBox 状态: $singboxStatus'); - print('📊 SingBox 状态类型: ${singboxStatus.runtimeType}'); - - // 2. 检查首页控制器状态 - try { - final homeController = Get.find(); - print('🏠 首页控制器连接文本: ${homeController.kr_connectText.value}'); - print('🏠 首页控制器是否连接: ${homeController.kr_isConnected.value}'); - print('🏠 首页控制器当前速度: ${homeController.kr_currentSpeed.value}'); - print('🏠 首页控制器节点延迟: ${homeController.kr_currentNodeLatency.value}'); - } catch (e) { - print('❌ 无法获取首页控制器: $e'); - } - - // 3. 检查活动组 - final activeGroups = KRSingBoxImp.instance.kr_activeGroups; - print('📋 活动组数量: ${activeGroups.length}'); - for (int i = 0; i < activeGroups.length; i++) { - final group = activeGroups[i]; - print(' └─ 组[$i]: tag=${group.tag}, type=${group.type}, selected=${group.selected}'); - } - - // 4. 检查状态监听器 - print('🔄 状态监听器状态:'); - KRSingBoxImp.instance.kr_status.listen((status) { - print(' └─ 状态变化: $status (${status.runtimeType})'); - }); - - print('🔍 === 调试信息结束 ==='); - } - - static void forceStatusSync() { - print('🔄 强制同步连接状态...'); - try { - final homeController = Get.find(); - homeController.kr_forceSyncConnectionStatus(); - print('✅ 状态同步完成'); - } catch (e) { - print('❌ 状态同步失败: $e'); - } - } - - static void testConnectionFlow() { - print('🧪 测试连接流程...'); - - // 模拟连接流程 - print('1. 开始连接...'); - KRSingBoxImp.instance.kr_start().then((_) { - print('2. 连接启动完成'); - - // 等待状态更新 - Future.delayed(const Duration(seconds: 3), () { - print('3. 检查连接状态...'); - debugConnectionStatus(); - }); - }).catchError((e) { - print('❌ 连接失败: $e'); - }); - } -} diff --git a/docs/CLASH_ARCHITECTURE.md b/docs/CLASH_ARCHITECTURE.md deleted file mode 100644 index 3779d73..0000000 --- a/docs/CLASH_ARCHITECTURE.md +++ /dev/null @@ -1,255 +0,0 @@ -# Clash Meta 核心架构文档 - -## 架构概览 - -LighthouseApp 使用 Clash Meta (Mihomo) 作为核心代理引擎,替代原有的 sing-box 实现。 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Flutter Application │ -├─────────────────────────────────────────────────────────────┤ -│ Dart Layer │ -│ ┌──────────────────────────────────────────────────────┐ │ -│ │ KRClashImp (lib/app/services/clash_imp/) │ │ -│ │ • kr_clash_imp.dart - 核心封装 │ │ -│ │ • clash_ffi.dart - FFI 绑定 │ │ -│ │ • clash_config_generator - YAML 配置生成 │ │ -│ │ • clash_service_handler - 服务处理器 │ │ -│ └──────────────────┬───────────────────────────────────┘ │ -│ │ dart:ffi │ -├─────────────────────┼───────────────────────────────────────┤ -│ Android Native │ │ -│ ┌──────────────────▼───────────────────────────────────┐ │ -│ │ ClashService (Kotlin) │ │ -│ │ • VPNService.kt - VPN 服务入口 │ │ -│ │ • ClashService.kt - Clash 服务管理 │ │ -│ │ • Service Isolate - 后台 Dart 运行时 │ │ -│ └──────────────────┬───────────────────────────────────┘ │ -│ │ JNI │ -│ ┌──────────────────▼───────────────────────────────────┐ │ -│ │ libclash.so (Go + C) │ │ -│ │ • quickStart() - 启动核心 │ │ -│ │ • getAndroidVpnOptions() - 获取 VPN 配置 │ │ -│ │ • startTUN() - 启动 TUN 设备 │ │ -│ │ • getTraffic() - 流量统计 │ │ -│ └──────────────────┬───────────────────────────────────┘ │ -│ │ │ -├─────────────────────┼───────────────────────────────────────┤ -│ Go Core │ │ -│ ┌──────────────────▼───────────────────────────────────┐ │ -│ │ Clash.Meta (Mihomo) │ │ -│ │ • TUN 设备管理 │ │ -│ │ • 路由策略 (bypass-LAN) │ │ -│ │ • 代理协议支持 (SS/Trojan/VMess/...) │ │ -│ │ • DNS 解析 │ │ -│ │ • 流量统计 │ │ -│ └──────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - -## 核心组件 - -### 1. Dart FFI 层 (`kr_clash_imp.dart`) - -**职责:** -- 提供与 Go 核心的 FFI 通信接口 -- 管理核心生命周期 (启动/停止) -- 配置文件生成和管理 -- 并发安全的初始化机制 - -**关键方法:** -- `start()` - 启动 Clash 核心 -- `stop()` - 停止核心 -- `getAndroidVpnOptions()` - 获取 VPN 路由配置 (关键!) -- `startTun()` - 启动 TUN 设备 - -**并发安全设计:** -```dart -// 使用 Completer 实现初始化锁 -Completer? _initLock; - -Future _ensureInitialized() async { - if (_initialized) return; - if (_initLock != null) { - await _initLock!.future; // 等待其他初始化完成 - return; - } - // 执行初始化... -} -``` - -### 2. Android Service 层 (`ClashService.kt`) - -**职责:** -- 管理 VPN 服务生命周期 -- 创建 Service Isolate (后台 Dart 运行时) -- 处理系统 VPN 权限 -- 注册底层网络回调 (修复模拟器兼容性) - -**Service Isolate 架构:** -```kotlin -// 创建独立的 FlutterEngine 用于后台服务 -serviceEngine = FlutterEngine(Application.application) - -// 执行 Dart Service 入口点 -val entrypoint = DartExecutor.DartEntrypoint( - FlutterInjector.instance().flutterLoader().findAppBundlePath(), - "_clashService" // 在 lib/main.dart 中定义 -) -serviceEngine?.dartExecutor?.executeDartEntrypoint(entrypoint) -``` - -### 3. Go 核心层 (`core/`) - -**目录结构:** -``` -core/ -├── Clash.Meta/ # Git 子模块,Mihomo 核心 -├── go.mod # Go 依赖管理 -├── lib_android.go # Android JNI 桥接 -├── action.go # 核心操作接口 -└── hub.go # HTTP API 服务器 -``` - -**关键桥接函数:** -```go -//export quickStart -func quickStart(initParams, params, stateParams *C.char, port C.longlong) - -//export getAndroidVpnOptions -func getAndroidVpnOptions() *C.char // 返回详细路由配置! - -//export startTUN -func startTUN(fd C.int, callback unsafe.Pointer) C.int -``` - -## 数据流 - -### 启动流程 - -``` -1. Flutter UI (用户点击连接) - │ - ├──> KRClashImp.start() - │ ├─ 生成 Clash 配置 YAML - │ ├─ 调用 FFI: quickStart() - │ └─ 等待启动回调 - │ - ├──> libclash.so: quickStart() - │ ├─ 初始化 Clash Meta 核心 - │ ├─ 解析配置文件 - │ └─ 启动监听器 - │ - ├──> ClashService.kt - │ ├─ 调用 VpnService.prepare() - │ ├─ 获取 VPN 权限 - │ └─ 建立 TUN 接口 - │ - ├──> KRClashImp.getAndroidVpnOptions() ⭐ 关键! - │ └─ 获取 35+ CIDR 路由列表 - │ - └──> VPNService.kt: 配置 VPN Builder - ├─ addAddress("172.19.0.1/30") - ├─ addRoute("0.0.0.0/1") - ├─ addRoute("128.0.0.0/1") - ├─ addRoute("10.0.0.0/8") # bypass-LAN - └─ 启动 TUN 设备 -``` - -### 流量统计流程 - -``` -1. UI 定时器 (每秒) - │ - ├──> KRClashImp.getTraffic() - │ └─ FFI 调用 - │ - ├──> libclash.so: getTraffic() - │ └─ Clash Meta 内部统计 - │ - └──> 返回 JSON - { - "upload": 1234567, - "download": 7654321 - } -``` - -## 关键设计决策 - -### 为什么使用 Clash Meta 替代 sing-box? - -| 问题 | sing-box | Clash Meta | -|------|----------|------------| -| **Android VPN 路由** | 简单路由 (3-5条) | 详细路由 (35+条 CIDR) | -| **bypass-LAN 支持** | ❌ 不支持 | ✅ 完整支持 | -| **PermissionMonitor error 22** | ⚠️ 频繁出现 | ✅ 已解决 | -| **模拟器兼容性** | ⚠️ 兼容性问题 | ✅ 完美兼容 | - -### 并发安全保证 - -**问题:** Go 运行时初始化不是线程安全的,多个 Dart 方法并发调用 `_ensureInitialized()` 可能导致崩溃。 - -**解决方案:** 使用 `Completer` 实现初始化锁: -```dart -// 场景 1: 第一次调用 -Thread A: _ensureInitialized() → 创建 _initLock → 执行初始化 → complete() - -// 场景 2: 并发调用 -Thread B: _ensureInitialized() → 发现 _initLock != null → await _initLock.future ✅ - -// 场景 3: 初始化失败重试 -Thread C: _ensureInitialized() → 异常 → _initLock = null → 允许重试 ✅ -``` - -## 配置文件 - -### Clash 配置生成 (`clash_config_generator.dart`) - -```yaml -# 生成的 clash_config.yaml 示例 -mixed-port: 51213 -allow-lan: false - -tun: - enable: true - stack: system - auto-route: true - auto-detect-interface: true - dns-hijack: - - any:53 - route-address: # ⭐ 关键! 35+ 详细路由 - - 0.0.0.0/1 - - 128.0.0.0/1 - # ... bypass-LAN CIDRs - route-exclude-address: - - 10.0.0.0/8 # 绕过局域网 - - 172.16.0.0/12 - - 192.168.0.0/16 - -proxies: - - name: "Server-1" - type: ss - server: example.com - port: 8388 - # ... - -proxy-groups: - - name: "PROXY" - type: select - proxies: - - Server-1 -``` - -## 故障排查 - -参考 [CLASH_TROUBLESHOOTING.md](./CLASH_TROUBLESHOOTING.md) - -## 构建指南 - -参考 [CLASH_BUILD_GUIDE.md](./CLASH_BUILD_GUIDE.md) - -## 相关资源 - -- [Clash Meta 官方文档](https://wiki.metacubex.one/) -- [Mihomo GitHub](https://github.com/MetaCubeX/mihomo) -- [Xboard-Mihomo 参考实现](https://github.com/chen08209/Xboard-Mihomo) diff --git a/docs/CLASH_BUILD_GUIDE.md b/docs/CLASH_BUILD_GUIDE.md deleted file mode 100644 index 9c69068..0000000 --- a/docs/CLASH_BUILD_GUIDE.md +++ /dev/null @@ -1,345 +0,0 @@ -# Clash Meta 核心编译指南 - -## 环境准备 - -### 1. 安装必要工具 - -```bash -# macOS -brew install go -brew install android-ndk # 或从 Android Studio 安装 - -# 验证 -go version # 需要 go 1.20+ -``` - -### 2. 配置环境变量 - -```bash -# 添加到 ~/.zshrc 或 ~/.bash_profile -export ANDROID_HOME="$HOME/Library/Android/sdk" -export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/29.0.14033849" # 根据实际版本调整 -export PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin:$PATH" - -# 应用配置 -source ~/.zshrc -``` - -## 编译步骤 - -### 方法 1: 使用项目脚本 (推荐) - -```bash -cd /Users/mac/Project/Dart/LighthouseApp/core - -# 编译 ARM64 版本 -make android-arm64 - -# 编译所有架构 -make android-all # arm64-v8a, armeabi-v7a, x86, x86_64 -``` - -### 方法 2: 手动编译 - -#### 编译 ARM64 (arm64-v8a) - -```bash -cd /Users/mac/Project/Dart/LighthouseApp/core - -# 1. 初始化 Go 模块 -go mod download -git submodule update --init --recursive - -# 2. 设置交叉编译环境 -export CGO_ENABLED=1 -export GOOS=android -export GOARCH=arm64 -export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android29-clang" - -# 3. 编译为共享库 -go build -buildmode=c-shared \ - -ldflags="-s -w" \ - -trimpath \ - -o ../android/app/src/main/jniLibs/arm64-v8a/libclash.so \ - . - -# 4. 验证编译结果 -ls -lh ../android/app/src/main/jniLibs/arm64-v8a/libclash.so -nm -D ../android/app/src/main/jniLibs/arm64-v8a/libclash.so | grep quickStart -``` - -#### 编译 ARMv7 (armeabi-v7a) - -```bash -export GOARCH=arm -export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi29-clang" - -go build -buildmode=c-shared \ - -ldflags="-s -w" \ - -trimpath \ - -o ../android/app/src/main/jniLibs/armeabi-v7a/libclash.so \ - . -``` - -#### 编译 x86_64 - -```bash -export GOARCH=amd64 -export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin/x86_64-linux-android29-clang" - -go build -buildmode=c-shared \ - -ldflags="-s -w" \ - -trimpath \ - -o ../android/app/src/main/jniLibs/x86_64/libclash.so \ - . -``` - -## 编译优化 - -### 减小文件体积 - -```bash -# 使用 -ldflags 优化 -go build -buildmode=c-shared \ - -ldflags="-s -w -X 'github.com/metacubex/mihomo/constant.Version=1.0.0'" \ - -trimpath \ - -o libclash.so \ - . - -# -s: 去除符号表 -# -w: 去除 DWARF 调试信息 -# -trimpath: 移除文件系统路径 -``` - -### UPX 压缩 (可选) - -```bash -# 安装 UPX -brew install upx - -# 压缩 SO 文件 (可减少 30-50% 体积) -upx --best --lzma libclash.so - -# ⚠️ 注意: UPX 压缩可能导致某些设备加载失败,仅在测试环境使用 -``` - -## 常见问题 - -### 问题 1: `undefined reference to 'xxx'` - -**原因:** NDK 版本不匹配或缺少依赖 - -**解决:** -```bash -# 检查 NDK 版本 -ls $ANDROID_HOME/ndk/ - -# 使用推荐版本 (r25c / 25.2.9519653 或更高) -export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/25.2.9519653" -``` - -### 问题 2: `clang: command not found` - -**原因:** CC 环境变量路径错误 - -**解决:** -```bash -# macOS (Apple Silicon) -export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-aarch64/bin/aarch64-linux-android29-clang" - -# macOS (Intel) -export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android29-clang" -``` - -### 问题 3: 编译后文件过大 (>50MB) - -**原因:** 未启用优化参数 - -**解决:** -```bash -# 确保使用 -ldflags="-s -w" -go build -buildmode=c-shared \ - -ldflags="-s -w" \ - -trimpath \ - -o libclash.so \ - . - -# 预期大小: 25-30MB (ARM64) -``` - -### 问题 4: `go: github.com/metacubex/mihomo: module not found` - -**原因:** 子模块未初始化 - -**解决:** -```bash -cd core -git submodule update --init --recursive -go mod download -``` - -## 验证编译结果 - -### 1. 检查导出函数 - -```bash -nm -D libclash.so | grep -E "(quickStart|getAndroidVpnOptions|startTUN)" - -# 预期输出: -# 0000000000e23960 T getAndroidVpnOptions -# 0000000000e237b0 T quickStart -# 0000000000e23820 T startTUN -``` - -### 2. 检查架构 - -```bash -file libclash.so - -# ARM64 预期输出: -# libclash.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked -``` - -### 3. 测试加载 - -```bash -# 在 Android 设备上测试 -adb push libclash.so /data/local/tmp/ -adb shell "cd /data/local/tmp && LD_LIBRARY_PATH=. /system/bin/true" # 测试加载 -``` - -## 持续集成 (CI/CD) - -### GitHub Actions 示例 - -```yaml -# .github/workflows/build-clash-core.yml -name: Build Clash Core - -on: - push: - paths: - - 'core/**' - workflow_dispatch: - -jobs: - build-android: - runs-on: ubuntu-latest - - strategy: - matrix: - arch: [arm64, arm, amd64] - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - - uses: actions/setup-go@v4 - with: - go-version: '1.20' - - - name: Setup Android NDK - uses: nttld/setup-ndk@v1 - with: - ndk-version: r25c - - - name: Build - run: | - cd core - make android-${{ matrix.arch }} - - - name: Upload Artifact - uses: actions/upload-artifact@v3 - with: - name: libclash-${{ matrix.arch }} - path: android/app/src/main/jniLibs/**/libclash.so -``` - -## 更新核心版本 - -### 更新 Clash.Meta 子模块 - -```bash -cd core/Clash.Meta - -# 更新到最新版本 -git fetch origin -git checkout Alpha # 或其他分支 -git pull - -cd .. -git add Clash.Meta -git commit -m "chore: update Clash.Meta to latest" - -# 重新编译 -make clean -make android-arm64 -``` - -### 查看版本信息 - -```bash -# 查看当前 Clash.Meta 版本 -cd core/Clash.Meta -git log -1 --oneline - -# 查看依赖版本 -cd .. -go list -m github.com/metacubex/mihomo -``` - -## 调试编译问题 - -### 启用详细日志 - -```bash -# 查看详细编译过程 -go build -v -x -buildmode=c-shared -o libclash.so . - -# -v: 显示正在编译的包 -# -x: 显示执行的命令 -``` - -### 检查依赖 - -```bash -# 列出所有依赖 -go list -m all - -# 检查特定依赖 -go mod why github.com/metacubex/mihomo -``` - -## 性能优化 - -### 编译时优化 - -```bash -# 启用所有优化 -go build -buildmode=c-shared \ - -ldflags="-s -w -extldflags=-Wl,-z,now" \ - -trimpath \ - -tags="with_gvisor,with_quic" \ - -o libclash.so \ - . -``` - -### Profile 引导优化 (PGO) - -```bash -# 1. 生成性能剖析文件 -go test -cpuprofile=cpu.prof ./... - -# 2. 使用剖析文件编译 -go build -buildmode=c-shared \ - -pgo=cpu.prof \ - -o libclash.so \ - . -``` - -## 相关资源 - -- [Android NDK 官方文档](https://developer.android.com/ndk) -- [Go 交叉编译指南](https://go.dev/doc/install/source#environment) -- [Clash Meta 编译指南](https://wiki.metacubex.one/dev/) diff --git a/docs/CLASH_TROUBLESHOOTING.md b/docs/CLASH_TROUBLESHOOTING.md deleted file mode 100644 index 0d75010..0000000 --- a/docs/CLASH_TROUBLESHOOTING.md +++ /dev/null @@ -1,441 +0,0 @@ -# Clash Meta 故障排查指南 - -## 常见运行时问题 - -### 问题 1: VPN 连接失败,日志显示 "PermissionMonitor error 22 (EINVAL)" - -**症状:** -``` -E/VPNService: PermissionMonitor error 22 (EINVAL) -E/Clash: TUN 设备启动失败 -``` - -**原因:** -- VPN Builder 配置的路由规则无效 -- 缺少 bypass-LAN 路由配置 -- 路由 CIDR 格式错误 - -**解决方案:** - -1. 检查 `getAndroidVpnOptions()` 返回的路由列表: -```dart -final options = await KRClashImp().getAndroidVpnOptions(); -print('路由数量: ${options?['routeAddress']?.length}'); -print('路由列表: ${options?['routeAddress']}'); -``` - -2. 确认配置包含完整的 bypass-LAN 路由: -```yaml -# clash_config.yaml -tun: - route-exclude-address: - - 10.0.0.0/8 - - 100.64.0.0/10 - - 127.0.0.0/8 - - 169.254.0.0/16 - - 172.16.0.0/12 - - 192.0.0.0/24 - - 192.0.2.0/24 - - 192.88.99.0/24 - - 192.168.0.0/16 - - 198.18.0.0/15 - - 198.51.100.0/24 - - 203.0.113.0/24 - - 224.0.0.0/3 - - fc00::/7 - - fe80::/10 - - ff00::/8 -``` - -3. 验证 VPN Builder 配置: -```kotlin -// VPNService.kt -builder - .addAddress("172.19.0.1/30") - .addRoute("0.0.0.0/1") // ✅ 拆分默认路由 - .addRoute("128.0.0.0/1") // ✅ 避免 0.0.0.0/0 - .addRoute("10.0.0.0/8") // ✅ bypass-LAN - // ... -``` - -**参考:** `lib/app/services/clash_imp/kr_clash_imp.dart:192` - ---- - -### 问题 2: FFI 初始化崩溃 "Go runtime already initialized" - -**症状:** -``` -F/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR) -E/Clash: Go runtime already initialized -``` - -**原因:** -- 多线程并发调用 `_ensureInitialized()` -- Go 运行时被重复初始化 - -**解决方案:** - -已在 `kr_clash_imp.dart` 中修复,使用 `Completer` 实现并发安全: -```dart -Future _ensureInitialized() async { - if (_initialized) return; - if (_initLock != null) { - await _initLock!.future; // ✅ 等待其他初始化完成 - return; - } - _initLock = Completer(); - // ... 执行初始化 -} -``` - -**验证修复:** -```dart -// 并发测试 -await Future.wait([ - KRClashImp().start(...), - KRClashImp().getAndroidVpnOptions(), - KRClashImp().getTraffic(), -]); -// ✅ 应该不会崩溃 -``` - -**参考:** `lib/app/services/clash_imp/kr_clash_imp.dart:43` - ---- - -### 问题 3: 模拟器无法联网 "Network unreachable" - -**症状:** -``` -E/Clash: 网络不可达 -W/VPNService: 底层网络丢失 -``` - -**原因:** -- 模拟器需要显式设置底层网络 -- 缺少 `setUnderlyingNetworks()` 调用 - -**解决方案:** - -已在 `VPNService.kt` 中实现: -```kotlin -// Android P+ 需要设置底层网络 -private val defaultNetworkCallback by lazy { - object : ConnectivityManager.NetworkCallback() { - override fun onAvailable(network: Network) { - setUnderlyingNetworks(arrayOf(network)) // ✅ 关键! - } - } -} - -// 注册回调 -connectivityManager.registerDefaultNetworkCallback(defaultNetworkCallback) -``` - -**验证修复:** -```bash -# 在 MuMu 模拟器测试 -adb logcat | grep "底层网络" -# 应该看到: "底层网络可用: NetworkIdentity{...}" -``` - -**参考:** `android/.../bg/VPNService.kt:32-66` - ---- - -### 问题 4: 配置文件解析失败 "invalid YAML" - -**症状:** -``` -E/Clash: 启动失败: yaml: unmarshal errors: - line 10: cannot unmarshal !!str `8388` into int -``` - -**原因:** -- YAML 类型不匹配 (字符串 vs 整数) -- 配置格式错误 - -**解决方案:** - -检查 `ClashConfigGenerator.generate()`: -```dart -proxies: - - name: "Server-1" - type: ss - server: "example.com" - port: 8388 # ✅ 整数,不要引号 - password: "password" # ✅ 字符串,使用引号 - cipher: "aes-256-gcm" -``` - -**调试方法:** -```dart -// 打印生成的配置 -final config = ClashConfigGenerator.generate(...); -print('配置预览:\n$config'); - -// 保存到文件手动检查 -File('/tmp/clash_debug.yaml').writeAsStringSync(config); -``` - -**参考:** `lib/app/services/clash_imp/clash_config_generator.dart` - ---- - -### 问题 5: "quickStart timeout" 启动超时 - -**症状:** -``` -W/Clash: 启动超时 (10秒) -E/Clash: quickStart 未收到回调 -``` - -**原因:** -- Go 核心启动耗时过长 -- ReceivePort 未正确监听 -- 回调被阻塞 - -**解决方案:** - -1. 增加超时时间: -```dart -_isRunning = await completer.future.timeout( - const Duration(seconds: 20), // ✅ 增加到 20 秒 - onTimeout: () { - print('⚠️ 启动超时'); - return false; - }, -); -``` - -2. 检查 Go 核心日志: -```kotlin -// ClashService.kt - 添加日志回调 -tempMethodChannel.setMethodCallHandler { call, result -> - if (call.method == "log") { - Log.d(TAG, "Go 核心日志: ${call.arguments}") - } -} -``` - -3. 使用 Service Isolate 避免阻塞: -```kotlin -// ClashService.kt:102 - 已实现 -serviceEngine?.dartExecutor?.executeDartEntrypoint(entrypoint) -``` - -**参考:** `lib/app/services/clash_imp/kr_clash_imp.dart:145` - ---- - -### 问题 6: 流量统计不更新 - -**症状:** -``` -I/Clash: 流量统计: {"upload": 0, "download": 0} # 始终为 0 -``` - -**原因:** -- TUN 设备未正确启动 -- 流量未通过代理 - -**解决方案:** - -1. 确认 TUN 启动成功: -```dart -final tunStarted = await KRClashImp().startTun(fd, protectCallback); -print('TUN 启动状态: $tunStarted'); // 应该为 true -``` - -2. 检查路由配置: -```bash -# 在设备上检查路由表 -adb shell "ip route show table all | grep tun" -``` - -3. 测试代理连接: -```bash -# 使用 curl 测试 -adb shell "curl -v http://www.google.com" -# 应该看到代理日志 -``` - -**参考:** `lib/app/services/clash_imp/kr_clash_imp.dart:261` - ---- - -## 日志分析 - -### 启用详细日志 - -```dart -// lib/app/services/clash_imp/kr_clash_imp.dart -// 添加更详细的日志 -print('📨 [Clash] 收到消息: ${jsonEncode(message)}'); -print('📋 [Clash] 配置完整内容:\n$config'); -``` - -### Android Logcat 过滤 - -```bash -# 只看 Clash 相关日志 -adb logcat -s "A/Clash" "E/Clash" "W/Clash" - -# 实时监控 FFI 调用 -adb logcat | grep -E "(ClashFFI|quickStart|getAndroidVpnOptions)" - -# 保存日志到文件 -adb logcat -d > clash_debug.log -``` - -### Dart Observatory 调试 - -```bash -# 启用 Dart Observatory -flutter run --observatory-port=8181 - -# 在浏览器打开 -open http://localhost:8181 - -# 查看 Isolate 状态 -# - Main Isolate (UI) -# - Service Isolate (Clash 后台) -``` - ---- - -## 性能问题 - -### 内存泄漏 - -**症状:** -- 应用内存持续增长 -- 最终 OOM 崩溃 - -**排查:** -```dart -// 确保调用 dispose() -@override -void dispose() { - KRClashImp().dispose(); - super.dispose(); -} - -// 检查 ReceivePort 是否关闭 -receivePort.listen((message) { - // ... - receivePort.close(); // ✅ 必须关闭! -}); -``` - -### CPU 占用过高 - -**症状:** -- 设备发热 -- 电池消耗快 - -**排查:** -```bash -# 查看 CPU 占用 -adb shell "top -m 10" - -# 使用 Profiler -flutter run --profile -# DevTools → CPU Profiler -``` - -**优化:** -```dart -// 降低流量统计频率 -Timer.periodic(const Duration(seconds: 2), (timer) { // ✅ 2秒而非1秒 - final traffic = await KRClashImp().getTraffic(); - // ... -}); -``` - ---- - -## 崩溃分析 - -### 获取崩溃堆栈 - -```bash -# Native 崩溃 -adb logcat -d | grep "backtrace" - -# 使用 ndk-stack 解析 -adb logcat | ndk-stack -sym android/app/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a -``` - -### 常见崩溃模式 - -#### SIGSEGV (段错误) - -**原因:** FFI 指针使用错误 - -**示例:** -```dart -// ❌ 错误: 释放后使用 -final ptr = 'hello'.toNativeUtf8(); -malloc.free(ptr); -_ffi!.someFunction(ptr); // 崩溃! - -// ✅ 正确: 使用后释放 -final ptr = 'hello'.toNativeUtf8(); -_ffi!.someFunction(ptr); -malloc.free(ptr); -``` - -#### SIGABRT (异常终止) - -**原因:** Go panic 未恢复 - -**解决:** 在 Go 侧添加 recover: -```go -//export quickStart -func quickStart(...) { - defer func() { - if r := recover(); r != nil { - log.Println("Panic recovered:", r) - } - }() - // ... -} -``` - ---- - -## 获取帮助 - -### 收集诊断信息 - -创建 Bug 报告时请包含: - -1. **系统信息:** -```bash -adb shell "getprop ro.build.version.release" # Android 版本 -adb shell "getprop ro.product.cpu.abi" # CPU 架构 -``` - -2. **应用日志:** -```bash -adb logcat -d > full_log.txt -``` - -3. **配置文件:** -```dart -// 脱敏后的 clash_config.yaml -print(config.replaceAll(RegExp(r'password:.*'), 'password: ***')); -``` - -4. **复现步骤:** -- 详细操作流程 -- 预期结果 vs 实际结果 -- 复现概率 - -### 相关资源 - -- [GitHub Issues](https://github.com/your-repo/issues) -- [Clash Meta Wiki](https://wiki.metacubex.one/) -- [Flutter FFI 文档](https://dart.dev/guides/libraries/c-interop) diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 2a7457e..0000000 --- a/docs/README.md +++ /dev/null @@ -1,269 +0,0 @@ -# LighthouseApp 技术文档 - -欢迎查阅 LighthouseApp 技术文档。本目录包含项目的架构设计、开发指南和故障排查信息。 - -## 📚 文档导航 - -### Clash Meta 核心 (推荐阅读) - -| 文档 | 说明 | 适用人群 | -|------|------|----------| -| [**架构文档**](./CLASH_ARCHITECTURE.md) | 完整架构设计、数据流、关键决策 | 所有开发者 | -| [**编译指南**](./CLASH_BUILD_GUIDE.md) | 本地编译步骤、环境配置、优化方法 | 核心开发者 | -| [**故障排查**](./CLASH_TROUBLESHOOTING.md) | 常见问题、日志分析、崩溃调试 | 测试/运维 | - -### CI/CD 工作流 - -| 文档 | 说明 | -|------|------| -| [**GitHub Actions 说明**](../.github/workflows/README.md) | 自动化构建、发布流程 | - -## 🚀 快速开始 - -### 新开发者入门 - -1. **了解架构** (必读) - - 阅读 [CLASH_ARCHITECTURE.md](./CLASH_ARCHITECTURE.md) - - 理解 Dart → Android → Go 三层架构 - - 掌握 FFI 通信机制 - -2. **配置开发环境** - - 按照 [CLASH_BUILD_GUIDE.md](./CLASH_BUILD_GUIDE.md) 配置环境 - - 编译第一个 Clash Core - - 验证编译结果 - -3. **运行项目** - ```bash - # 1. 获取代码 - git clone - cd LighthouseApp - - # 2. 初始化子模块 - git submodule update --init --recursive - - # 3. 编译核心 - cd core - make android-arm64 - - # 4. 运行 Flutter - cd .. - flutter pub get - flutter run - ``` - -### 核心开发者 - -如果您需要修改 Clash Meta 核心: - -1. **修改代码** - ```bash - cd core - vim lib_android.go # 或其他核心文件 - ``` - -2. **本地测试** - ```bash - make android-arm64 - flutter run - ``` - -3. **提交 PR** - - CI/CD 会自动构建所有架构 - - 检查 Actions 页面的构建结果 - - 等待代码审查 - -## 🏗️ 架构速览 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ LighthouseApp │ -├─────────────────────────────────────────────────────────────┤ -│ Flutter/Dart Layer │ -│ └─ lib/app/services/clash_imp/ │ -│ ├─ kr_clash_imp.dart (核心封装) │ -│ ├─ clash_ffi.dart (FFI 绑定) │ -│ └─ clash_config_generator (配置生成) │ -├─────────────────────────────────────────────────────────────┤ -│ Android Native Layer │ -│ └─ android/app/src/main/kotlin/com/hiddify/hiddify/ │ -│ ├─ bg/VPNService.kt (VPN 服务) │ -│ └─ bg/ClashService.kt (Clash 服务) │ -├─────────────────────────────────────────────────────────────┤ -│ Go Core Layer │ -│ └─ core/ │ -│ ├─ Clash.Meta/ (Git 子模块) │ -│ ├─ lib_android.go (JNI 桥接) │ -│ └─ libclash.so (编译产物) │ -└─────────────────────────────────────────────────────────────┘ -``` - -详细架构请参考 [CLASH_ARCHITECTURE.md](./CLASH_ARCHITECTURE.md) - -## 🔧 常见任务 - -### 编译核心 - -```bash -cd core - -# 单个架构 (快速) -make android-arm64 - -# 所有架构 (发布) -make android-all - -# 清理 -make clean - -# 验证 -make verify -``` - -### 更新 Clash.Meta - -```bash -cd core -make update # 更新子模块到最新版本 -make android-arm64 # 重新编译 -``` - -### 调试问题 - -```bash -# 查看 Android 日志 -adb logcat -s "A/Clash" "E/Clash" - -# 查看编译详情 -cd core -go build -v -x -buildmode=c-shared -o test.so . - -# 验证 SO 文件 -nm -D libclash.so | grep quickStart -``` - -## 📖 核心概念 - -### 1. FFI 并发安全 - -**问题:** Go 运行时初始化不是线程安全的 - -**解决:** 使用 `Completer` 实现初始化锁 - -```dart -Future _ensureInitialized() async { - if (_initialized) return; - if (_initLock != null) { - await _initLock!.future; // ✅ 等待其他初始化 - return; - } - // ... 执行初始化 -} -``` - -详见 [CLASH_ARCHITECTURE.md § 并发安全保证](./CLASH_ARCHITECTURE.md#并发安全保证) - -### 2. Service Isolate 架构 - -**为什么需要?** -- VPN 服务运行在后台 -- 主 Isolate 可能被销毁 -- 需要独立的 Dart 运行时 - -**实现:** -```kotlin -// ClashService.kt -serviceEngine = FlutterEngine(Application.application) -val entrypoint = DartExecutor.DartEntrypoint(..., "_clashService") -serviceEngine?.dartExecutor?.executeDartEntrypoint(entrypoint) -``` - -详见 [CLASH_ARCHITECTURE.md § Service Isolate 架构](./CLASH_ARCHITECTURE.md#2-android-service-层-clashservicekt) - -### 3. Android VPN 路由配置 - -**关键:** `getAndroidVpnOptions()` 返回 35+ 详细 CIDR 路由 - -**为什么重要?** -- 避免 PermissionMonitor error 22 -- 支持 bypass-LAN -- 兼容模拟器 - -详见 [CLASH_TROUBLESHOOTING.md § 问题 1](./CLASH_TROUBLESHOOTING.md#问题-1-vpn-连接失败日志显示-permissionmonitor-error-22-einval) - -## 🐛 遇到问题? - -1. **查看故障排查文档** - - [CLASH_TROUBLESHOOTING.md](./CLASH_TROUBLESHOOTING.md) 包含所有常见问题 - -2. **收集诊断信息** - ```bash - # 系统信息 - adb shell "getprop ro.build.version.release" - - # 应用日志 - adb logcat -d > full_log.txt - - # 核心信息 - cd core - make verify - ``` - -3. **提交 Issue** - - 使用诊断信息模板 - - 包含复现步骤 - - 附上日志文件 - -## 🤝 贡献指南 - -### 代码规范 - -项目遵循以下原则: -- **KISS** (Keep It Simple, Stupid) - 简单至上 -- **DRY** (Don't Repeat Yourself) - 杜绝重复 -- **SOLID** - 面向对象设计原则 -- **YAGNI** (You Aren't Gonna Need It) - 精益求精 - -### 提交流程 - -1. Fork 项目 -2. 创建特性分支 (`git checkout -b feature/amazing`) -3. 提交更改 (`git commit -m 'feat: add amazing feature'`) -4. 推送分支 (`git push origin feature/amazing`) -5. 创建 Pull Request - -### Commit 规范 - -使用 Conventional Commits: -- `feat:` 新功能 -- `fix:` 修复 Bug -- `docs:` 文档更新 -- `refactor:` 代码重构 -- `perf:` 性能优化 -- `test:` 测试相关 -- `chore:` 构建/工具链 - -## 📞 获取帮助 - -- **GitHub Issues:** [提交问题](https://github.com/your-repo/issues) -- **文档索引:** 您正在阅读! -- **外部资源:** - - [Clash Meta Wiki](https://wiki.metacubex.one/) - - [Flutter FFI 文档](https://dart.dev/guides/libraries/c-interop) - - [Android VPN 指南](https://developer.android.com/reference/android/net/VpnService) - -## 📝 更新日志 - -| 日期 | 版本 | 更新内容 | -|------|------|----------| -| 2025-10-25 | 1.0.0 | 完成 Xboard-Mihomo 核心集成 | -| 2025-10-25 | 1.0.0 | 修复 FFI 并发安全问题 | -| 2025-10-25 | 1.0.0 | 添加完整技术文档 | - -## 📄 许可证 - -本项目采用 [LICENSE](../LICENSE) 许可证。 - ---- - -**最后更新:** 2025-10-25 -**维护者:** LighthouseApp 开发团队 diff --git a/docs/go修复.md b/docs/go修复.md deleted file mode 100644 index 9bf051d..0000000 --- a/docs/go修复.md +++ /dev/null @@ -1,318 +0,0 @@ -# Android SELinux chown 权限问题修复方案 - -## 问题背景 - -在 Android 12+ 系统上,由于 SELinux 严格模式的权限限制,sing-box 核心库在启动时会因为 `chown` 操作被拒绝而失败。具体表现为以下三个错误: - -1. **CommandServer 错误**: `chown: chown command.sock: operation not permitted` -2. **Logger 错误**: `start logger: chown box.log: operation not permitted` -3. **Clash Cache 错误**: `pre-start cache file: platform chown: chown clash.db: operation not permitted` - -## 问题分析 - -### 根本原因 - -sing-box (libbox) 在创建文件后会尝试修改文件所有权(`chown`操作),但在 Android 的 SELinux 环境下,应用无法修改外部存储目录中文件的所有权,导致启动失败。 - -### 涉及的文件 - -1. `command.sock` - CommandServer 的 Unix socket 文件 -2. `box.log` - sing-box 的日志文件 -3. `clash.db` - Clash API 的缓存数据库文件 - -## 修复方案 - -### 方案概述 - -**核心思路**: 在配置层面禁用会触发 chown 操作的功能,或者修改底层代码跳过 chown 操作。 - -由于修改 sing-box 底层库较为复杂,建议采用配置修改方案。 - ---- - -## 具体修复步骤 - -### 修复 1: 禁用文件日志 - -**文件**: `libcore/config/hiddify_option.go` - -**位置**: `DefaultHiddifyOptions()` 函数 - -**修改前**: -```go -LogLevel: "warn", -// LogFile: "/dev/null", -LogFile: "box.log", -``` - -**修改后**: -```go -LogLevel: "warn", -LogFile: "", // 禁用文件日志,避免 Android SELinux chown 权限问题 -// LogFile: "box.log", -``` - -**说明**: -- 将 `LogFile` 设置为空字符串,禁用文件日志输出 -- 日志将只输出到 stderr,可以通过 logcat 查看 -- 这不会影响日志功能,只是改变了输出目标 - ---- - -### 修复 2: 禁用 Clash API 缓存 - -**文件**: `libcore/config/config.go` - -**位置**: `setClashAPI()` 函数 - -**修改前**: -```go -func setClashAPI(options *option.Options, opt *HiddifyOptions) { - if opt.EnableClashApi { - if opt.ClashApiSecret == "" { - opt.ClashApiSecret = generateRandomString(16) - } - options.Experimental = &option.ExperimentalOptions{ - ClashAPI: &option.ClashAPIOptions{ - ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", opt.ClashApiPort), - Secret: opt.ClashApiSecret, - }, - - CacheFile: &option.CacheFileOptions{ - Enabled: true, - Path: "clash.db", - }, - } - } -} -``` - -**修改后**: -```go -func setClashAPI(options *option.Options, opt *HiddifyOptions) { - if opt.EnableClashApi { - if opt.ClashApiSecret == "" { - opt.ClashApiSecret = generateRandomString(16) - } - options.Experimental = &option.ExperimentalOptions{ - ClashAPI: &option.ClashAPIOptions{ - ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", opt.ClashApiPort), - Secret: opt.ClashApiSecret, - }, - - CacheFile: &option.CacheFileOptions{ - Enabled: false, // 禁用缓存以避免 Android SELinux chown 权限问题 - Path: "", // 清空路径 - }, - } - } -} -``` - -**说明**: -- 将 `Enabled` 设置为 `false`,禁用 Clash API 缓存功能 -- 将 `Path` 设置为空字符串 -- Clash API 功能仍然可用,只是不会持久化节点选择等信息 - ---- - -### 修复 3: CommandServer 错误处理 (可选) - -**说明**: CommandServer 主要用于命令行控制,对 Android VPN 功能不是必需的。 - -#### 方案 A: 在应用层捕获异常 (推荐) - -**文件**: `android/app/src/main/kotlin/com/hiddify/hiddify/bg/BoxService.kt` - -**位置**: `onStartCommand()` 函数 - -**修改**: -```kotlin -GlobalScope.launch(Dispatchers.IO) { - Settings.startedByUser = true - initialize() - try { - startCommandServer() - } catch (e: Exception) { - // CommandServer 启动失败不是致命错误 - // 在 Android 12+ SELinux 环境下,chown 操作可能被拒绝 - // 但这不影响 VPN 核心功能,因此记录警告但继续启动服务 - Log.w(TAG, "CommandServer failed to start (non-fatal): ${e.message}") - } - startService() -} -``` - -#### 方案 B: 完全禁用 CommandServer - -如果不需要 CommandServer 功能,可以直接注释掉启动代码: -```kotlin -// startCommandServer() // 在 Android 上禁用 -``` - ---- - -## 验证修复 - -### 编译步骤 - -1. **使用 Docker 编译** (推荐): -```bash -cd libcore -docker run --rm -v "$PWD:/workspace" -w /workspace golang:1.23 bash -c "bash docker-compile.sh" -``` - -2. **或者本地编译**: -```bash -cd libcore -make android -``` - -### 部署编译好的库 - -编译完成后,有两种部署方式: - -#### 方式A: 替换完整AAR (推荐生产环境) - -```bash -cd libcore -# 替换AAR文件 -cp libcore.aar ../android/app/libs/ - -# 删除可能冲突的so文件 -rm -rf ../android/app/src/main/jniLibs/ - -# 重新编译Flutter项目 -cd .. -flutter clean && flutter build apk -``` - -**优点**: 支持所有架构,适合发布版本 - -#### 方式B: 只提取arm64 so文件 (推荐测试环境) - -```bash -cd libcore -# 从AAR提取arm64的libbox.so -unzip -j libcore.aar jni/arm64-v8a/libbox.so -d /tmp/ -mkdir -p ../android/app/src/main/jniLibs/arm64-v8a/ -cp /tmp/libbox.so ../android/app/src/main/jniLibs/arm64-v8a/ - -# 临时禁用AAR(避免冲突) -mv ../android/app/libs/libcore.aar ../android/app/libs/libcore.aar.old - -# 编译测试版本 -cd .. -flutter clean && flutter build apk --debug --split-per-abi -``` - -**优点**: 编译快速,APK体积小,适合开发调试 - -⚠️ **重要**: 两种方式不能同时使用,会产生冲突!请根据需求选择其一。 - -### 测试验证 - -1. 重新编译 Flutter 应用 -2. 在 Android 设备上安装并启动 -3. 查看 logcat 日志,确认没有 chown 相关错误 -4. 验证 VPN 能正常启动和代理流量 - ---- - -## 预期结果 - -修复后,应用启动日志应该显示: - -``` -D/A/BoxService: base dir: /data/user/0/app.xxx.com/files -D/A/BoxService: working dir: /storage/emulated/0/Android/data/app.xxx.com/files -D/A/BoxService: temp dir: /data/user/0/app.xxx.com/cache -W/A/BoxService: CommandServer failed to start (non-fatal): chown: chown command.sock: operation not permitted -D/A/BoxService: starting service -D/A/BoxService: 配置已修改: 禁用文件日志和Clash缓存 -D/A/EventHandler: new status: Started ✅ 成功启动! -``` - ---- - -## 影响评估 - -### 功能影响 - -| 功能 | 修复前 | 修复后 | 影响 | -|------|--------|--------|------| -| VPN 代理 | ❌ 无法启动 | ✅ 正常工作 | 无影响 | -| 日志记录 | 文件输出 | logcat 输出 | 日志仍可用,通过 logcat 查看 | -| Clash API | 带缓存 | 无缓存 | 节点选择不持久化,重启后重置 | -| CommandServer | ❌ 失败 | 跳过启动 | 命令行控制不可用(非必需) | - -### 性能影响 - -- **无性能损失**: 禁用缓存和文件日志对性能无负面影响 -- **启动速度**: 可能略微加快(减少文件 I/O 操作) - ---- - -## 替代方案 (高级) - -如果需要保留完整功能,可以考虑以下方案: - -### 方案 1: 修改 sing-box 源码 - -在 sing-box 底层库中跳过 Android 平台的 chown 操作: - -```go -// 在文件创建后的 chown 调用处添加平台判断 -if runtime.GOOS != "android" { - if err := os.Chown(path, uid, gid); err != nil { - return err - } -} -``` - -**优点**: 保留所有功能 -**缺点**: 需要修改 sing-box 上游代码,维护成本高 - -### 方案 2: 使用内部存储 - -将文件创建在 `/data/user/0/` 目录下而不是外部存储: - -**优点**: 避免 SELinux 限制 -**缺点**: 空间受限,不适合大文件 - ---- - -## 常见问题 - -### Q1: 禁用文件日志后如何查看日志? - -**A**: 使用 adb logcat: -```bash -adb logcat | grep "A/BoxService\|singbox" -``` - -### Q2: 禁用 Clash 缓存后有什么影响? - -**A**: 每次启动 VPN 时,节点选择会重置为默认值,但不影响 VPN 的核心代理功能。 - -### Q3: 为什么 hiddify-app 可以正常运行? - -**A**: hiddify-app 使用的 libcore 版本已经包含了这些修复,或者使用了不同的配置策略。 - -### Q4: 这个修复是否适用于所有 Android 版本? - -**A**: 是的,这个修复对 Android 11 及以下版本也兼容,不会产生负面影响。 - ---- - -## 参考资料 - -- [Android SELinux 权限文档](https://source.android.com/docs/security/features/selinux) -- [sing-box 配置文档](https://sing-box.sagernet.org/configuration/) -- [Clash API 配置](https://sing-box.sagernet.org/configuration/experimental/clash-api/) - ---- - -## 更新日志 - -- **2025-10-27**: 初始版本,包含三个核心修复方案 diff --git a/scripts/DATA_CLEANUP_README.md b/scripts/DATA_CLEANUP_README.md deleted file mode 100644 index 35f985c..0000000 --- a/scripts/DATA_CLEANUP_README.md +++ /dev/null @@ -1,302 +0,0 @@ -# 📋 旧数据清理机制说明文档 - -## 问题背景 - -**问题现象**: 客户每次安装APP时,个人中心显示旧的测试账号 `calvin.duke@hotmail.com` - -**根本原因**: -- 开发环境中登录过测试账号 -- 打包时未清理本地Hive数据库 -- 旧数据被打包进APP包中 -- 新安装的APP恢复了这个旧账号信息 - ---- - -## ✅ 解决方案 - -本修复包含三个层面的防护机制: - -### 1️⃣ 应用层 - DEBUG模式清理(生效方式:优先级最高) - -**文件**: `lib/app/modules/kr_splash/controllers/kr_splash_controller.dart` - -**工作原理**: -- 仅在DEBUG模式(`kDebugMode == true`)下执行 -- 在应用启动时(`onInit()`)立即清理旧数据 -- 调用 `_kr_clearOldLocalData()` 方法 -- 清理内容:`USER_INFO` 和 `DEVICE_INFO` key - -**触发时机**: -``` -APP启动 → onInit() → 检测kDebugMode → 清理旧数据 -``` - -**优点**: -- ✅ 对用户数据0影响(DEBUG模式下才清理) -- ✅ 自动化,无需手动干预 -- ✅ 可在日志中追踪 - ---- - -### 2️⃣ 数据验证层 - Token合法性检查 - -**文件**: `lib/app/common/app_run_data.dart` - -**工作原理**: -- 在初始化用户信息时 (`kr_initializeUserInfo()`) -- 调用 `_kr_isValidToken()` 验证Token格式 -- 检查是否符合JWT格式:`header.payload.signature` -- 验证payload是否能解析为有效JSON - -**验证流程**: -``` -读取本地存储 - ↓ -解析JSON - ↓ -验证Token格式 - ├─ ❌ 格式错误 → 清理数据 (kr_loginOut) - ├─ ❌ 账号信息为空 → 清理数据 (kr_loginOut) - └─ ✅ 全部通过 → 恢复登录状态 -``` - -**检查项目**: -1. Token分段数是否为3 (header.payload.signature) -2. 每段是否非空 -3. Payload是否能正确解码为base64 -4. 解码后是否为有效JSON - -**日志示例**: -``` -✅ Token格式验证通过 -✅ Token和账号验证通过,设置登录状态为true -📊 恢复账号: user@example.com -``` - ---- - -### 3️⃣ 打包前清理 - 预防层 - -**文件**: `scripts/clean_build_cache.sh` - -**工作原理**: -- 打包前手动运行此脚本 -- 清理所有平台的本地缓存数据 -- 删除Hive数据库文件 - -**清理内容**: -- ✅ macOS应用数据目录 -- ✅ macOS/Linux Hive数据库 -- ✅ Flutter构建缓存 -- ✅ `.dart_tool` 目录 -- ✅ `build/` 产物目录 - -**使用方法**: -```bash -# 进入脚本目录 -cd scripts/ - -# 运行清理脚本 -./clean_build_cache.sh - -# 后续步骤 -flutter pub get -./build_android.sh # 或其他平台脚本 -``` - ---- - -## 🔄 完整流程图 - -### 新安装APP时的数据恢复流程 - -``` -┌─────────────────────────────────────┐ -│ APP启动 │ -└──────────────┬──────────────────────┘ - ↓ -┌─────────────────────────────────────┐ -│ DEBUG模式清理(第1道防线) │ -│ - 清理USER_INFO │ -│ - 清理DEVICE_INFO │ -└──────────────┬──────────────────────┘ - ↓ -┌─────────────────────────────────────┐ -│ 初始化用户信息 │ -│ kr_initializeUserInfo() │ -└──────────────┬──────────────────────┘ - ↓ -┌─────────────────────────────────────┐ -│ Token合法性检查(第2道防线) │ -│ _kr_isValidToken() │ -│ │ -│ ├─ 格式检查(JWT) │ -│ ├─ Payload解码检查 │ -│ └─ JSON有效性检查 │ -└──────────────┬──────────────────────┘ - │ - ┌────────┴────────┐ - ↓ ↓ - ✅ 有效 ❌ 无效 - │ │ - ↓ ↓ - 恢复登录 清理旧数据 - 显示账号 kr_loginOut() - │ │ - └────────┬────────┘ - ↓ - 进入个人中心 -``` - ---- - -## 🧪 测试验证方法 - -### 测试场景1:新安装APP(DEBUG模式) - -**预期结果**: 看到"DEBUG模式:清理旧本地存储数据"日志 - -```bash -1. 构建DEBUG版本 -2. 安装APP -3. 查看日志:adb logcat | grep "清理旧本地存储数据" -4. 进入个人中心,不应显示旧账号 -``` - -### 测试场景2:手动清理后打包 - -**步骤**: -```bash -1. cd scripts/ -2. ./clean_build_cache.sh # 清理本地缓存 -3. flutter pub get -4. ./build_android.sh # 打包新APP -5. 安装新APP -6. 进入个人中心,验证没有旧数据 -``` - -### 测试场景3:验证Token验证机制 - -**模拟被污染的Token**: - -在DEBUG模式下修改Hive存储,加入无效Token: -- 格式错误的Token(少于或多于3段) -- 无效base64的payload -- 无法解析为JSON的payload - -**预期**: 应用启动时自动清理,不显示任何账号 - ---- - -## 🔍 日志信息参考 - -### 成功清理的日志 -``` -🧹 DEBUG模式:准备清理旧本地存储数据 -🧹 开始清理旧本地存储数据... -✅ 已清理USER_INFO -✅ 已清理DEVICE_INFO -✅ 旧本地存储数据已全部清理 -``` - -### Token验证通过的日志 -``` -✅ Token格式验证通过 -✅ Token和账号验证通过,设置登录状态为true -📊 恢复账号: user@example.com -``` - -### Token验证失败的日志 -``` -❌ Token格式无效:分段数不对 (2 != 3) -⚠️ Token验证失败或格式错误,清理该条用户数据 -``` - ---- - -## ⚠️ 重要注意事项 - -### ✅ 安全性设计 - -1. **DEBUG模式专用**: 清理逻辑仅在DEBUG构建中运行,生产环境不受影响 -2. **用户数据保护**: 验证失败才清理,不会盲目删除有效数据 -3. **完整性检查**: 多层验证确保数据完整性 - -### ⚠️ 潜在风险 - -1. **如果手动禁用清理**: 需要确保打包前运行`clean_build_cache.sh` -2. **如果Token损坏**: 自动清理,用户需要重新登录 -3. **跨版本兼容**: 确保Token格式保持一致 - ---- - -## 📊 修复前后对比 - -| 方面 | 修复前 | 修复后 | -|-----|------|------| -| 新安装APP | 显示旧测试账号 | ✅ 显示未登录 | -| 损坏数据 | 直接使用 | ✅ 自动检测清理 | -| DEBUG模式 | 无特殊处理 | ✅ 自动清理 | -| 打包防护 | 无 | ✅ 专用清理脚本 | -| 日志追踪 | 无 | ✅ 完整的日志记录 | - ---- - -## 🚀 部署指南 - -### 对开发人员 - -1. **本地开发**: 无需特殊操作,DEBUG模式会自动清理 -2. **打包前**: 运行 `scripts/clean_build_cache.sh` -3. **CI/CD**: 在构建脚本中加入清理步骤 - -### 对用户 - -- **无需任何操作**: 修复完全透明,用户无感知 -- **新安装**: 自动清理旧数据 -- **现有用户**: 升级后仍可正常登录 - ---- - -## 📞 故障排查 - -### 问题:APP仍显示旧账号 - -**检查清单**: -1. 是否使用了DEBUG构建? -2. 是否是第一次安装? -3. 检查日志中是否有清理消息 - -### 问题:登录后无法显示账号 - -**检查清单**: -1. Token是否有效 -2. 查看日志中的Token验证信息 -3. 尝试重新登录 - -### 问题:脚本执行失败 - -**常见原因**: -1. 脚本没有执行权限:`chmod +x clean_build_cache.sh` -2. 路径不正确:确保在scripts目录下执行 -3. Flutter未安装:需要Flutter环境 - ---- - -## 📝 修改记录 - -- **2025-10-31**: 创建数据清理机制 - - 新增DEBUG模式清理 - - 新增Token验证机制 - - 新增打包前清理脚本 - - 新增文档说明 - ---- - -## 📚 相关文件 - -- `lib/app/modules/kr_splash/controllers/kr_splash_controller.dart` - 启动时清理 -- `lib/app/common/app_run_data.dart` - Token验证 -- `scripts/clean_build_cache.sh` - 打包前清理脚本 -- `scripts/VERSION_INCREMENT_README.md` - 版本递增说明 - diff --git a/scripts/clean_build_cache.sh b/scripts/clean_build_cache.sh deleted file mode 100755 index f4e63b7..0000000 --- a/scripts/clean_build_cache.sh +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash -# 🔧 打包前清理脚本 - 清理Hive数据库和本地存储缓存 -# 目的:防止旧的测试数据被打包进APK/IPA中 -# 作者:Claude Code AI -# 用法:./clean_build_cache.sh - -set -e - -echo "═══════════════════════════════════════════════════════════════" -echo "🧹 打包前清理脚本 - 清理本地存储和缓存" -echo "═══════════════════════════════════════════════════════════════" -echo "" - -# 获取脚本所在目录 -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -PROJECT_DIR="$(dirname "$SCRIPT_DIR")" - -# 定义各平台的存储位置 -echo "📍 检测平台并清理相应数据..." -echo "" - -# 1. macOS应用数据清理 -if [ -d "$HOME/Library/Application Support/com.example.kae" ]; then - echo "🍎 清理 macOS 应用数据..." - rm -rf "$HOME/Library/Application Support/com.example.kae" - echo " ✅ macOS 数据已清理" -fi - -# 2. macOS Hive数据库清理 -HIVE_MACOS_PATH="$HOME/Library/Application Support" -if [ -d "$HIVE_MACOS_PATH" ]; then - echo "🍎 清理 macOS Hive数据库..." - find "$HIVE_MACOS_PATH" -name "*kaer_secure_storage*" -delete 2>/dev/null || true - find "$HIVE_MACOS_PATH" -name "*hive*" -type f \( -name "*.hive" -o -name "*.lock" \) -delete 2>/dev/null || true - echo " ✅ macOS Hive数据库已清理" -fi - -# 3. Linux Hive数据库清理 -HIVE_LINUX_PATH="$HOME/.local/share" -if [ -d "$HIVE_LINUX_PATH" ]; then - echo "🐧 清理 Linux Hive数据库..." - find "$HIVE_LINUX_PATH" -name "*kaer_secure_storage*" -delete 2>/dev/null || true - find "$HIVE_LINUX_PATH" -name "*hive*" -type f \( -name "*.hive" -o -name "*.lock" \) -delete 2>/dev/null || true - echo " ✅ Linux Hive数据库已清理" -fi - -# 4. Flutter构建缓存清理 -echo "" -echo "🔄 清理 Flutter 构建缓存..." -if command -v flutter &> /dev/null; then - flutter clean - echo " ✅ Flutter 缓存已清理" -else - echo " ⚠️ Flutter 未找到,跳过缓存清理" -fi - -# 5. pub缓存清理(可选) -echo "" -echo "📦 清理 Pub 缓存(可选)..." -echo " 提示:如果遇到依赖问题,可以运行:flutter pub get" -echo "" - -# 6. 清理Android构建产物 -if [ -d "$PROJECT_DIR/build" ]; then - echo "🤖 清理 Android/Flutter 构建产物..." - rm -rf "$PROJECT_DIR/build" - echo " ✅ 构建产物已清理" -fi - -# 7. 清理.dart_tool目录 -if [ -d "$PROJECT_DIR/.dart_tool" ]; then - echo "🔧 清理 .dart_tool..." - rm -rf "$PROJECT_DIR/.dart_tool" - echo " ✅ .dart_tool 已清理" -fi - -echo "" -echo "═══════════════════════════════════════════════════════════════" -echo "✅ 打包前清理完成!" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "📝 后续步骤:" -echo " 1. 运行 flutter pub get" -echo " 2. 运行相应平台的构建脚本(build_android.sh / build_ios.sh 等)" -echo " 3. 确认新构建的APP中没有旧数据" -echo "" -echo "🔍 验证方法:" -echo " - 在DEBUG模式下运行APP,查看是否显示旧的测试账号" -echo " - 检查日志中是否有'DEBUG模式:清理旧本地存储数据'消息" -echo "" diff --git a/test_singbox_url_test.dart b/test_singbox_url_test.dart deleted file mode 100755 index 366db03..0000000 --- a/test_singbox_url_test.dart +++ /dev/null @@ -1,41 +0,0 @@ -// 测试 SingBox URL 测试功能的脚本 -import 'dart:io'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:kaer_with_panels/app/modules/kr_home/controllers/kr_home_controller.dart'; -import 'package:kaer_with_panels/app/services/singbox_imp/kr_sing_box_imp.dart'; -import 'package:kaer_with_panels/app/utils/kr_log_util.dart'; - -void main() async { - // 初始化 GetX - Get.put(KRHomeController()); - - // 获取控制器实例 - final homeController = Get.find(); - - print('🧪 开始测试 SingBox URL 测试功能...'); - - // 等待 SingBox 初始化 - await Future.delayed(const Duration(seconds: 2)); - - // 手动触发 URL 测试 - print('🚀 触发 URL 测试...'); - await homeController.kr_urlTest(); - - // 等待测试完成 - await Future.delayed(const Duration(seconds: 5)); - - // 检查结果 - print('📊 检查测试结果...'); - final activeGroups = KRSingBoxImp.instance.kr_activeGroups; - for (int i = 0; i < activeGroups.length; i++) { - final group = activeGroups[i]; - print('📋 活动组[$i]: tag=${group.tag}, type=${group.type}, selected=${group.selected}'); - for (int j = 0; j < group.items.length; j++) { - final item = group.items[j]; - print(' └─ 节点[$j]: tag=${item.tag}, type=${item.type}, delay=${item.urlTestDelay}'); - } - } - - print('✅ 测试完成'); -} diff --git a/test_trojan_connection.dart b/test_trojan_connection.dart deleted file mode 100755 index 00d3ab1..0000000 --- a/test_trojan_connection.dart +++ /dev/null @@ -1,42 +0,0 @@ -// 测试 Trojan 连接问题的脚本 -import 'dart:io'; - -void main() async { - print('🔍 测试 Trojan 连接问题...'); - - // 测试服务器连接 - final server = '156.224.78.176'; - final port = 27639; - - print('📡 测试服务器连接: $server:$port'); - - try { - final socket = await Socket.connect(server, port, timeout: Duration(seconds: 10)); - print('✅ TCP 连接成功'); - socket.destroy(); - } catch (e) { - print('❌ TCP 连接失败: $e'); - } - - // 测试 DNS 解析 - print('🌐 测试 DNS 解析...'); - try { - final addresses = await InternetAddress.lookup('baidu.com'); - print('✅ baidu.com 解析成功: ${addresses.map((a) => a.address).join(', ')}'); - } catch (e) { - print('❌ baidu.com 解析失败: $e'); - } - - // 测试服务器地址解析 - try { - final addresses = await InternetAddress.lookup(server); - print('✅ 服务器地址解析成功: ${addresses.map((a) => a.address).join(', ')}'); - } catch (e) { - print('❌ 服务器地址解析失败: $e'); - } - - print('🔧 建议的修复方案:'); - print('1. 将 server_name 改为服务器实际域名或 IP'); - print('2. 或者设置 insecure: true 跳过证书验证'); - print('3. 检查服务器是否支持 baidu.com 作为 SNI'); -}