diff --git a/lib/app/modules/hi_node_list/views/hi_node_list_view.dart b/lib/app/modules/hi_node_list/views/hi_node_list_view.dart index 1d35299..1018e8e 100755 --- a/lib/app/modules/hi_node_list/views/hi_node_list_view.dart +++ b/lib/app/modules/hi_node_list/views/hi_node_list_view.dart @@ -436,7 +436,7 @@ class HINodeListView extends GetView { print('🎯 检测到auto组节点,获取最快节点信息'); final autoNodeInfo = controller.homeController.kr_getCountryAutoSelectedNode(item.country); print('📊 _kr_buildNodeListItem获取auto最快节点: $autoNodeInfo'); - displayDelay = autoNodeInfo?['delay'] ?? 3000; + displayDelay = autoNodeInfo?['delay'] ?? 0; print('✅ _kr_buildNodeListItem使用auto最快节点延迟: $displayDelay'); } else { // 普通节点,直接显示节点自身的速度 diff --git a/lib/app/services/singbox_imp/kr_sing_box_imp.dart b/lib/app/services/singbox_imp/kr_sing_box_imp.dart index b6eb2a4..c6677c6 100755 --- a/lib/app/services/singbox_imp/kr_sing_box_imp.dart +++ b/lib/app/services/singbox_imp/kr_sing_box_imp.dart @@ -12,6 +12,7 @@ import 'package:kaer_with_panels/singbox/service/singbox_service.dart'; import 'package:kaer_with_panels/singbox/service/singbox_service_provider.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as p; +import 'package:device_info_plus/device_info_plus.dart'; import '../../../core/model/directories.dart'; import '../../../singbox/model/singbox_config_option.dart'; @@ -112,6 +113,62 @@ class KRSingBoxImp { /// 初始化进行中共享 Future(single-flight 防并发) Future? _kr_initFuture; + /// 是否为Android模拟器 + bool _kr_isAndroidEmulator = false; + + /// 检测并缓存模拟器标识 + /// + /// - 仅在 Android 上进行模拟器特征识别 + /// - 通过 brand/model/product/manufacturer 的常见模拟器特征判断 + /// 返回:无(结果写入 `_kr_isAndroidEmulator`) + Future _kr_detectEmulator() async { + try { + if (!Platform.isAndroid) { + _kr_isAndroidEmulator = false; + return; + } + + final info = await DeviceInfoPlugin().androidInfo; + final brand = (info.brand ?? '').toLowerCase(); + final model = (info.model ?? '').toLowerCase(); + final product = (info.product ?? '').toLowerCase(); + final manufacturer = (info.manufacturer ?? '').toLowerCase(); + final device = (info.device ?? '').toLowerCase(); + + bool containsAny(String s, List keys) => keys.any((k) => s.contains(k)); + + final indicators = [ + containsAny(brand, [ + 'generic', 'unknown', 'google', 'vbox', 'virtualbox', + 'bluestacks', 'nox', 'ldplayer', 'genymotion', 'mumu', 'netease', 'leidian' + ]), + containsAny(model, [ + 'emulator', 'sdk', 'sdk_gphone', 'google_sdk', 'android sdk built for x86', + 'bluestacks', 'genymotion', 'nox', 'ldplayer', 'mumu' + ]), + containsAny(product, [ + 'sdk', 'google_sdk', 'sdk_gphone', 'emulator', 'vbox', 'virtualbox' + ]), + containsAny(manufacturer, [ + 'genymotion', 'unknown', 'bluestacks', 'nox', 'ld', 'netease', 'mumu' + ]), + containsAny(device, [ + 'emulator', 'generic', 'vbox', 'virtualbox', 'sdk' + ]), + ]; + + _kr_isAndroidEmulator = indicators.any((v) => v); + KRLogUtil.kr_i( + '🔍 Android 模拟器检测: ${_kr_isAndroidEmulator ? '是模拟器' : '非模拟器'}' + ' (brand=$brand, model=$model, product=$product, manufacturer=$manufacturer, device=$device)', + tag: 'SingBox', + ); + } catch (e) { + _kr_isAndroidEmulator = false; + KRLogUtil.kr_w('⚠️ 模拟器检测失败,按真机处理: $e', tag: 'SingBox'); + } + } + /// 当前混合代理端口是否就绪 bool get kr_isProxyReady => kr_status.value is SingboxStarted; @@ -167,6 +224,9 @@ class KRSingBoxImp { await KRCountryUtil.kr_init(); KRLogUtil.kr_i('国家工具初始化完成'); + // 设备环境检测(Android模拟器) + await _kr_detectEmulator(); + final oOption = SingboxConfigOption.fromJson(_getConfigOption()); KRLogUtil.kr_i('配置选项初始化完成'); @@ -555,9 +615,11 @@ class KRSingBoxImp { "log-level": "info", // 调试阶段使用 info,生产环境改为 warn "resolve-destination": false, "ipv6-mode": "ipv4_only", // 参考 hiddify-app: 仅使用 IPv4 (有效值: ipv4_only, prefer_ipv4, prefer_ipv6, ipv6_only) - "remote-dns-address": "https://dns.google/dns-query", // 使用 Google DoH,避免中转节点 DNS 死锁 + "remote-dns-address": _kr_isAndroidEmulator + ? "local" + : "https://dns.google/dns-query", "remote-dns-domain-strategy": "prefer_ipv4", - "direct-dns-address": "local", // 使用系统 DNS,确保中转服务器域名能被解析 + "direct-dns-address": "local", "direct-dns-domain-strategy": "prefer_ipv4", "mixed-port": kr_port, "tproxy-port": kr_port, @@ -645,6 +707,47 @@ class KRSingBoxImp { return op; } + /// 动态构建 DNS 配置 + /// + /// - 真机:使用远程 DoH + 本地系统 DNS,final 指向远程 + /// - 模拟器:仅使用系统 DNS,final 指向直连,避免覆盖系统 DNS + /// 返回:Sing-box `dns` 段配置 Map + Map _kr_buildDnsConfig() { + if (_kr_isAndroidEmulator) { + KRLogUtil.kr_i('🛡️ 模拟器兼容模式:强制使用系统 DNS', tag: 'SingBox'); + return { + "servers": [ + { + "tag": "dns-direct", + "address": "local", + "detour": "direct" + } + ], + "rules": [], + "final": "dns-direct", + "strategy": "prefer_ipv4" + }; + } + + return { + "servers": [ + { + "tag": "dns-remote", + "address": "https://1.1.1.1/dns-query", + "address_resolver": "dns-direct" + }, + { + "tag": "dns-direct", + "address": "local", + "detour": "direct" + } + ], + "rules": _kr_buildDnsRules(), + "final": "dns-remote", + "strategy": "prefer_ipv4" + }; + } + /// 订阅状态变化流 /// 参考 hiddify-app: 监听 libcore 发送的状态事件来自动更新 UI void _kr_subscribeToStatus() { @@ -1150,23 +1253,7 @@ class KRSingBoxImp { "level": "debug", "timestamp": true }, - "dns": { - "servers": [ - { - "tag": "dns-remote", - "address": "https://1.1.1.1/dns-query", - "address_resolver": "dns-direct" - }, - { - "tag": "dns-direct", - "address": "local", - "detour": "direct" - } - ], - "rules": _kr_buildDnsRules(), // ✅ 使用动态构建的 DNS 规则 - "final": "dns-remote", - "strategy": "prefer_ipv4" - }, + "dns": _kr_buildDnsConfig(), "inbounds": [ { "type": "tun",