update browser history switching (flutter/engine#23471)

This commit is contained in:
chunhtai 2021-01-20 09:34:02 -08:00 committed by GitHub
parent ca255e3794
commit 367ce3fcf3
2 changed files with 84 additions and 5 deletions

View File

@ -51,7 +51,7 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow {
}
BrowserHistory? _browserHistory;
bool _usingRouter = false;
Future<void> _useSingleEntryBrowserHistory() async {
if (_browserHistory is SingleEntryBrowserHistory) {
return;
@ -61,6 +61,15 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow {
_browserHistory = SingleEntryBrowserHistory(urlStrategy: strategy);
}
Future<void> _useMultiEntryBrowserHistory() async {
if (_browserHistory is MultiEntriesBrowserHistory) {
return;
}
final UrlStrategy? strategy = _browserHistory?.urlStrategy;
await _browserHistory?.tearDown();
_browserHistory = MultiEntriesBrowserHistory(urlStrategy: strategy);
}
@visibleForTesting
Future<void> debugInitializeHistory(
UrlStrategy? strategy, {
@ -68,7 +77,7 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow {
}) async {
// Prevent any further customization of URL strategy.
_isUrlStrategySet = true;
_usingRouter = false;
await _browserHistory?.tearDown();
if (useSingle) {
_browserHistory = SingleEntryBrowserHistory(urlStrategy: strategy);
@ -95,11 +104,22 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow {
switch (decoded.method) {
case 'routeUpdated':
await _useSingleEntryBrowserHistory();
browserHistory.setRouteName(arguments['routeName']);
if (!_usingRouter) {
await _useSingleEntryBrowserHistory();
browserHistory.setRouteName(arguments['routeName']);
} else {
assert(
false,
'Receives old navigator update in a router application. '
'This can happen if you use non-router versions of MaterialApp/'
'CupertinoApp/WidgetsApp together with the router versions of them.'
);
return false;
}
return true;
case 'routeInformationUpdated':
assert(browserHistory is MultiEntriesBrowserHistory);
await _useMultiEntryBrowserHistory();
_usingRouter = true;
browserHistory.setRouteName(
arguments['location'],
state: arguments['state'],

View File

@ -3,6 +3,7 @@
// found in the LICENSE file.
// @dart = 2.6
import 'dart:async';
import 'dart:html' as html;
import 'dart:js_util' as js_util;
import 'dart:typed_data';
@ -69,6 +70,64 @@ void testMain() {
expect(window.defaultRouteName, '/');
});
test('should throw when using nav1 and nav2 together',
() async {
await window.debugInitializeHistory(TestUrlStrategy.fromEntry(
TestHistoryEntry('initial state', null, '/initial'),
), useSingle: false);
// Receive nav1 update first.
Completer<void> callback = Completer<void>();
window.sendPlatformMessage(
'flutter/navigation',
JSONMethodCodec().encodeMethodCall(MethodCall(
'routeUpdated',
<String, dynamic>{'routeName': '/bar'},
)),
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory is SingleEntryBrowserHistory, true);
expect(window.browserHistory.urlStrategy.getPath(), '/bar');
// We can still receive nav2 update.
callback = Completer<void>();
window.sendPlatformMessage(
'flutter/navigation',
JSONMethodCodec().encodeMethodCall(MethodCall(
'routeInformationUpdated',
<String, dynamic>{
'location': '/baz',
'state': null,
},
)),
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory is MultiEntriesBrowserHistory, true);
expect(window.browserHistory.urlStrategy.getPath(), '/baz');
// Throws assertion error if it receives nav1 update after nav2 update.
AssertionError caughtAssertion;
await window.handleNavigationMessage(
JSONMethodCodec().encodeMethodCall(MethodCall(
'routeUpdated',
<String, dynamic>{'routeName': '/foo'},
))
).catchError((Object e) {
caughtAssertion = e as AssertionError;
});
expect(
caughtAssertion.message,
'Receives old navigator update in a router application. This can '
'happen if you use non-router versions of '
'MaterialApp/CupertinoApp/WidgetsApp together with the router versions of them.'
);
// The history does not change.
expect(window.browserHistory is MultiEntriesBrowserHistory, true);
expect(window.browserHistory.urlStrategy.getPath(), '/baz');
});
test('can disable location strategy', () async {
// Disable URL strategy.
expect(() => jsSetUrlStrategy(null), returnsNormally);