Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(analytics): reinstate Analytics screen navigation observer. (#7529)
- Loading branch information
1 parent
c657ade
commit caf2986
Showing
4 changed files
with
128 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
packages/firebase_analytics/firebase_analytics/lib/src/observer.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Copyright 2021 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
part of firebase_analytics; | ||
|
||
/// Signature for a function that extracts a screen name from [RouteSettings]. | ||
/// | ||
/// Usually, the route name is not a plain string, and it may contains some | ||
/// unique ids that makes it difficult to aggregate over them in Firebase | ||
/// Analytics. | ||
typedef ScreenNameExtractor = String? Function(RouteSettings settings); | ||
|
||
String? defaultNameExtractor(RouteSettings settings) => settings.name; | ||
|
||
/// A [NavigatorObserver] that sends events to Firebase Analytics when the | ||
/// currently active [PageRoute] changes. | ||
/// | ||
/// When a route is pushed or popped, [nameExtractor] is used to extract a name | ||
/// from [RouteSettings] of the now active route and that name is sent to | ||
/// Firebase. | ||
/// | ||
/// The following operations will result in sending a screen view event: | ||
/// ```dart | ||
/// Navigator.pushNamed(context, '/contact/123'); | ||
/// | ||
/// Navigator.push<void>(context, MaterialPageRoute( | ||
/// settings: RouteSettings(name: '/contact/123'), | ||
/// builder: (_) => ContactDetail(123))); | ||
/// | ||
/// Navigator.pushReplacement<void>(context, MaterialPageRoute( | ||
/// settings: RouteSettings(name: '/contact/123'), | ||
/// builder: (_) => ContactDetail(123))); | ||
/// | ||
/// Navigator.pop(context); | ||
/// ``` | ||
/// | ||
/// To use it, add it to the `navigatorObservers` of your [Navigator], e.g. if | ||
/// you're using a [MaterialApp]: | ||
/// ```dart | ||
/// MaterialApp( | ||
/// home: MyAppHome(), | ||
/// navigatorObservers: [ | ||
/// FirebaseAnalyticsObserver(analytics: service.analytics), | ||
/// ], | ||
/// ); | ||
/// ``` | ||
/// | ||
/// You can also track screen views within your [PageRoute] by implementing | ||
/// [PageRouteAware] and subscribing it to [FirebaseAnalyticsObserver]. See the | ||
/// [PageRouteObserver] docs for an example. | ||
class FirebaseAnalyticsObserver extends RouteObserver<PageRoute<dynamic>> { | ||
/// Creates a [NavigatorObserver] that sends events to [FirebaseAnalytics]. | ||
/// | ||
/// When a route is pushed or popped, [nameExtractor] is used to extract a | ||
/// name from [RouteSettings] of the now active route and that name is sent to | ||
/// Firebase. Defaults to `defaultNameExtractor`. | ||
/// | ||
/// If a [PlatformException] is thrown while the observer attempts to send the | ||
/// active route to [analytics], `onError` will be called with the | ||
/// exception. If `onError` is omitted, the exception will be printed using | ||
/// `debugPrint()`. | ||
FirebaseAnalyticsObserver({ | ||
required this.analytics, | ||
this.nameExtractor = defaultNameExtractor, | ||
Function(PlatformException error)? onError, | ||
}) : _onError = onError; | ||
|
||
final FirebaseAnalytics analytics; | ||
final ScreenNameExtractor nameExtractor; | ||
final void Function(PlatformException error)? _onError; | ||
|
||
void _sendScreenView(PageRoute<dynamic> route) { | ||
final String? screenName = nameExtractor(route.settings); | ||
if (screenName != null) { | ||
analytics.setCurrentScreen(screenName: screenName).catchError( | ||
(Object error) { | ||
final _onError = this._onError; | ||
if (_onError == null) { | ||
debugPrint('$FirebaseAnalyticsObserver: $error'); | ||
} else { | ||
_onError(error as PlatformException); | ||
} | ||
}, | ||
test: (Object error) => error is PlatformException, | ||
); | ||
} | ||
} | ||
|
||
@override | ||
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) { | ||
super.didPush(route, previousRoute); | ||
if (route is PageRoute) { | ||
_sendScreenView(route); | ||
} | ||
} | ||
|
||
@override | ||
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) { | ||
super.didReplace(newRoute: newRoute, oldRoute: oldRoute); | ||
if (newRoute is PageRoute) { | ||
_sendScreenView(newRoute); | ||
} | ||
} | ||
|
||
@override | ||
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) { | ||
super.didPop(route, previousRoute); | ||
if (previousRoute is PageRoute && route is PageRoute) { | ||
_sendScreenView(previousRoute); | ||
} | ||
} | ||
} |