Simplytics (Simple analytics)
Simple and lightweight Analytics and Crash Reporting abstraction.
Simplytics is a simple abstraction for analytics and crash reports that allows you to connect several different analytics and error monitoring services such as Firebase Analytics and Crashlytics, as well as simple logging of events to the system log.
Features
- Easily add a new analytics/error monitoring service or replace an already added one without any changes in the application, only changes in the
Simplytics
settings - Send reports on transitions between routes and events to several different analytics services at once
- Send crash and error reports to several error monitoring services at once
- Easily debug events and send them to the system log
- Easily connect new analytics and error monitoring services
- Easily connect Firebase Analytics and Crashlytics using simplytics_firebase package
Table of Contents
- Getting started
- Usage
- Debugging analytics events and error reporting
- Creating your own analytics and error monitoring service classes
- Analytics events with type safe parameters
Getting started
To start using Simplytics, you need to configure it, specify which classes of analytics and error monitoring services to use:
Simplytics.setup(
analyticsService: SimplyticsDebugAnalyticsService(),
crashlogService: SimplyticsDebugCrashlogService(),
);
Attention! These setup needs to be done before runApp()
:
void main() {
Simplytics.setup(
analyticsService: SimplyticsDebugAnalyticsService(),
crashlogService: SimplyticsDebugCrashlogService(),
);
runApp(const MyApp());
}
You can use more than one service for both analytics and error monitoring. To do this, you need to wrap them in groups:
Simplytics.setup(
analyticsService: SimplyticsAnalyticsServiceGroup([
SimplyticsDebugAnalyticsService(),
CustomAnalyticsService(),
]),
crashlogService: SimplyticsCrashlogServiceGroup([
SimplyticsDebugCrashlogService(),
CustomCrashReportingService(),
]),
);
For Firebase Analytics and Crashlytics, you can use pre-built service classes from the simplytics_firebase package:
Simplytics.setup(
analyticsService: SimplyticsFirebaseAnalyticsService(FirebaseAnalytics.instance),
crashlogService: SimplyticsFirebaseCrashlogService(FirebaseCrashlytics.instance),
);
If you wish to catch all Dart and Flutter errors and exceptions and send them to the error monitoring system, you can do this using runAppGuarded()
:
void main() {
runAppGuarded(
// Initializing Simplytics and creating an application class object
() async {
// Setup Simplytics
Simplytics.setup(
analyticsService: SimplyticsDebugAnalyticsService(),
crashlogService: SimplyticsDebugCrashlogService(),
);
// Create an application class object
return const MyApp();
},
// Sends fatal errors to Simplytics
onError: (error, stackTrace) => Simplytics.crashlog.recordFatalError,
);
}
The runAppGuarded()
function makes it easy to configure and catch all unhandled errors and exceptions.
It calls WidgetsFlutterBinding.ensureInitialized()
(can be disabled), configures all Dart and Flutter error handlers, and launches the application. All errors and exceptions will be passed to your handler in the onError
parameter.
Usage
Sending events
To send events to analytics services, you can use the logEvent
method of the Simplytics.analytics
object:
Simplytics.analytics.logEvent(name: 'button_tapped');
You can pass parameters to the event in the Map<String, Object>
:
Simplytics.analytics.logEvent(name: 'product_details', parameters: {'id': 1, 'name': 'Product 1'});
You can clear all analytics data on a device with resetAnalyticsData
:
Simplytics.analytics.resetAnalyticsData();
Track transitions between routes
To track navigation between routes, you can use the SimplyticsNavigatorObserver
observer in your application:
class MyApp extends StatelessWidget {
// Creating an instance of the Simplytics observer
static SimplyticsNavigatorObserver simplyticsObserver = SimplyticsNavigatorObserver();
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Simplytics Demo',
theme: ThemeData(
primarySwatch: Colors.teal,
),
home: const DemoPage(),
// Passing an instance of the Simplytics observer
navigatorObservers: <NavigatorObserver>[simplyticsObserver],
);
}
}
The observer will send events to the analytics service when the current active ModalRoute
changes.
You can configure the extraction of the route name from RouteSettings
using the nameExtractor
parameter, as well as filter transitions between which routes will be automatically sent to the analytics service using the routeFilter
parameter.
You can also manually dispatch route entry and exit events using the routeStart
and routeEnd
methods of the Simplytics.analytics
object:
Simplytics.analytics.routeStart('Login Screen');
...
Simplytics.analytics.routeEnd('Login Screen');
Sending errors to the error monitoring service
You can send error information to the error monitoring service using the recordError()
method of the Simplytics.crashlog
object:
Simplytics.crashlog.recordError('Entity not found.', StackTrace.current, reason: 'NotFoundException');
Set user identity and custom properties
You can store the user identity to the analytics and error monitoring services using the setUserId
method of the corresponding objects:
Simplytics.analytics.setUserId('user_1');
Simplytics.crashlog.setUserId('user_1');
You can also add custom properties and keys to the analytics and error monitoring services using the setUserProperty
and setCustomKey
methods:
// Setting a user property for an analytics service
Simplytics.analytics.setUserProperty(name: 'prop1', value: 'value1');
// Setting a custom key for the error monitoring service
Simplytics.crashlog.setCustomKey('test_key', 'test_value');
Debugging analytics events and error reporting
To debug events, you can use the SimplyticsDebugAnalyticsService
and SimplyticsDebugCrashlogService
service classes, which output analytics events and error reports to the system log in debug compilation mode (kDebugMode
):
Simplytics.setup(
analyticsService: SimplyticsAnalyticsServiceGroup([
// Sending events to system log in kDebugMode
SimplyticsDebugAnalyticsService(),
CustomAnalyticsService(),
]),
crashlogService: SimplyticsCrashlogServiceGroup([
// Sending events to system log in kDebugMode
SimplyticsDebugCrashlogService(),
CustomCrashReportingService(),
]),
);
This behavior can be configured using the constructor parameter of these classes:
// Always send events to system log
SimplyticsDebugAnalyticsService(true)
Creating your own analytics and error monitoring service classes
For your own or any other analytics and error monitoring services, you can create your own service classes and use them in Simplytics.setup()
.
Your own analytics service class
To create your own class for the analytics service, you need to extend the SimplyticsAnalyticsInterface
interface.
Here is an example implementation of an analytics service class for Firebase Analytics (but you can use a pre-built class from the simplytics_firebase package):
class CustomFirebaseAnalyticsService extends SimplyticsAnalyticsInterface {
final FirebaseAnalytics analytics;
CustomFirebaseAnalyticsService(this.analytics);
bool _enabled = true;
@override
Future<void> logEvent({required String name, Map<String, Object?>? parameters}) {
return analytics.logEvent(name: name, parameters: parameters);
}
@override
Future<void> resetAnalyticsData() {
return analytics.resetAnalyticsData();
}
@override
Future<void> routeStart({required String name, String? screenClassOverride}) {
return analytics.setCurrentScreen(screenName: name, screenClassOverride: screenClassOverride ?? 'Flutter');
}
@override
Future<void> routeEnd({required String name}) async {}
@override
Future<void> setUserId(String? id) {
return analytics.setUserId(id: id);
}
@override
Future<void> setUserProperty({required String name, required String? value}) {
return analytics.setUserProperty(name: name, value: value);
}
@override
bool get isEnabled => _enabled;
@override
Future<void> setEnabled(bool enabled) {
_enabled = enabled;
return analytics.setAnalyticsCollectionEnabled(enabled);
}
}
Your own error monitoring service class
To create your own class for the crash monitoring service, you need to extend the SimplyticsCrashlogInterface
interface.
Here is an example implementation of the Firebase Crashlytics error monitoring service class (but you can use the pre-built class from the simplytics_firebase package):
class CustomFirebaseCrashlogService extends SimplyticsCrashlogInterface {
final FirebaseCrashlytics crashlytics;
CustomFirebaseCrashlogService(this.crashlytics);
@override
Future<void> log(String message) {
return crashlytics.log(message);
}
@override
Future<void> recordError(exception, StackTrace? stackTrace, {reason, bool fatal = false}) {
return crashlytics.recordError(exception, stackTrace, reason: reason, fatal: fatal);
}
@override
Future<void> setCustomKey(String key, Object value) {
return crashlytics.setCustomKey(key, value);
}
@override
Future<void> setUserId(String identifier) {
return crashlytics.setUserIdentifier(identifier);
}
@override
bool get isEnabled => crashlytics.isCrashlyticsCollectionEnabled;
@override
Future<void> setEnabled(bool enabled) => crashlytics.setCrashlyticsCollectionEnabled(enabled);
}
Analytics events with type safe parameters
You can create your own event classes with type safe parameters and use them when dispatching events:
Simplytics.analytics.log(PostScoreEvent(score: 7));
To do this, extend the SimplyticsEvent
class and implement its getEventData
method:
class PostScoreEvent extends SimplyticsEvent {
final int score;
final int level;
final String? character;
PostScoreEvent({required this.score, this.level = 1, this.character});
@override
SimplyticsEventData getEventData(SimplyticsAnalyticsInterface service) => SimplyticsEventData(
name: 'post_score',
parameters: {
'score': score,
'level': level,
'character': character,
},
);
}
It is possible to send different events for different analytics services
with a different set of parameters by checking the type of the service
parameter:
class PostScoreEvent extends SimplyticsEvent {
final int score;
final int level;
final String? character;
PostScoreEvent({required this.score, this.level = 1, this.character});
@override
SimplyticsEventData getEventData(SimplyticsAnalyticsInterface service) {
if (service is SimplyticsFirebaseAnalyticsService) {
return SimplyticsEventData(
name: 'post_score',
parameters: {
'score': score,
'level': level,
'character': character,
},
);
} else {
return SimplyticsEventData(
name: 'game_score',
parameters: {
'scoreValue': score,
'gameLevel': level,
'characterName': character,
},
);
}
}
}
Libraries
- simplytics
- Simple and lightweight Analytics and Crash Reporting abstraction.