using UnityEngine; using UnityEngine.UI; using TMPro; using System.Net; using System.Net.NetworkInformation; /// /// 网络设置面板 /// 配置系统网络连接参数 /// public class NetworkSettingPanel : BasePanel { [Header("网络模式")] public Toggle DhcpToggle; public Toggle StaticToggle; public ToggleGroup NetworkModeGroup; [Header("静态IP设置")] public TMP_InputField IPv4Input; public TMP_InputField SubnetMaskInput; public TMP_InputField GatewayInput; public TMP_InputField DNS1Input; public TMP_InputField DNS2Input; [Header("网络状态")] public TextMeshProUGUI NetworkStatusText; public Button TestConnectionButton; public Image ConnectionStatusIcon; public TextMeshProUGUI CurrentIPText; public Button ResetButton; [Header("控制按钮")] public Button HomeButton; public Button ConfirmButton; public Button BackButton; private SettingsViewModel _vm; private NetworkConfig _tempConfig; public override void Init() { _vm = new SettingsViewModel(); _tempConfig = _vm.Network; InitializeUI(); LoadCurrentSettings(); // 保留网络配置功能,但完全禁用网络状态检查避免Unity底层网络错误 // 医疗设备通常在局域网环境中运行,无需互联网连接检查 #if UNITY_ANDROID && !UNITY_EDITOR // Android平台:显示局域网配置状态,禁用互联网检查 Debug.Log("[NetworkSettingPanel] Android平台:局域网配置模式 (禁用互联网检查)"); ShowLANConfigurationStatus(); #else // PC平台:也禁用网络检查,避免"Network is unreachable"错误导致软件崩溃 Debug.Log("[NetworkSettingPanel] PC平台:网络配置模式 (禁用网络检查防止崩溃)"); ShowStaticNetworkStatus(); // 完全禁用定期网络检查,防止Unity底层网络异常 // InvokeRepeating(nameof(UpdateNetworkStatus), 1f, 5f); // 已禁用 #endif } private void InitializeUI() { // 设置网络模式切换 if (DhcpToggle != null && StaticToggle != null) { DhcpToggle.onValueChanged.AddListener(OnNetworkModeChanged); StaticToggle.onValueChanged.AddListener((value) => OnNetworkModeChanged(!value)); } // 输入字段验证 SetupInputFieldValidation(); if (ResetButton != null) ResetButton.onClick.AddListener(ResetToDefaults); if (HomeButton != null) { HomeButton.onClick.AddListener(() => { ConfirmDialog.Show("确认", "是否返回主界面?", () => { ReturnToHome(); }); }); } if (ConfirmButton != null) { ConfirmButton.onClick.AddListener(ApplyAndBack); } if (BackButton != null) { BackButton.onClick.AddListener(() => ConfirmDialog.Show("确认", "是否返回设置界面?", () => { ClosePanel(); ClosePanel(); }) ); } } private void LoadCurrentSettings() { var config = _vm.Network; // 设置网络模式 bool isDhcp = config.Mode == NetworkMode.Dhcp; if (DhcpToggle != null) DhcpToggle.isOn = isDhcp; if (StaticToggle != null) StaticToggle.isOn = !isDhcp; // 加载IP配置 if (isDhcp) { // DHCP模式:显示当前获取的IP信息 LoadAndDisplayCurrentDhcpIP(); } else { // 静态IP模式:显示保存的配置 if (IPv4Input != null) IPv4Input.text = config.IPv4; if (SubnetMaskInput != null) SubnetMaskInput.text = config.Mask; if (GatewayInput != null) GatewayInput.text = config.Gateway; if (DNS1Input != null) DNS1Input.text = config.Dns1; if (DNS2Input != null) DNS2Input.text = config.Dns2; } // 设置静态IP字段的可用性 SetStaticFieldsInteractable(!isDhcp); } private void OnNetworkModeChanged(bool isDhcp) { _tempConfig.Mode = isDhcp ? NetworkMode.Dhcp : NetworkMode.Static; SetStaticFieldsInteractable(!isDhcp); UpdateNetworkModeDisplay(isDhcp); // 模式切换时更新显示 if (isDhcp) { LoadAndDisplayCurrentDhcpIP(); } else { // 切换到静态IP时,清空或恢复到配置值 var config = _vm.Network; if (IPv4Input != null) IPv4Input.text = config.IPv4; if (SubnetMaskInput != null) SubnetMaskInput.text = config.Mask; if (GatewayInput != null) GatewayInput.text = config.Gateway; if (DNS1Input != null) DNS1Input.text = config.Dns1; if (DNS2Input != null) DNS2Input.text = config.Dns2; } } private void SetStaticFieldsInteractable(bool interactable) { if (IPv4Input != null) IPv4Input.interactable = interactable; if (SubnetMaskInput != null) SubnetMaskInput.interactable = interactable; if (GatewayInput != null) GatewayInput.interactable = interactable; if (DNS1Input != null) DNS1Input.interactable = interactable; if (DNS2Input != null) DNS2Input.interactable = interactable; // 改变颜色以指示状态 // DHCP模式:灰色半透明(只读);静态IP模式:完全不透明(可编辑) float alpha = interactable ? 1f : 0.5f; SetInputFieldAlpha(IPv4Input, alpha); SetInputFieldAlpha(SubnetMaskInput, alpha); SetInputFieldAlpha(GatewayInput, alpha); SetInputFieldAlpha(DNS1Input, alpha); SetInputFieldAlpha(DNS2Input, alpha); // DHCP模式下禁用编辑,设置为只读提示 if (!interactable) { if (IPv4Input != null) IPv4Input.readOnly = true; if (SubnetMaskInput != null) SubnetMaskInput.readOnly = true; if (GatewayInput != null) GatewayInput.readOnly = true; if (DNS1Input != null) DNS1Input.readOnly = true; if (DNS2Input != null) DNS2Input.readOnly = true; } else { if (IPv4Input != null) IPv4Input.readOnly = false; if (SubnetMaskInput != null) SubnetMaskInput.readOnly = false; if (GatewayInput != null) GatewayInput.readOnly = false; if (DNS1Input != null) DNS1Input.readOnly = false; if (DNS2Input != null) DNS2Input.readOnly = false; } } private void SetInputFieldAlpha(TMP_InputField inputField, float alpha) { if (inputField != null) { var colors = inputField.colors; colors.normalColor = new Color(colors.normalColor.r, colors.normalColor.g, colors.normalColor.b, alpha); inputField.colors = colors; } } private void SetupInputFieldValidation() { // 设置自定义键盘(IP 地址使用数字和点号) if (IPv4Input != null) { IPv4Input.onEndEdit.AddListener(ValidateIPAddress); IPv4Input.characterLimit = 15; CustomKeyboardManager.SetupInputField(IPv4Input, KeyboardLayout.Numeric, (newValue) => { IPv4Input.text = newValue; ValidateIPAddress(newValue); }, clearOnFirstInput: true); } if (SubnetMaskInput != null) { SubnetMaskInput.onEndEdit.AddListener(ValidateSubnetMask); SubnetMaskInput.characterLimit = 15; CustomKeyboardManager.SetupInputField(SubnetMaskInput, KeyboardLayout.Numeric, (newValue) => { SubnetMaskInput.text = newValue; ValidateSubnetMask(newValue); }, clearOnFirstInput: true); } if (GatewayInput != null) { GatewayInput.onEndEdit.AddListener(ValidateIPAddress); GatewayInput.characterLimit = 15; CustomKeyboardManager.SetupInputField(GatewayInput, KeyboardLayout.Numeric, (newValue) => { GatewayInput.text = newValue; ValidateIPAddress(newValue); }, clearOnFirstInput: true); } if (DNS1Input != null) { DNS1Input.onEndEdit.AddListener(ValidateIPAddress); DNS1Input.characterLimit = 15; CustomKeyboardManager.SetupInputField(DNS1Input, KeyboardLayout.Numeric, (newValue) => { DNS1Input.text = newValue; ValidateIPAddress(newValue); }, clearOnFirstInput: true); } if (DNS2Input != null) { DNS2Input.onEndEdit.AddListener(ValidateIPAddress); DNS2Input.characterLimit = 15; CustomKeyboardManager.SetupInputField(DNS2Input, KeyboardLayout.Numeric, (newValue) => { DNS2Input.text = newValue; ValidateIPAddress(newValue); }, clearOnFirstInput: true); } } private void ValidateIPAddress(string ip) { if (string.IsNullOrEmpty(ip)) return; if (!IPAddress.TryParse(ip, out _)) { Debug.LogWarning($"无效的IP地址格式: {ip}"); // 这里可以显示错误提示 } } private void ValidateSubnetMask(string mask) { if (string.IsNullOrEmpty(mask)) return; // 验证子网掩码格式和有效性 if (!IPAddress.TryParse(mask, out IPAddress maskAddr)) { Debug.LogWarning($"无效的子网掩码格式: {mask}"); return; } // 检查是否为有效的子网掩码 byte[] maskBytes = maskAddr.GetAddressBytes(); uint maskUint = (uint)(maskBytes[0] << 24 | maskBytes[1] << 16 | maskBytes[2] << 8 | maskBytes[3]); // 检查掩码是否连续 uint inverted = ~maskUint; if ((inverted & (inverted + 1)) != 0) { Debug.LogWarning($"无效的子网掩码: {mask}"); } } private void UpdateNetworkModeDisplay(bool isDhcp) { string mode = isDhcp ? "DHCP (自动获取)" : "静态IP"; StaticToggle.isOn = !isDhcp; DhcpToggle.isOn = isDhcp; Debug.Log($"网络模式: {mode}"); } private void UpdateNetworkStatus() { try { #if UNITY_ANDROID && !UNITY_EDITOR // Android平台:避免Unity底层网络检查,使用简化的状态显示 ShowStaticNetworkStatus(); #else // 其他平台:保留原有网络检查逻辑 NetworkReachability reachability = Application.internetReachability; bool isConnected = reachability != NetworkReachability.NotReachable; string networkType = reachability.ToString(); if (NetworkStatusText != null) { string status = isConnected ? "网络已连接" : "网络未连接"; NetworkStatusText.text = $"{status} ({networkType})"; NetworkStatusText.color = isConnected ? Color.green : Color.red; } if (ConnectionStatusIcon != null) { ConnectionStatusIcon.color = isConnected ? Color.green : Color.red; } // 更新当前IP地址和网络信息 UpdateCurrentIPDisplay(); #endif } catch (System.Exception ex) { Debug.LogError($"更新网络状态失败: {ex.Message}"); // 异常时显示静态状态 ShowStaticNetworkStatus(); } } /// /// 显示静态网络状态(Android平台专用,避免Unity网络检查) /// private void ShowStaticNetworkStatus() { if (NetworkStatusText != null) { NetworkStatusText.text = "网络配置 (无在线检测)"; NetworkStatusText.color = Color.gray; } if (ConnectionStatusIcon != null) { ConnectionStatusIcon.color = Color.gray; } if (CurrentIPText != null) { CurrentIPText.text = "当前IP: 配置模式"; } } /// /// 显示局域网配置状态(Android平台专用,适用于医疗设备局域网环境) /// private void ShowLANConfigurationStatus() { if (NetworkStatusText != null) { NetworkStatusText.text = "局域网配置模式 (医疗设备专用)"; NetworkStatusText.color = Color.blue; // 蓝色表示局域网模式 } if (ConnectionStatusIcon != null) { ConnectionStatusIcon.color = Color.blue; // 蓝色表示局域网模式 } // 显示当前配置的IP信息(不检查连接状态) UpdateIPConfigurationDisplay(); } /// /// 更新IP配置显示(不进行网络连接检查) /// private void UpdateIPConfigurationDisplay() { if (CurrentIPText != null) { try { var config = _vm.Network; string displayText = ""; if (config.Mode == NetworkMode.Dhcp) { displayText = "网络模式: DHCP (自动获取)\n"; displayText += "适用于: 路由器环境\n"; displayText += "状态: 配置已保存"; } else { displayText = "网络模式: 静态IP\n"; displayText += $"IP地址: {config.IPv4}\n"; displayText += $"子网掩码: {config.Mask}\n"; displayText += $"网关: {config.Gateway}\n"; if (!string.IsNullOrEmpty(config.Dns1)) displayText += $"DNS1: {config.Dns1}\n"; if (!string.IsNullOrEmpty(config.Dns2)) displayText += $"DNS2: {config.Dns2}\n"; displayText += "适用于: 监护仪局域网"; } CurrentIPText.text = displayText; } catch (System.Exception ex) { CurrentIPText.text = "IP配置: 获取配置失败"; Debug.LogError($"获取IP配置显示失败: {ex.Message}"); } } } /// /// 加载并显示当前DHCP获取的IP信息 /// private void LoadAndDisplayCurrentDhcpIP() { try { #if UNITY_ANDROID && !UNITY_EDITOR // Android平台:获取实际的DHCP分配的IP信息 var ipConfig = AndroidNetworkConfigurator.GetCurrentIPConfiguration(); if (ipConfig != null && ipConfig.ContainsKey("status") && ipConfig["status"] == "success") { string dhcpIp = ipConfig.ContainsKey("dhcp_ip") ? ipConfig["dhcp_ip"] : "获取中..."; string dhcpMask = ipConfig.ContainsKey("dhcp_mask") ? ipConfig["dhcp_mask"] : "获取中..."; string dhcpGateway = ipConfig.ContainsKey("dhcp_gateway") ? ipConfig["dhcp_gateway"] : "获取中..."; string dhcpDns1 = ipConfig.ContainsKey("dhcp_dns1") ? ipConfig["dhcp_dns1"] : ""; string dhcpDns2 = ipConfig.ContainsKey("dhcp_dns2") ? ipConfig["dhcp_dns2"] : ""; // 在输入字段中显示当前IP(只读) if (IPv4Input != null) IPv4Input.text = dhcpIp; if (SubnetMaskInput != null) SubnetMaskInput.text = dhcpMask; if (GatewayInput != null) GatewayInput.text = dhcpGateway; if (DNS1Input != null) DNS1Input.text = dhcpDns1; if (DNS2Input != null) DNS2Input.text = dhcpDns2; Debug.Log($"[DHCP] 已加载当前IP: {dhcpIp}"); } else { // 获取失败时显示提示 if (IPv4Input != null) IPv4Input.text = "自动获取中..."; if (SubnetMaskInput != null) SubnetMaskInput.text = ""; if (GatewayInput != null) GatewayInput.text = ""; if (DNS1Input != null) DNS1Input.text = ""; if (DNS2Input != null) DNS2Input.text = ""; Debug.LogWarning("[DHCP] 获取IP配置失败"); } #else // PC平台:尝试获取本地IP try { System.Net.NetworkInformation.NetworkInterface[] interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); string localIP = "127.0.0.1"; string subnetMask = "255.255.255.0"; string gateway = ""; foreach (var ni in interfaces) { if (ni.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up && ni.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback) { var ipProps = ni.GetIPProperties(); foreach (var addr in ipProps.UnicastAddresses) { if (addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { localIP = addr.Address.ToString(); subnetMask = addr.IPv4Mask.ToString(); break; } } if (ipProps.GatewayAddresses.Count > 0) { gateway = ipProps.GatewayAddresses[0].Address.ToString(); } break; } } if (IPv4Input != null) IPv4Input.text = localIP; if (SubnetMaskInput != null) SubnetMaskInput.text = subnetMask; if (GatewayInput != null) GatewayInput.text = gateway; if (DNS1Input != null) DNS1Input.text = ""; if (DNS2Input != null) DNS2Input.text = ""; Debug.Log($"[DHCP] 已加载当前IP: {localIP}"); } catch (System.Exception ex) { Debug.LogWarning($"[DHCP] 获取PC IP失败: {ex.Message}"); if (IPv4Input != null) IPv4Input.text = "127.0.0.1"; } #endif } catch (System.Exception ex) { Debug.LogError($"[DHCP] 加载IP配置异常: {ex.Message}"); if (IPv4Input != null) IPv4Input.text = "获取失败"; } } private void UpdateCurrentIPDisplay() { if (CurrentIPText != null) { try { #if UNITY_ANDROID && !UNITY_EDITOR // Android平台:显示配置模式,避免网络检查 CurrentIPText.text = "当前IP: 配置模式 (避免网络检查)"; #else // 其他平台:保留IP获取逻辑 string currentIP = "127.0.0.1"; // 临时修复 CurrentIPText.text = $"当前IP: {currentIP}"; CurrentIPText.text += $"\n网络: 配置模式"; #endif } catch (System.Exception ex) { CurrentIPText.text = "当前IP: 获取失败"; Debug.LogError($"获取IP显示失败: {ex.Message}"); } } } #if UNITY_ANDROID && !UNITY_EDITOR private void UpdateAndroidPermissionStatus() { try { bool hasNetworkPermission = AndroidPermissionManager.HasNetworkStatePermission(); bool hasWifiPermission = AndroidPermissionManager.HasWifiStatePermission(); if (!hasNetworkPermission || !hasWifiPermission) { if (NetworkStatusText != null) { NetworkStatusText.text += "\n⚠️ 权限受限"; NetworkStatusText.color = Color.yellow; } Debug.LogWarning("网络权限不足,功能可能受限"); } } catch (System.Exception ex) { Debug.LogError($"检查Android权限失败: {ex.Message}"); } } #endif /// /// 完成局域网配置验证(Android平台专用) /// private void CompleteLANConfigurationTest() { // 验证IP配置的有效性(不进行实际网络连接) bool configValid = ValidateCurrentNetworkConfig(); if (NetworkStatusText != null) { if (configValid) { NetworkStatusText.text = "局域网配置有效"; NetworkStatusText.color = Color.green; } else { NetworkStatusText.text = "局域网配置需要检查"; NetworkStatusText.color = new Color(1f, 0.5f, 0f); // 橙色 } } Debug.Log($"局域网配置验证结果: {(configValid ? "配置有效" : "需要检查配置")}"); // 3秒后恢复局域网状态显示 Invoke(nameof(ShowLANConfigurationStatus), 3f); } /// /// 验证当前网络配置的有效性(不进行实际连接测试) /// private bool ValidateCurrentNetworkConfig() { try { var config = _tempConfig; // DHCP模式总是有效的 if (config.Mode == NetworkMode.Dhcp) { return true; } // 静态IP模式验证 if (config.Mode == NetworkMode.Static) { // 验证IP地址格式 if (string.IsNullOrEmpty(config.IPv4) || !System.Net.IPAddress.TryParse(config.IPv4, out _)) { return false; } // 验证子网掩码格式 if (string.IsNullOrEmpty(config.Mask) || !System.Net.IPAddress.TryParse(config.Mask, out _)) { return false; } // 验证网关格式(可选) if (!string.IsNullOrEmpty(config.Gateway) && !System.Net.IPAddress.TryParse(config.Gateway, out _)) { return false; } // 验证DNS格式(可选) if (!string.IsNullOrEmpty(config.Dns1) && !System.Net.IPAddress.TryParse(config.Dns1, out _)) { return false; } if (!string.IsNullOrEmpty(config.Dns2) && !System.Net.IPAddress.TryParse(config.Dns2, out _)) { return false; } return true; } return false; } catch (System.Exception ex) { Debug.LogError($"验证网络配置时发生异常: {ex.Message}"); return false; } } private void ResetToDefaults() { _tempConfig = new NetworkConfig { Mode = NetworkMode.Dhcp, IPv4 = "", Mask = "255.255.255.0", Gateway = "", Dns1 = "", Dns2 = "" }; LoadConfigToUI(_tempConfig); Debug.Log("网络设置已重置为默认值"); } private void LoadConfigToUI(NetworkConfig config) { bool isDhcp = config.Mode == NetworkMode.Dhcp; if (DhcpToggle != null) DhcpToggle.isOn = isDhcp; if (StaticToggle != null) StaticToggle.isOn = !isDhcp; if (IPv4Input != null) IPv4Input.text = config.IPv4; if (SubnetMaskInput != null) SubnetMaskInput.text = config.Mask; if (GatewayInput != null) GatewayInput.text = config.Gateway; if (DNS1Input != null) DNS1Input.text = config.Dns1; if (DNS2Input != null) DNS2Input.text = config.Dns2; SetStaticFieldsInteractable(!isDhcp); } private void ApplyAndBack() { // 收集当前UI的设置 _tempConfig.Mode = (DhcpToggle != null && DhcpToggle.isOn) ? NetworkMode.Dhcp : NetworkMode.Static; if (_tempConfig.Mode == NetworkMode.Static) { if (IPv4Input != null) _tempConfig.IPv4 = IPv4Input.text; if (SubnetMaskInput != null) _tempConfig.Mask = SubnetMaskInput.text; if (GatewayInput != null) _tempConfig.Gateway = GatewayInput.text; if (DNS1Input != null) _tempConfig.Dns1 = DNS1Input.text; if (DNS2Input != null) _tempConfig.Dns2 = DNS2Input.text; // 验证静态IP配置 if (!ValidateStaticConfig(_tempConfig)) { Debug.LogWarning("静态IP配置无效,请检查输入"); return; } } else { _tempConfig.Dns1 = ""; _tempConfig.Dns2 = ""; } // 应用设置 _vm.Network = _tempConfig; Debug.Log($"网络设置已应用: {_tempConfig.Mode}, IP: {_tempConfig.IPv4}"); // DHCP模式下尝试立即刷新当前IP显示(下发后可能有短暂延迟) if (_tempConfig.Mode == NetworkMode.Dhcp) { Invoke(nameof(UpdateCurrentIPDisplay), 1f); } else { UpdateCurrentIPDisplay(); } ClosePanel(); } private bool ValidateStaticConfig(NetworkConfig config) { if (config.Mode == NetworkMode.Static) { if (string.IsNullOrEmpty(config.IPv4) || !IPAddress.TryParse(config.IPv4, out _)) return false; if (string.IsNullOrEmpty(config.Mask) || !IPAddress.TryParse(config.Mask, out _)) return false; if (!string.IsNullOrEmpty(config.Gateway) && !IPAddress.TryParse(config.Gateway, out _)) return false; if (!string.IsNullOrEmpty(config.Dns1) && !IPAddress.TryParse(config.Dns1, out _)) return false; if (!string.IsNullOrEmpty(config.Dns2) && !IPAddress.TryParse(config.Dns2, out _)) return false; } return true; } // public void ClosePanel() // { // CancelInvoke(); // 停止定期更新 // UIManager.Instance.HidePanel(); // } void OnDestroy() { CancelInvoke(); // 关闭自定义键盘(如果正在显示) if (CustomKeyboardManager.Instance != null && CustomKeyboardManager.Instance.IsKeyboardShowing()) { CustomKeyboardManager.Instance.HideKeyboard(); } } }