How to set Firebase Analytics custom events in Flutter without passing 'analytics/observer' object in each screen

You can use the provider package to 'provide' both your analytics and observer down your widget tree.

class MyApp extends StatelessWidget {
  static FirebaseAnalytics analytics = FirebaseAnalytics();
  static FirebaseAnalyticsObserver observer =
      FirebaseAnalyticsObserver(analytics: analytics);

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
            Provider<FirebaseAnalytics>.value(value: analytics),
            Provider<FirebaseAnalyticsObserver>.value(value: observer),
        ],
        child: MaterialApp(
            title: 'Firebase Analytics Demo',
            theme: ThemeData(
                primarySwatch: Colors.blue,
            ),
            navigatorObservers: <NavigatorObserver>[observer],
            home: MyHomePage(
                title: 'Firebase Analytics Demo',
            ),
        ),
    ); 
  }
}

Then in any of your child widgets...

Future<void> _sendAnalyticsEvent() async {
    FirebaseAnalytics analytics = Provider.of<FirebaseAnalytics>(context);
    await analytics.logEvent(
      name: 'test_event',
      parameters: <String, dynamic>{
        'string': 'string',
        'int': 42,
        'long': 12345678910,
        'double': 42.0,
        'bool': true,
      },
    );
    setMessage('logEvent succeeded');
  }

Now you don't need to pass your Firebase instances to the widget constructors.


It is also possible to create a file with all of your global instances. e.g: file: globals.dart in your lib directory.

Content of the file:

class Global {
    static final FirebaseAnalytics analytics = FirebaseAnalytics();
}

Then to use it:

Global.analytics.logEvent(...)

Besides using provider or a global class with static parameters, another option is to use services with the GetIt package.

Just create a class that hold's the analytics and observer. E.g. like this:

class AnalyticsService {
  final FirebaseAnalytics _analytics = FirebaseAnalytics();

  FirebaseAnalyticsObserver getAnalyticsObserver() => FirebaseAnalyticsObserver(analytics: _analytics);

  Future logScreens({@required String name}) async {
    await _analytics.setCurrentScreen(screenName: name);
  }

  ... // implement the events you want to track
}

Now create a locator and register the class as a lazy singleton:

GetIt locator = GetIt.instance;

setupServiceLocator() {
  locator.registerLazySingleton<AnalyticsService>(() => AnalyticsService());
}

Make the locator accessable:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  setupServiceLocator();
  runApp(MyApp());
}

Now you can access the service from everywhere in your app by calling the locator. For example:

return MaterialApp(
  debugShowCheckedModeBanner: false,
  title: 'Demo',
  theme: themeData,
  initialRoute: SplashScreen.id,
  routes: routes,
  navigatorObservers: [
    // Access the observer
    locator<AnalyticsService>().getAnalyticsObserver(),
  ],
);

}

or

 onTap: () {
   locator<AnalyticsService>().logScreens(name: DetailsScreen.id);
 }