feat: 添加登录页面 URL 检测功能;更新 H5ShellPage 状态管理以支持路由变化

This commit is contained in:
Booker
2026-05-27 13:16:35 +07:00
parent 6e3920972b
commit 179a2332ae
3 changed files with 119 additions and 1 deletions

View File

@@ -133,11 +133,12 @@ class _H5ShellPageState extends State<H5ShellPage> {
setState(() => _lineSlots[lineIndex].progress = progress);
}
},
onPageStarted: (_) {
onPageStarted: (url) {
final slot = _lineSlots[lineIndex];
slot.shellCoverFallbackTimer?.cancel();
if (mounted) {
setState(() {
slot.setCurrentUrl(url);
slot.loadError = null;
slot.progress = 0;
slot.showShellCover = true;
@@ -147,6 +148,9 @@ class _H5ShellPageState extends State<H5ShellPage> {
onPageFinished: (_) {
unawaited(_handlePageFinished(lineIndex));
},
onUrlChange: (change) {
_updateSlotUrl(lineIndex, change.url);
},
onWebResourceError: (error) {
if (error.isForMainFrame ?? true) {
final slot = _lineSlots[lineIndex];
@@ -183,6 +187,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
Future<void> _handlePageFinished(int lineIndex) async {
await _loadShellBrandingIfNeeded();
await _syncShellBranding(lineIndex);
await _installRouteObserver(lineIndex);
if (mounted) {
setState(() {
_lineSlots[lineIndex].progress = 100;
@@ -196,6 +201,8 @@ class _H5ShellPageState extends State<H5ShellPage> {
final decoded = jsonDecode(message.message);
if (decoded is Map && decoded['type'] == 'first-screen-ready') {
_hideShellCover(lineIndex);
} else if (decoded is Map && decoded['type'] == 'route-changed') {
_updateSlotUrl(lineIndex, decoded['url']?.toString());
}
} catch (_) {
if (message.message == 'first-screen-ready') {
@@ -260,6 +267,60 @@ class _H5ShellPageState extends State<H5ShellPage> {
return _runJavaScriptSafely(lineIndex, script);
}
Future<void> _installRouteObserver(int lineIndex) {
const script = '''
(() => {
try {
const notify = () => {
try {
window.OpenIMShell.postMessage(JSON.stringify({
type: 'route-changed',
url: window.location.href
}));
} catch (_) {}
};
if (window.__OPENIM_FLUTTER_ROUTE_OBSERVER__) {
window.__OPENIM_FLUTTER_ROUTE_OBSERVER__.notify();
return;
}
const originalPushState = window.history.pushState;
const originalReplaceState = window.history.replaceState;
window.history.pushState = function() {
const result = originalPushState.apply(this, arguments);
notify();
return result;
};
window.history.replaceState = function() {
const result = originalReplaceState.apply(this, arguments);
notify();
return result;
};
window.addEventListener('popstate', notify);
window.__OPENIM_FLUTTER_ROUTE_OBSERVER__ = { notify };
notify();
} catch (_) {}
})();
''';
return _runJavaScriptSafely(lineIndex, script);
}
void _updateSlotUrl(int lineIndex, String? url) {
if (url == null || lineIndex < 0 || lineIndex >= _lineSlots.length) {
return;
}
final slot = _lineSlots[lineIndex];
final changed = slot.setCurrentUrl(url);
if (changed && mounted) {
setState(() {});
}
}
Future<void> _ensureLineLoaded(int lineIndex) async {
final slot = _lineSlots[lineIndex];
if (slot.hasLoadedInitialRequest) {
@@ -270,6 +331,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
if (mounted) {
slot.shellCoverFallbackTimer?.cancel();
setState(() {
slot.setCurrentUrl(slot.line.url);
slot.loadError = null;
slot.progress = 0;
slot.showShellCover = true;
@@ -369,6 +431,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
final bottomInset = MediaQuery.viewInsetsOf(context).bottom;
final showLineSwitch = !currentSlot.showShellCover &&
currentSlot.loadError == null &&
currentSlot.isLoginPage &&
bottomInset == 0;
return PopScope(
@@ -448,8 +511,21 @@ class _H5LineWebViewSlot {
String? loadError;
bool showShellCover = true;
bool hasLoadedInitialRequest = false;
bool isLoginPage = false;
String? currentUrl;
Timer? shellCoverFallbackTimer;
bool setCurrentUrl(String url) {
final nextIsLoginPage = AppConfig.isLoginPageUrl(url);
if (currentUrl == url && isLoginPage == nextIsLoginPage) {
return false;
}
currentUrl = url;
isLoginPage = nextIsLoginPage;
return true;
}
void dispose() {
shellCoverFallbackTimer?.cancel();
}