From 6e083495569518aa229f568f7898842849c79bb4 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 24 Mar 2026 15:54:38 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20ErrorOverlay=20=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E8=A7=81=20=E2=80=94=20Stack=20=E5=9C=A8=20Visibility(visible:?= =?UTF-8?q?false)=20=E6=97=B6=E5=9D=8D=E7=BC=A9=E4=B8=BA=200=C3=970?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当 _hasMainFrameError=true 时,Visibility(visible:false) 将 WebView 替换为 SizedBox.shrink()(0×0),这是 Stack 唯一的非 positioned 子组件。 Scaffold.body 提供松约束(0→max),导致 Stack 尺寸为 0×0, Positioned.fill 的 ErrorOverlay 也变为 0×0,用户只能看到 Scaffold 的 深色背景而看不到错误页面的内容。 修复方式:用 SizedBox.expand() 包裹 Stack,强制紧约束使其始终填满屏幕。 附带变更: - 添加 _debugLog() 封装(kDebugMode 保护) - 在 7 个关键状态转换点添加调试日志 --- .../web_shell_core/lib/src/ui/shell_page.dart | 125 +++++++++++++----- 1 file changed, 95 insertions(+), 30 deletions(-) diff --git a/packages/web_shell_core/lib/src/ui/shell_page.dart b/packages/web_shell_core/lib/src/ui/shell_page.dart index beaf934..da7593b 100644 --- a/packages/web_shell_core/lib/src/ui/shell_page.dart +++ b/packages/web_shell_core/lib/src/ui/shell_page.dart @@ -199,6 +199,12 @@ class _WebShellPageState extends State return generation == _webViewGeneration; } + void _debugLog(String message) { + if (kDebugMode) { + debugPrint(message); + } + } + PlatformWebViewWidgetCreationParams _buildAndroidWidgetParams( PlatformWebViewWidgetCreationParams widgetParams, AndroidRenderMode renderMode, @@ -282,6 +288,11 @@ class _WebShellPageState extends State _hasMeasuredProgress = true; } }); + _debugLog( + '🔍 [onProgress] progress=$progress, ' + 'hasStartedRemote=$_hasStartedRemoteMainFrame, ' + 'hasMeasured=$_hasMeasuredProgress', + ); }, onNavigationRequest: (request) async { if (!_isActiveWebViewGeneration(generation)) { @@ -316,6 +327,13 @@ class _WebShellPageState extends State _hasStartedRemoteMainFrame = true; _cancelStartupWatchdog(); _recordWebViewEvent('页面开始加载:$url'); + _debugLog( + '🔍 [onPageStarted] url=$url, ' + 'hasStartedRemote=$_hasStartedRemoteMainFrame, ' + 'hasBootstrapped=$_hasBootstrapped, ' + 'hasMainFrameError=$_hasMainFrameError, ' + 'watchdog已取消', + ); if (!mounted) { return; } @@ -341,6 +359,12 @@ class _WebShellPageState extends State } _recordWebViewEvent('页面加载完成:$url'); _cancelStartupWatchdog(); + _debugLog( + '🔍 [onPageFinished] url=$url, ' + 'hasMainFrameError=$_hasMainFrameError, ' + 'injectBridge=${!_hasMainFrameError}, ' + 'retryCount=$_startupRetryCount', + ); if (!_hasMainFrameError) { unawaited(_injectAppShellBridge(_controller, url)); } @@ -392,6 +416,11 @@ class _WebShellPageState extends State 'url=${error.url}, ' 'description=${error.description}', ); + _debugLog( + '🔍 [onWebResourceError] isMainFrame=${error.isForMainFrame}, ' + 'errorType=${error.errorType}, ' + 'willSetMainFrameError=${error.isForMainFrame != false}', + ); if (!mounted || error.isForMainFrame == false) { return; } @@ -476,10 +505,19 @@ class _WebShellPageState extends State } Future _handleStartupTimeout() async { + _debugLog( + '🔍 [_handleStartupTimeout] mounted=$mounted, ' + 'isLoading=$_isLoadingPage, ' + 'hasMainFrameError=$_hasMainFrameError, ' + 'hasStartedRemote=$_hasStartedRemoteMainFrame, ' + 'retryCount=$_startupRetryCount, ' + 'renderIndex=$_renderModeIndex', + ); if (!mounted || !_isLoadingPage || _hasMainFrameError || _hasStartedRemoteMainFrame) { + _debugLog('🔍 [_handleStartupTimeout] 提前返回,不执行超时恢复'); return; } @@ -487,6 +525,11 @@ class _WebShellPageState extends State final maxRetryCount = _androidCompatibilityPlan.prefersAggressiveRecovery ? 2 : 1; + _debugLog( + '🔍 [_handleStartupTimeout] switchedRenderMode=$switchedRenderMode, ' + 'maxRetryCount=$maxRetryCount, ' + 'currentRetryCount=$_startupRetryCount', + ); if (switchedRenderMode || _startupRetryCount < maxRetryCount) { final nextRetryCount = _startupRetryCount + 1; @@ -505,6 +548,7 @@ class _WebShellPageState extends State return; } + _debugLog('🔍 [_handleStartupTimeout] 所有重试已耗尽,显示错误页面'); _setMainFrameError( title: '页面启动超时', message: [ @@ -516,6 +560,10 @@ class _WebShellPageState extends State } void _setMainFrameError({required String title, required String message}) { + _debugLog( + '🔍 [_setMainFrameError] title=$title, ' + 'message=$message', + ); _cancelStartupWatchdog(); if (!mounted) { return; @@ -528,6 +576,12 @@ class _WebShellPageState extends State _errorMessage = message; _progress = 0; }); + _debugLog( + '🔍 [_setMainFrameError] 状态已更新: ' + 'isLoading=$_isLoadingPage, ' + 'hasMainFrameError=$_hasMainFrameError, ' + '→ 应显示 ErrorOverlay', + ); } Future _recoverFromBrokenStartupState({bool deepReset = false}) async { @@ -1023,6 +1077,15 @@ class _WebShellPageState extends State final showProgressBar = _isLoadingPage && (!_hasMeasuredProgress || _progress < 100); final showLaunchOverlay = !_hasBootstrapped && !_hasMainFrameError; + _debugLog( + '🔍 [build] showProgressBar=$showProgressBar, ' + 'showLaunchOverlay=$showLaunchOverlay, ' + 'showErrorOverlay=$_hasMainFrameError, ' + 'showWebView=${!_hasMainFrameError}, ' + 'isLoading=$_isLoadingPage, ' + 'hasBootstrapped=$_hasBootstrapped, ' + 'progress=$_progress', + ); return PopScope( canPop: false, @@ -1041,39 +1104,41 @@ class _WebShellPageState extends State end: Alignment.bottomCenter, ), ), - child: Stack( - children: [ - Visibility( - visible: !_hasMainFrameError, - child: _webViewWidget, - ), - if (showProgressBar) - Positioned( - top: 0, - left: 0, - right: 0, - child: TopProgressBar( - progress: _progress, - hasMeasuredProgress: _hasMeasuredProgress, - ), + child: SizedBox.expand( + child: Stack( + children: [ + Visibility( + visible: !_hasMainFrameError, + child: _webViewWidget, ), - if (showLaunchOverlay) - Positioned.fill( - child: LaunchOverlay( - progress: _progress, - hasMeasuredProgress: _hasMeasuredProgress, + if (showProgressBar) + Positioned( + top: 0, + left: 0, + right: 0, + child: TopProgressBar( + progress: _progress, + hasMeasuredProgress: _hasMeasuredProgress, + ), ), - ), - if (_hasMainFrameError) - Positioned.fill( - child: ErrorOverlay( - title: _errorTitle, - message: _errorMessage, - currentUrl: _currentUrl, - onRetry: _reloadPage, + if (showLaunchOverlay) + Positioned.fill( + child: LaunchOverlay( + progress: _progress, + hasMeasuredProgress: _hasMeasuredProgress, + ), ), - ), - ], + if (_hasMainFrameError) + Positioned.fill( + child: ErrorOverlay( + title: _errorTitle, + message: _errorMessage, + currentUrl: _currentUrl, + onRetry: _reloadPage, + ), + ), + ], + ), ), ), ),