Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
058a9343
Unverified
Commit
058a9343
authored
May 20, 2021
by
Ian Hickson
Committed by
GitHub
May 20, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate the navigator API to routeInformationUpdated. (#82594)
parent
b9645bfd
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
170 additions
and
77 deletions
+170
-77
system_channels.dart
packages/flutter/lib/src/services/system_channels.dart
+12
-3
system_navigator.dart
packages/flutter/lib/src/services/system_navigator.dart
+51
-8
navigator.dart
packages/flutter/lib/src/widgets/navigator.dart
+14
-6
router.dart
packages/flutter/lib/src/widgets/router.dart
+6
-0
system_navigator_test.dart
packages/flutter/test/services/system_navigator_test.dart
+41
-6
route_notification_messages_test.dart
...lutter/test/widgets/route_notification_messages_test.dart
+46
-54
No files found.
packages/flutter/lib/src/services/system_channels.dart
View file @
058a9343
...
...
@@ -32,10 +32,19 @@ class SystemChannels {
/// The following methods are used for the opposite direction data flow. The
/// framework notifies the engine about the route changes.
///
/// * `
routeUpdated`, which is called when current route has changed
.
/// * `
selectSingleEntryHistory`, which enables a single-entry history mode
.
///
/// * `routeInformationUpdated`, which is called by the [Router] when the
/// application navigate to a new location.
/// * `selectMultiEntryHistory`, which enables a multiple-entry history mode.
///
/// * `routeInformationUpdated`, which is called when the application
/// navigates to a new location, and which takes two arguments, `location`
/// (a URL) and `state` (an object).
///
/// * `routeUpdated`, a deprecated API which can be called in the same
/// situations as `routeInformationUpdated` but whose arguments are
/// `routeName` (a URL) and `previousRouteName` (which is ignored).
///
/// These APIs are exposed by the [SystemNavigator] class.
///
/// See also:
///
...
...
packages/flutter/lib/src/services/system_navigator.dart
View file @
058a9343
...
...
@@ -33,15 +33,50 @@ class SystemNavigator {
await
SystemChannels
.
platform
.
invokeMethod
<
void
>(
'SystemNavigator.pop'
,
animated
);
}
/// Selects the single-entry history mode.
///
/// On web, this switches the browser history model to one that only tracks a
/// single entry, so that calling [routeInformationUpdated] replaces the
/// current entry.
///
/// Currently, this is ignored on other platforms.
///
/// See also:
///
/// * [selectMultiEntryHistory], which enables the browser history to have
/// multiple entries.
static
Future
<
void
>
selectSingleEntryHistory
()
{
return
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'selectSingleEntryHistory'
);
}
/// Selects the multiple-entry history mode.
///
/// On web, this switches the browser history model to one that tracks alll
/// updates to [routeInformationUpdated] to form a history stack. This is the
/// default.
///
/// Currently, this is ignored on other platforms.
///
/// See also:
///
/// * [selectSingleEntryHistory], which forces the history to only have one
/// entry.
static
Future
<
void
>
selectMultiEntryHistory
()
{
return
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'selectMultiEntryHistory'
);
}
/// Notifies the platform for a route information change.
///
/// On Web, creates a new browser history entry and update URL with the route
/// information.
static
void
routeInformationUpdated
({
/// On web, creates a new browser history entry and update URL with the route
/// information. Whether the history holds one entry or multiple entries is
/// determined by [selectSingleEntryHistory] and [selectMultiEntryHistory].
///
/// Currently, this is ignored on other platforms.
static
Future
<
void
>
routeInformationUpdated
({
required
String
location
,
Object
?
state
,
})
{
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
return
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'routeInformationUpdated'
,
<
String
,
dynamic
>{
'location'
:
location
,
...
...
@@ -50,14 +85,22 @@ class SystemNavigator {
);
}
/// Notifies the platform of a route change.
/// Notifies the platform of a route change, and selects single-entry history
/// mode.
///
/// This is equivalent to calling [selectSingleEntryHistory] and
/// [routeInformationUpdated] together.
///
/// On Web, updates the URL bar with the [routeName].
static
void
routeUpdated
({
/// The `previousRouteName` argument is ignored.
@Deprecated
(
'Use routeInformationUpdated instead. '
'This feature was deprecated after v2.3.0-1.0.pre.'
)
static
Future
<
void
>
routeUpdated
({
String
?
routeName
,
String
?
previousRouteName
,
})
{
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
return
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'routeUpdated'
,
<
String
,
dynamic
>{
'previousRouteName'
:
previousRouteName
,
...
...
packages/flutter/lib/src/widgets/navigator.dart
View file @
058a9343
...
...
@@ -1624,6 +1624,13 @@ class Navigator extends StatefulWidget {
/// route update message to the engine when it detects top-most route changes.
/// The messages are used by the web engine to update the browser URL bar.
///
/// If the property is set to true when the [Navigator] is first created,
/// single-entry history mode is requested using
/// [SystemNavigator.selectSingleEntryHistory]. This means this property
/// should not be used at the same time as [PlatformRouteInformationProvider]
/// is used with a [Router] (including when used with [MaterialApp.router],
/// for example).
///
/// If there are multiple navigators in the widget tree, at most one of them
/// can set this property to true (typically, the top-most one created from
/// the [WidgetsApp]). Otherwise, the web engine may receive multiple route
...
...
@@ -3397,6 +3404,10 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
.
getElementForInheritedWidgetOfExactType
<
HeroControllerScope
>()
?.
widget
as
HeroControllerScope
?;
_updateHeroController
(
heroControllerScope
?.
controller
);
if
(
widget
.
reportsRouteUpdateToEngine
)
{
SystemNavigator
.
selectSingleEntryHistory
();
}
}
// Use [_nextPagelessRestorationScopeId] to get the next id.
...
...
@@ -4062,17 +4073,14 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
// notifications.
_flushRouteAnnouncement
();
// Announce
s
route name changes.
// Announce route name changes.
if
(
widget
.
reportsRouteUpdateToEngine
)
{
final
_RouteEntry
?
lastEntry
=
_history
.
cast
<
_RouteEntry
?>().
lastWhere
(
(
_RouteEntry
?
e
)
=>
e
!=
null
&&
_RouteEntry
.
isPresentPredicate
(
e
),
orElse:
()
=>
null
,
);
final
String
?
routeName
=
lastEntry
?.
route
.
settings
.
name
;
if
(
routeName
!=
_lastAnnouncedRouteName
)
{
SystemNavigator
.
routeUpdated
(
routeName:
routeName
,
previousRouteName:
_lastAnnouncedRouteName
,
);
if
(
routeName
!=
null
&&
routeName
!=
_lastAnnouncedRouteName
)
{
SystemNavigator
.
routeInformationUpdated
(
location:
routeName
);
_lastAnnouncedRouteName
=
routeName
;
}
}
...
...
packages/flutter/lib/src/widgets/router.dart
View file @
058a9343
...
...
@@ -1318,6 +1318,11 @@ abstract class RouteInformationProvider extends ValueListenable<RouteInformation
/// This provider also reports the new route information from the [Router] widget
/// back to engine using message channel method, the
/// [SystemNavigator.routeInformationUpdated].
///
/// Each time [SystemNavigator.routeInformationUpdated] is called, the
/// [SystemNavigator.selectMultiEntryHistory] method is also called. This
/// overrides the initialization behavior of
/// [Navigator.reportsRouteUpdateToEngine].
class
PlatformRouteInformationProvider
extends
RouteInformationProvider
with
WidgetsBindingObserver
,
ChangeNotifier
{
/// Create a platform route information provider.
///
...
...
@@ -1329,6 +1334,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid
@override
void
routerReportsNewRouteInformation
(
RouteInformation
routeInformation
)
{
SystemNavigator
.
selectMultiEntryHistory
();
SystemNavigator
.
routeInformationUpdated
(
location:
routeInformation
.
location
!,
state:
routeInformation
.
state
,
...
...
packages/flutter/test/services/system_navigator_test.dart
View file @
058a9343
...
...
@@ -2,23 +2,58 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
TestWidgetsFlutterBinding
.
ensureInitialized
();
test
(
'System navigator control test'
,
()
async
{
final
List
<
MethodCall
>
log
=
<
MethodCall
>[];
final
List
<
MethodCall
>
log
=
<
MethodCall
>[];
Future
<
void
>
verify
(
AsyncCallback
test
,
List
<
Object
>
expectations
)
async
{
log
.
clear
();
await
test
();
expect
(
log
,
expectations
);
}
test
(
'System navigator control test - platform messages'
,
()
async
{
SystemChannels
.
platform
.
setMockMethodCallHandler
((
MethodCall
methodCall
)
async
{
log
.
add
(
methodCall
);
});
await
SystemNavigator
.
pop
();
await
verify
(()
=>
SystemNavigator
.
pop
(),
<
Object
>[
isMethodCall
(
'SystemNavigator.pop'
,
arguments:
null
),
]);
SystemChannels
.
platform
.
setMockMethodCallHandler
(
null
);
});
test
(
'System navigator control test - navigation messages'
,
()
async
{
SystemChannels
.
navigation
.
setMockMethodCallHandler
((
MethodCall
methodCall
)
async
{
log
.
add
(
methodCall
);
});
await
verify
(()
=>
SystemNavigator
.
selectSingleEntryHistory
(),
<
Object
>[
isMethodCall
(
'selectSingleEntryHistory'
,
arguments:
null
),
]);
await
verify
(()
=>
SystemNavigator
.
selectMultiEntryHistory
(),
<
Object
>[
isMethodCall
(
'selectMultiEntryHistory'
,
arguments:
null
),
]);
await
verify
(()
=>
SystemNavigator
.
routeInformationUpdated
(
location:
'a'
),
<
Object
>[
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'location'
:
'a'
,
'state'
:
null
}),
]);
await
verify
(()
=>
SystemNavigator
.
routeInformationUpdated
(
location:
'a'
,
state:
true
),
<
Object
>[
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'location'
:
'a'
,
'state'
:
true
}),
]);
await
verify
(()
=>
SystemNavigator
.
routeUpdated
(
routeName:
'a'
,
previousRouteName:
'b'
),
<
Object
>[
isMethodCall
(
'routeUpdated'
,
arguments:
<
String
,
dynamic
>{
'routeName'
:
'a'
,
'previousRouteName'
:
'b'
}),
]);
expect
(
log
,
hasLength
(
1
));
expect
(
log
.
single
,
isMethodCall
(
'SystemNavigator.pop'
,
arguments:
null
));
SystemChannels
.
navigation
.
setMockMethodCallHandler
(
null
);
});
}
packages/flutter/test/widgets/route_notification_messages_test.dart
View file @
058a9343
...
...
@@ -63,46 +63,46 @@ void main() {
routes:
routes
,
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
.
last
,
isMethodCall
(
'routeUpdated'
,
expect
(
log
,
<
Object
>[
isMethodCall
(
'selectSingleEntryHistory'
,
arguments:
null
),
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
null
,
'
routeName'
:
'/'
,
'
location'
:
'/'
,
'
state'
:
null
,
},
),
);
]);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'/'
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
2
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
.
last
,
isMethodCall
(
'routeUpdated'
,
'route
Information
Updated'
,
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
'/
'
,
'
routeName'
:
'/A'
,
'
location'
:
'/A
'
,
'
state'
:
null
,
},
),
);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'A'
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
3
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
.
last
,
isMethodCall
(
'routeUpdated'
,
'route
Information
Updated'
,
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
'/A
'
,
'
routeName'
:
'/'
,
'
location'
:
'/
'
,
'
state'
:
null
,
},
),
);
...
...
@@ -168,46 +168,46 @@ void main() {
routes:
routes
,
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
.
last
,
isMethodCall
(
'routeUpdated'
,
expect
(
log
,
<
Object
>[
isMethodCall
(
'selectSingleEntryHistory'
,
arguments:
null
),
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
null
,
'
routeName'
:
'/'
,
'
location'
:
'/'
,
'
state'
:
null
,
},
),
);
]);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'/'
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
2
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
.
last
,
isMethodCall
(
'routeUpdated'
,
'route
Information
Updated'
,
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
'/
'
,
'
routeName'
:
'/A'
,
'
location'
:
'/A
'
,
'
state'
:
null
,
},
),
);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'A'
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
3
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
.
last
,
isMethodCall
(
'routeUpdated'
,
'route
Information
Updated'
,
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
'/A
'
,
'
routeName'
:
'/B'
,
'
location'
:
'/B
'
,
'
state'
:
null
,
},
),
);
...
...
@@ -237,27 +237,22 @@ void main() {
},
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
.
last
,
isMethodCall
(
'routeUpdated'
,
arguments:
<
String
,
dynamic
>{
'previousRouteName'
:
null
,
'routeName'
:
'/home'
,
}),
);
expect
(
log
,
<
Object
>[
isMethodCall
(
'selectSingleEntryHistory'
,
arguments:
null
),
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'location'
:
'/home'
,
'state'
:
null
,
},
),
]);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'Home'
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
2
));
expect
(
log
.
last
,
isMethodCall
(
'routeUpdated'
,
arguments:
<
String
,
dynamic
>{
'previousRouteName'
:
'/home'
,
'routeName'
:
null
,
}),
);
expect
(
log
,
isEmpty
);
});
testWidgets
(
'PlatformRouteInformationProvider reports URL'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -294,16 +289,13 @@ void main() {
await
tester
.
pump
();
expect
(
find
.
text
(
'update'
),
findsOneWidget
);
expect
(
log
,
hasLength
(
1
));
// TODO(chunhtai): check routeInformationUpdated instead once the engine
// side is done.
expect
(
log
.
last
,
expect
(
log
,
<
Object
>[
isMethodCall
(
'selectMultiEntryHistory'
,
arguments:
null
),
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'location'
:
'update'
,
'state'
:
'state'
,
}),
);
]
);
});
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment