Solución:
Este caso de uso exacto se encuentra en la documentación de Firebase Analytics en la sección Seguimiento de vistas de pantalla.
El seguimiento manual de las pantallas es útil si su aplicación no utiliza un UIViewController o Activity por separado para cada pantalla que desee seguir, como en un juego.
Este es exactamente el caso de Flutter, ya que Flutter se encarga de las actualizaciones de la pantalla: la mayoría de las aplicaciones sencillas de Flutter ejecutan una sola FlutterActivity
/FlutterAppDelegate
y se encarga de renderizar diferentes pantallas por sí solo, por lo que permitir que Firebase Analytics rastree automáticamente las pantallas no producirá el efecto deseado.
En lo que respecta a mi experiencia pasada, la FirebaseAnalyticsObserver
no fue muy útil, sin embargo, te recomiendo que revises sus documentos nuevamente, ellos implican que las cosas deberían “simplemente funcionar”. Mi mejor suposición es que no funcionó bien para mí porque no usé RouteSettings
en cualquiera de mis rutas *
.
En caso FirebaseAnalyticsObserver
no funcionará ni solicitará su aplicación, el siguiente enfoque funcionó bastante bien para mí durante los últimos meses de desarrollo.
Puede configurar la pantalla actual con FirebaseAnalytics
en cualquier momento, si llama al setCurrentScreen
método con el nombre de pantalla:
import 'package:firebase_analytics/firebase_analytics.dart';
// Somewhere in your widgets...
FirebaseAnalytics().setCurrentScreen(screenName: 'Example1');
Como primer intento, hice esto en el constructor de widgets, pero eso no funcionará bien y contará mal los eventos: si abre o empuja rutas, se llamarán a todos los constructores de widgets en la pila, aunque solo la ruta superior realmente califica como ” la pantalla actual “.
Para resolver esto, necesitamos usar el RouteAware
class y solo establezca la pantalla actual en caso de que sea la ruta principal: nuestra ruta se agrega a la pila o la ruta principal anterior se abrió y llegamos a la ruta.
RouteAware
viene con un código estándar y no queremos repetirlo en todas nuestras pantallas. Incluso para aplicaciones pequeñas, tienes decenas de pantallas diferentes, así que creé el RouteAwareAnalytics
mezclando:
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/widgets.dart';
// A Navigator observer that notifies RouteAwares of changes to state of their Route
final routeObserver = RouteObserver<PageRoute>();
mixin RouteAwareAnalytics<T extends StatefulWidget> on State<T>
implements RouteAware {
AnalyticsRoute get route;
@override
void didChangeDependencies() {
routeObserver.subscribe(this, ModalRoute.of(context));
super.didChangeDependencies();
}
@override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
@override
void didPop() {}
@override
void didPopNext() {
// Called when the top route has been popped off,
// and the current route shows up.
_setCurrentScreen(route);
}
@override
void didPush() {
// Called when the current route has been pushed.
_setCurrentScreen(route);
}
@override
void didPushNext() {}
Future<void> _setCurrentScreen(AnalyticsRoute analyticsRoute) {
print('Setting current screen to $analyticsRoute');
return FirebaseAnalytics().setCurrentScreen(
screenName: screenName(analyticsRoute),
screenClassOverride: screenClass(analyticsRoute),
);
}
}
Creé un enum
para rastrear las pantallas (y funciones para convertir la enumeración en nombres de pantalla). Usé las enumeraciones para poder rastrear fácilmente todas las rutas, refactorizar los nombres de las rutas. Al usar estas enumeraciones y funciones, puedo probar todos los valores posibles y aplicar nombres consistentes: sin espacios accidentales o caracteres especiales, sin mayúsculas inconsistentes. Podría haber otras formas mejores de determinar los valores de clase de pantalla, pero seguí este enfoque.
enum AnalyticsRoute { example }
String screenClass(AnalyticsRoute route) {
switch (route) {
case AnalyticsRoute.example:
return 'ExampleRoute';
}
throw ArgumentError.notNull('route');
}
String screenName(AnalyticsRoute route) {
switch (route) {
case AnalyticsRoute.example:
return '/example';
}
throw ArgumentError.notNull('route');
}
El siguiente paso en la configuración inicial es registrar el routeObserver
como un navigatorObserver
de tu MaterialApp
:
MaterialApp(
// ...
navigatorObservers: [
routeObserver,
// FirebaseAnalyticsObserver(analytics: FirebaseAnalytics()),
],
);
Finalmente, podemos agregar nuestra primera ruta de ejemplo que se rastrea. Añade el with RouteAwareAnalytics
a sus estados y anular get route
.
class ExampleRoute extends StatefulWidget {
@override
_ExampleRouteState createState() => _ExampleRouteState();
}
class _ExampleRouteState extends State<ExampleRoute> with RouteAwareAnalytics{
@override
Widget build(BuildContext context) => Text('Example');
@override
AnalyticsRoute get route => AnalyticsRoute.example;
}
Cada vez que agrega una nueva ruta, puede hacerlo con poco esfuerzo.: primero, agregue un nuevo valor de enumeración, luego el compilador de Dart lo guiará sobre qué agregar a continuación: agregue el nombre de pantalla y los valores de anulación de clase en sus respectivos switch-case
. Luego, busque el estado que está construyendo su ruta, agregue with RouteAwareAnalytics
y agregue el route
adquiridor.
*
La razón por la que no usé RouteSettings
es que prefiero el enfoque de Simon Lightfoot con los argumentos escritos en lugar de los Object
argumentos que proporciona la configuración:
class ExampleRoute extends StatefulWidget {
const ExampleRoute._({@required this.integer, Key key}) : super(key: key);
// All types of members are supported, but I used int as example
final int integer;
static Route<void> route({@required int integer}) =>
MaterialPageRoute(
// I could add the settings here, though, it wouldn't enforce good types
builder: (_) => ExampleRoute._(integer: integer),
);
// ...
}
Puedes agregar un observador de navegación analítica de Firebase:
Para usarlo, agréguelo al navigatorObservers de su Navigator, por ejemplo, si está usando una MaterialApp:
class MyApp extends StatelessWidget {
FirebaseAnalytics analytics = FirebaseAnalytics();
...
MaterialApp(
home: MyAppHome(),
navigatorObservers: [
FirebaseAnalyticsObserver(analytics: analytics),
],
);
¡NOTA!
Si ha integrado sus análisis con su aplicación por primera vez, tenga en cuenta que los análisis tardarán aproximadamente un día en aparecer en su panel de control.
Para ver primero, de inmediato, los resultados de la depuración, puede ejecutar el comando anterior en su terminal y ver sus análisis en firebase analytic debugView (como se ve en la imagen de la parte superior):
adb shell setprop debug.firebase.analytics.app [your_app_package_name]
¡Disfrutar!