diff --git a/lib/main.dart b/lib/main.dart index 1830c04..d3632a5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -475,6 +475,8 @@ class _H5ShellPageState extends State with WidgetsBindingObserver { _hideShellCover(generation); } else if (decoded is Map && decoded['type'] == 'keyboard-bridge-ready') { unawaited(_syncKeyboardState()); + } else if (decoded is Map && decoded['type'] == 'openExternalUrl') { + unawaited(_openExternalUrl(decoded['url']?.toString())); } } catch (_) { if (message.message == 'first-screen-ready') { @@ -512,6 +514,8 @@ class _H5ShellPageState extends State with WidgetsBindingObserver { unawaited(openAppSettings()); case 'keyboard-bridge-ready': unawaited(_syncKeyboardState()); + case 'openExternalUrl': + unawaited(_openExternalUrl(decoded['url']?.toString())); } } catch (_) { // Ignore malformed shell messages from web content. @@ -939,18 +943,52 @@ class _H5ShellPageState extends State with WidgetsBindingObserver { return NavigationDecision.prevent; } - const webSchemes = {'http', 'https', 'about', 'data'}; - if (webSchemes.contains(uri.scheme)) { + const inWebViewSchemes = {'about', 'data'}; + if (inWebViewSchemes.contains(uri.scheme) || _isCurrentH5Origin(uri)) { return NavigationDecision.navigate; } + if (uri.scheme == 'http' || uri.scheme == 'https') { + await _openExternalUri(uri); + return NavigationDecision.prevent; + } + + await _openExternalUri(uri); + return NavigationDecision.prevent; + } + + bool _isCurrentH5Origin(Uri uri) { + final currentUri = Uri.tryParse(_currentSlot.line.url); + if (currentUri == null) { + return false; + } + + return uri.scheme == currentUri.scheme && + uri.host == currentUri.host && + uri.port == currentUri.port; + } + + Future _openExternalUrl(String? rawUrl) async { + final url = rawUrl?.trim(); + if (url == null || url.isEmpty) { + return; + } + + final uri = Uri.tryParse(url); + if (uri == null || !uri.hasScheme) { + return; + } + + await _openExternalUri(uri); + } + + Future _openExternalUri(Uri uri) async { try { await launchUrl(uri, mode: LaunchMode.externalApplication); } catch (_) { // Ignore unsupported custom schemes so the WebView does not navigate to // an error page. } - return NavigationDecision.prevent; } Future _handleBackNavigation() async {