diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 0502675..8f45ea5 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -6,10 +6,14 @@ class AppConfig { static const Environment currentEnvironment = Environment.production; static const String appName = '本地打包'; static const String appLogo = ''; + static const String canonicalWebHost = 'h5-im.imharry.work'; + static const Set legacyWebHosts = { + 'h5-test.imharry.work', + }; static final Map> _environmentHosts = { Environment.production: [ - 'h5-im.imharry.work', + canonicalWebHost, ], }; @@ -18,9 +22,8 @@ class AppConfig { } static String homeUrl({String? appName, String? appLogo}) { - final host = environmentHosts.isNotEmpty - ? environmentHosts.first - : 'h5-im.imharry.work'; + final host = + environmentHosts.isNotEmpty ? environmentHosts.first : canonicalWebHost; final uri = Uri.parse(_normalizeHomeUrl(host)); final queryParameters = Map.from(uri.queryParameters) ..['_h5_t'] = DateTime.now().millisecondsSinceEpoch.toString(); @@ -29,7 +32,39 @@ class AppConfig { } static String withFreshShellParams(String url) { - final uri = Uri.parse(url); + return _removeShellParams(Uri.parse(url)).toString(); + } + + static bool shouldRewriteMainFrameUrl(String url) { + final uri = Uri.tryParse(url); + if (uri == null) { + return false; + } + + final host = uri.host.toLowerCase(); + return legacyWebHosts.contains(host) || _hasShellParams(uri); + } + + static String canonicalizeMainFrameUrl(String url) { + final uri = _removeShellParams(Uri.parse(url)); + final host = uri.host.toLowerCase(); + if (!legacyWebHosts.contains(host)) { + return uri.toString(); + } + + final queryParameters = Map.from(uri.queryParameters) + ..['_h5_t'] = DateTime.now().millisecondsSinceEpoch.toString(); + + return uri + .replace( + scheme: 'https', + host: canonicalWebHost, + queryParameters: queryParameters, + ) + .toString(); + } + + static Uri _removeShellParams(Uri uri) { final queryParameters = Map.from(uri.queryParameters); queryParameters.remove('flutter_shell'); queryParameters.remove('shell_cache_bust'); @@ -39,14 +74,22 @@ class AppConfig { fragmentParameters.remove('shell_app_name'); fragmentParameters.remove('shell_app_logo'); - return uri - .replace( - queryParameters: queryParameters, - fragment: fragmentParameters.isEmpty - ? '' - : Uri(queryParameters: fragmentParameters).query, - ) - .toString(); + return uri.replace( + queryParameters: queryParameters, + fragment: fragmentParameters.isEmpty + ? '' + : Uri(queryParameters: fragmentParameters).query, + ); + } + + static bool _hasShellParams(Uri uri) { + final fragmentParameters = Uri.splitQueryString(uri.fragment); + return uri.queryParameters.containsKey('flutter_shell') || + uri.queryParameters.containsKey('shell_cache_bust') || + uri.queryParameters.containsKey('shell_app_name') || + uri.queryParameters.containsKey('shell_app_logo') || + fragmentParameters.containsKey('shell_app_name') || + fragmentParameters.containsKey('shell_app_logo'); } static String _normalizeHomeUrl(String host) { diff --git a/lib/main.dart b/lib/main.dart index 1fb3ea5..8e761f3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -304,6 +304,8 @@ class _H5ShellPageState extends State { } Future _loadUrl(String url) async { + final targetUrl = AppConfig.canonicalizeMainFrameUrl(url); + if (mounted) { setState(() { _loadError = null; @@ -313,7 +315,7 @@ class _H5ShellPageState extends State { } await _clearWebViewHttpCache(); - await _controller.loadRequest(Uri.parse(url)); + await _controller.loadRequest(Uri.parse(targetUrl)); } Future _clearWebViewHttpCache() async { @@ -334,6 +336,11 @@ class _H5ShellPageState extends State { const webSchemes = {'http', 'https', 'about', 'data'}; if (webSchemes.contains(uri.scheme)) { + if (request.isMainFrame && + AppConfig.shouldRewriteMainFrameUrl(request.url)) { + unawaited(_loadUrl(AppConfig.canonicalizeMainFrameUrl(request.url))); + return NavigationDecision.prevent; + } return NavigationDecision.navigate; } diff --git a/test/widget_test.dart b/test/widget_test.dart index 3cfbcd3..418304e 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -47,4 +47,22 @@ void main() { expect(Uri.splitQueryString(uri.fragment).containsKey('shell_app_logo'), isFalse); }); + + test('rewrites legacy H5 host main-frame URLs to the canonical host', () { + final uri = Uri.parse( + AppConfig.canonicalizeMainFrameUrl( + 'https://h5-test.imharry.work/login?from=runtime' + '&shell_app_name=Old#shell_app_logo=old', + ), + ); + + expect(uri.scheme, 'https'); + expect(uri.host, 'h5-im.imharry.work'); + expect(uri.path, '/login'); + expect(uri.queryParameters['from'], 'runtime'); + expect(uri.queryParameters.containsKey('_h5_t'), isTrue); + expect(uri.queryParameters.containsKey('shell_app_name'), isFalse); + expect(Uri.splitQueryString(uri.fragment).containsKey('shell_app_logo'), + isFalse); + }); }