fix: 精简脚本
This commit is contained in:
parent
c9a6ad2046
commit
5f2fb90bb2
@ -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<KRHomeController>();
|
|
||||||
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<KRHomeController>();
|
|
||||||
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');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<void>? _initLock;
|
|
||||||
|
|
||||||
Future<void> _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)
|
|
||||||
@ -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/)
|
|
||||||
@ -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<void> _ensureInitialized() async {
|
|
||||||
if (_initialized) return;
|
|
||||||
if (_initLock != null) {
|
|
||||||
await _initLock!.future; // ✅ 等待其他初始化完成
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_initLock = Completer<void>();
|
|
||||||
// ... 执行初始化
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**验证修复:**
|
|
||||||
```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)
|
|
||||||
269
docs/README.md
269
docs/README.md
@ -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 <repo-url>
|
|
||||||
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<void> _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 开发团队
|
|
||||||
318
docs/go修复.md
318
docs/go修复.md
@ -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**: 初始版本,包含三个核心修复方案
|
|
||||||
@ -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` - 版本递增说明
|
|
||||||
|
|
||||||
@ -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 ""
|
|
||||||
@ -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<KRHomeController>();
|
|
||||||
|
|
||||||
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('✅ 测试完成');
|
|
||||||
}
|
|
||||||
@ -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');
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user