Представьте себе ситуацию: вы рассказали всем своим родным и близким о своем замечательном новом приложении. Возможно, вам даже посчастливилось сформировать список ожидания из заинтересованных пользователей. Вы сгораете от нетерпения нажать кнопку «Publish».
Но погодите минутку…
А как вы узнаете, что действительно работает, а что нуждается в улучшении?
Сколько пользователей завершили онбординг?
Сколько пользователей зарегистрировались и создали учетную запись?
Сколько пользователей достигли пейвола и сколько конвертировались?
Без аналитики вы действуете вслепую.
Вы принимаете решения о продукте, основываясь на предположениях, а не на данных. Это самый простой способ замедлить ваш рост, потратить впустую время разработки или, что еще хуже, потерять пользователей.
Важность аналитики
Аналитика предоставляет вам данные, необходимые для достижения успеха. Она помогает вам:
Измерять вовлеченность: Кто использует ваше приложение, как часто и как долго?
Понимать ретеншн: Где пользователи отваливаются и почему?
Отслеживать использование функций: Что популярно? Что игнорируется?
Оптимизировать прибыль: Отслеживание покупок, подписок и оттока.
Знать своих пользователей: Демография, устройства, платформы.
Контролировать пользовательский опыт: Составление карты пользовательского опыта и выявление проблемных областей.
Получив эту информацию вы перестанете гадать и начнете принимать обоснованные решения о продукте, которые действительно улучшат ваше приложение.

Чему вы научитесь
В этой статье я покажу вам, как эффективно отслеживать аналитику в вашем Flutter‑приложении — от базового логирования событий до масштабируемой архитектуры, которая будет работать с разными системами, такими как Firebase и Mixpanel.
Ключевые моменты, которые мы рассмотрим:
Что стоит отслеживать: Выбор ключевых событий и их значимость.
Как структурировать аналитику: Простые и масштабируемые архитектуры для отслеживания событий.
Настройка Firebase Analytics: Как настроить аналитику в реальном приложении.
Что ж, давайте приступим.
Эта статья познакомит вас с основами. Если вы хотите углубить свои знания, я рекомендую ознакомиться с курсом "Flutter Mobile Developer".
Введение в отслеживание событий
Если вы спросите пять разных разработчиков, как они внедрили аналитику, вы, вероятно, получите пять разных ответов.
Как это часто бывает в программной инженерии, не существует универсального решения — только компромиссы.
Поэтому, прежде чем мы углубимся в код, давайте немного отдалимся и ответим на несколько ключевых вопросов:
Какие события нам следует отслеживать?
Как мы должны их отслеживать?
Каким требованиям должно соответствовать наше решение?
Как только мы разберемся с этим, мы сможем выбрать подходящую архитектуру.
Какие события нам нужно отслеживать?
Говоря простым языком, события представляют собой взаимодействия между пользователем и вашим приложением.
Давайте рассмотрим в качестве примера мое приложение Flutter Ship:
Демо‑версия приложения Flutter Ship
Приложение поможет вам «поставить все галочки» перед выпуском приложений Flutter. По сути, это предварительно заполненный список дел.
Задача этого приложения заключается в том, чтобы помочь вам выполнить все необходимые шаги перед релизом ваших Flutter‑приложений. По сути, это просто готовый список задач: https://bizz84.github.io/flutter_ship_app_web/#apps [Откройте в отдельном окне]
Если бы вам нужно было добавить аналитику в это приложение, какие события вы бы отслеживали?
Важно сосредоточиться на событиях, которые:
Помогают пользователю добиться успеха (например, выполнить задачи)
Способствуют успеху вашего бизнеса (например, регистрация пользователей, ретеншн, монетизация)
Для этого приложения значимыми событиями являются:
Создание нового приложения
Внесение изменений в существующее приложение
Удаление приложения
Выполнение задачи
Остальные события не являются обязательными для отслеживания. Не стоит отслеживать все подряд только потому что вы можете это сделать.
Отслеживание событий с помощью Firebase Analytics и Mixpanel
Теперь давайте рассмотрим, как вы можете отслеживать различные события в своем Flutter‑приложении.
Если вы используете пакет firebase_analytics, вы можете реализовать это следующим образом:
final analytics = FirebaseAnalytics.instance; analytics.logEvent('app_created'); analytics.logEvent('app_updated'); analytics.logEvent('app_deleted'); analytics.logEvent('task_completed', parameters: {'count': count});
Или, если вы предпочитаете пакет mixpanel_flutter, то это может выглядеть так:
final mixpanel = await Mixpanel.init( Env.mixpanelProjectToken, trackAutomaticEvents: true, ); mixpanel.track('App Created'); mixpanel.track('App Updated'); mixpanel.track('App Deleted'); mixpanel.track('Task Completed', properties: {'count': count});
Проблема сразу же бросается в глаза: разные API — разный синтаксис.
❌ Разбрасывать эти вызовы по всей вашей кодовой базе — не лучшая идея. ❌
Давайте разберемся, почему:
Вы привязываете себя к определенным SDK
Вы повсюду дублируете названия событий (легко сделать опечатку, трудно рефакторить)
Вы теряете типобезопасность и поддержку IDE
Вы не можете повторно использовать логику или отправлять события сразу нескольким вендорам
Вы смешиваете бизнес‑логику с деталями реализации
Мы можем добиться гораздо большего, если определим четкий интерфейс, который отделит отслеживание событий от всего остального.
Но для этого нам потребуется сформировать список требований.
Аналитика приложения: Требования
Прежде чем приступить к реализации, давайте четко сформулируем требования к аналитической системе.
Ниже представлен ряд ключевых требований, которые нам необходимо учесть:
Разделение ответственности: Код приложения не должен напрямую взаимодействовать с SDK‑пакетами вендоров (например, Firebase или Mixpanel). Вместо этого все отслеживание событий будет происходить через простой и понятный интерфейс.
Поддержка нескольких клиентов: Нам необходимо иметь возможность отправлять события сразу нескольким вендорам. Например, мы можем захотеть реализовать логирование одновременно в Firebase и Mixpanel.
Отдельные режимы для отладочной и релизной сборки: Во время разработки в большинстве ситуаций мы хотим отражать события только в консоли. В релизной сборке же следует использовать реальных вендоров аналитики — без изменений логики приложения.
Другие важные вещи, о которых стоит задуматься:
Отслеживание переходов между экраннами
Переключение между активным и неактивным режимами (например, из соображений конфиденциальности / GDPR)
Идентификация пользователя (после входа в систему)
Несколько вариантов сборки (dev/staging/prod)
Но сейчас мы сосредоточимся на двух наиболее важных моментах:
Изоляция аналитики от логики приложения
Поддержка нескольких вендоров аналитики
Давайте рассмотрим две возможные архитектуры и разберем их компромиссы.
Простейшая архитектура аналитики
Этот сетап был разработан мной на основе предложения, которое я получил в X (Twitter):
import 'dart:developer'; import 'package:flutter/foundation.dart'; import 'package:mixpanel_flutter/mixpanel_flutter.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; class AnalyticsClient { const AnalyticsClient(this._analytics, this._mixpanel); final FirebaseAnalytics _analytics; final Mixpanel _mixpanel; Future<void> track( String name, { Map<String, dynamic> params = const {}, }) async { if (kReleaseMode) { await _analytics.logEvent(name: name, parameters: params); await _mixpanel.track(name, properties: params); } else { log('$name $params', name: 'Event'); } } }
Проще некуда. Это минималистичный общий интерфейс для отслеживания событий:
В релизной сборке он отправляет события и в Firebase, и в Mixpanel
В режиме отладки они просто выводятся в консоль.
Если вы используете Riverpod, отслеживание событий выглядит следующим образом:
final analytics = ref.read(analyticsClientProvider); analytics.track('app_created'); analytics.track('app_updated'); analytics.track('app_deleted'); analytics.track('task_completed', parameters: {'count': count});
Если названия ваших событий соответствуют рекомендациям Firebase Analytics (от 1 до 40 буквенно‑цифровых символов с нижними подчеркиваниями), то вам больше не о чем беспокоиться.
Этот подход на удивление гибок, учитывая, как мало кода он требует. Вы можете легко сменить вендоров аналитики, обновив всего лишь один класс, и при этом остальные части вашего приложения останутся нетронутыми.
Но у нее есть недостатки
Которые начинают проявляться по мере роста вашего приложения:
Отсутствие условного отслеживания: Вы не можете выборочно отправлять некоторые события в Mixpanel, но не в Firebase. Это может стать проблемой, если вам нужно следить за объемом отправляемых событий (и их стоимостью).
Повсюду сплошной хардкод: Имена событий в конечном итоге дублируются по всей кодовой базе. Легко опечатку. Сложно рефакторить. Большие грабли с точки зрения командной работы.
Нет единого источника истины: Нет централизованного списка событий или их ожидаемых параметров.
Нет автозаполнения: Вы теряете поддержку IDE. Если бы у вас был типобезопасный API, то вы могли бы наслаждаться автозаполнением:

Этот сетап может быть достаточно хорош для инди‑разработчиков или небольших приложений, где требуется полный контроль и минимум сложностей.
Однако, если вы работаете с более крупной кодовой базой или в составе команды, то стоит инвестировать во что‑то более серьезное. Давайте рассмотрим более масштабируемую альтернативу.
Архитектура аналитики посложнее
Если вам нужен типобезопасный API аналитики с автозаполнением и четким разделением ответственности, я рекомендую следующий подход.
Начнем с определения абстрактного интерфейса AnalyticsClient. Для приложения Flutter Ship это может выглядеть следующим образом:
abstract class AnalyticsClient { Future<void> trackAppCreated(); Future<void> trackAppUpdated(); Future<void> trackAppDeleted(); Future<void> trackTaskCompleted(int completedCount); }
Таким образом, все события будут определяться в одном месте, что позволит избежать дублирования и потенциальных ошибок.
Но как нам реализовать поддержку нескольких клиентов?
Вот один из способов структурировать это:

Как это работает:
Мы определяем все наши события в абстрактном интерфейсе
AnalyticsClient.Каждая конкретная реализация (например,
LoggerAnalyticsClient,FirebaseAnalyticsClientи т. д.) определяет, как регистрируются эти события.Класс
AnalyticsFacadeтакже реализует интерфейсAnalyticsClient, но его задача — просто отправлять события всем зарегистрированным клиентам.Наконец, приложение использует
analyticsFacadeProviderдля доступа к фасаду и вызова соответствующих методов отслеживания.
Теперь, чтобы отслеживать события из кода вашего приложения, достаточно просто добавить:
final analytics = ref.read(analyticsFacadeProvider); analytics.trackEditApp();
Поскольку каждое событие представлено отдельным методом, вы также получаете типобезопасность и автозаполнение:

Как нам реализовать эту архитектуру?
Пока это всего лишь высокоуровневая архитектура. Чтобы заставить ее работать, нам нужно ответить на три важных вопроса:
Как нам зарегистрировать нескольких клиентов в
AnalyticsFacade?Как отправлять события каждому клиенту?
Как выглядят конкретные подклассы
AnalyticsClient?
Далее давайте рассмотрим детали реализации.
Аналитика приложения: детали реализации
Чтобы реализовать архитектуру, о которой мы говорили ранее, нам потребуется несколько ключевых компонентов:
Интерфейс
AnalyticsClient, который определяет все события, которые мы хотим отслеживать.AnalyticsFacade, который реализуетAnalyticsClientи делегирует вызовы нескольким клиентам.LoggerAnalyticsClientдля локальной разработки — отправляет события в консоль.Дополнительные клиенты, такие как
FirebaseAnalyticsClient,MixpanelAnalyticsClientи т. д., которые используют SDK от соответствующего вендора.
Для организации всего этого кода я рекомендую разместить его в отдельной папке monitoring:
‣ lib ‣ src ‣ monitoring ‣ analytics_client.dart ‣ analytics_facade.dart ‣ logger_analytics_client.dart ‣ firebase_analytics_client.dart
Вот как работает каждая часть:
1. Интерфейс AnalyticsClient
Это контракт, который описывает все события, поддерживаемые вашим приложением.
abstract class AnalyticsClient { // Custom events for the Flutter Ship app. // TODO: Replace with your own events. Future<void> trackNewAppOnboarding(); Future<void> trackNewAppHome(); Future<void> trackAppCreated(); Future<void> trackAppUpdated(); Future<void> trackAppDeleted(); Future<void> trackTaskCompleted(int completedCount); }
Поскольку этот класс является абстрактным, все методы представляют собой только объявления, без реализации.
2. Класс LoggerAnalyticsClient
Тут все просто: этот класс просто отправляет события в консоль. Он полезен для локальной разработки и тестов, прежде чем мы подключим реальный серверный модуль аналитики.
import 'dart:async'; import 'dart:developer'; import 'package:flutter_ship_app/src/monitoring/analytics_client.dart'; class LoggerAnalyticsClient implements AnalyticsClient { const LoggerAnalyticsClient(); static const _name = 'Event'; @override Future<void> trackNewAppHome() async { log('trackNewAppHome', name: _name); } @override Future<void> trackNewAppOnboarding() async { log('trackNewAppOnboarding', name: _name); } @override Future<void> trackAppCreated() async { log('trackAppCreated', name: _name); } @override Future<void> trackAppUpdated() async { log('trackAppUpdated', name: _name); } @override Future<void> trackAppDeleted() async { log('trackAppDeleted', name: _name); } @override Future<void> trackTaskCompleted(int completedCount) async { log('trackTaskCompleted(completedCount: $completedCount)', name: _name); } }
Мы добавим FirebaseAnalyticsClient позже. Сейчас сосредоточьтесь на том, что вы хотите отслеживать, а не на том, как это будет отправляться.
Существует ли лучший способ определения событий?
Наш текущий подход работает, но он не очень удобен, так как требует много копипаста для добавления новых событий:
// copy-paste when creating new events @override Future<void> trackAppCreated() async { log('trackAppCreated', name: _name); }
Следует упомянуть несколько альтернативных вариантов:
Перечисления: Определить перечисление (enum)
AppEvent, в котором в виде значений будут перечислены все возможные виды событий. Этот вариант не подойдет, если разным событиям нужны разные аргументы.Sealed классы: Использовать базовый sealed класс
AppEventи создавать подкласс каждый раз, когда нам нужно добавить новое событие. Это более гибкий подход, но требует больше кода.Union‑типы freezed: Лаконичный синтаксис и паттернматчинг, но требуется кодогенерации.
Каждый из этих вариантов имеет свои преимущества и недостатки. На данный момент мы будем придерживаться нашего первоначального подхода.
3. Класс AnalyticsFacade
AnalyticsFacade реализует интерфейс AnalyticsClient. Этот класс отвечает за пересылку вызовов методов всем зарегистрированным клиентам.
import 'package:flutter/foundation.dart'; import 'package:flutter_ship_app/src/monitoring/analytics_client.dart'; import 'package:flutter_ship_app/src/monitoring/logger_analytics_client.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'analytics_facade.g.dart'; // https://refactoring.guru/design-patterns/facade class AnalyticsFacade implements AnalyticsClient { const AnalyticsFacade(this.clients); final List<AnalyticsClient> clients; @override Future<void> trackAppOpened() => _dispatch( (c) => c.trackAppOpened(), ); @override Future<void> trackNewAppHome() => _dispatch( (c) => c.trackNewAppHome(), ); @override Future<void> trackNewAppOnboarding() => _dispatch( (c) => c.trackNewAppOnboarding(), ); @override Future<void> trackAppCreated() => _dispatch( (c) => c.trackAppCreated(), ); @override Future<void> trackAppUpdated() => _dispatch( (c) => c.trackAppUpdated(), ); @override Future<void> trackAppDeleted() => _dispatch( (c) => c.trackAppDeleted(), ); @override Future<void> trackTaskCompleted(int completedCount) => _dispatch( (c) => c.trackTaskCompleted(completedCount), ); Future<void> _dispatch( Future<void> Function(AnalyticsClient client) work, ) async { for (final client in clients) { await work(client); } } }
Метод _dispatch уменьшает дублирование кода и транслирует каждое событие всем зарегистрированным клиентам.
Настройка провайдера
Вот как можно отобразить AnalyticsFacade с помощью Riverpod:
@Riverpod(keepAlive: true) AnalyticsFacade analyticsFacade(Ref ref) { return const AnalyticsFacade([ if (!kReleaseMode) LoggerAnalyticsClient(), ]); }
В отладочных сборках у нас будет логирование в консоль. В релизных сборках мы можем добавлять реальных клиентов, таких как FirebaseAnalyticsClient (подробнее об этом позже).
Этот сетап предоставляет нам понятный, модульный и масштабируемый способ отслеживания событий аналитики — без привязки логики нашего приложения к какому‑либо SDK конкретного вендора.
Какая архитектура лучше?
Архитектура, которую мы только что создали, дает нам:
Типобезопасный API отслеживания событий
Автозаполнение и поддержка IDE
Четкое разделение обязанностей
Поддержка нескольких серверов аналитики
Вот визуальное представление:

Она гибкая, масштабируемая и готовая к работе в продакшене.
Однако за эту гибкость и масштабируемость приходится платить.
Каждый раз, когда вы добавляете новое событие, вам необходимо:
Добавить новый метод в интерфейс
AnalyticsClientРеализовать его в
AnalyticsFacadeРеализовать его для каждого конкретного клиента (например, Logger, Firebase, Mixpanel)
Когда может быть достаточно простого подхода
Для небольших приложений или MVP может быть достаточно более простого подхода:
import 'dart:developer'; import 'package:flutter/foundation.dart'; import 'package:mixpanel_flutter/mixpanel_flutter.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; class AnalyticsClient { const AnalyticsClient(this._analytics, this._mixpanel); final FirebaseAnalytics _analytics; final Mixpanel _mixpanel; Future<void> track( String name, { Map<String, dynamic> params = const {}, }) async { if (kReleaseMode) { await _analytics.logEvent(name: name, parameters: params); await _mixpanel.track(name, properties: params); } else { log('$name $params', name: 'Event'); } } }
Такой подход позволяет быстро реализовать аналитику, но при этом вы теряете важные преимущества:
Автозаполнение
Типобезопасность
Централизованные определения событий
Контроль и фильтрация на уровне вендора

В итоге: Если вы разрабатываете что‑то более серьезное, чем просто одноразовый прототип, то стоит обратить внимание на более структурированную архитектуру. Хотя она может показаться более сложной в реализации, она окупится лучшей поддерживаемостью, удобством в тестировании и общим опытом разработки.
Давайте теперь посмотрим, как можно использовать analyticsFacadeProvider для отслеживания событий в реальном коде приложения.
Отслеживание пользовательских Событий
Мы определили интерфейс следующим образом:
abstract class AnalyticsClient { Future<void> trackNewAppOnboarding(); Future<void> trackNewAppHome(); Future<void> trackAppCreated(); Future<void> trackAppUpdated(); Future<void> trackAppDeleted(); Future<void> trackTaskCompleted(int completedCount); }
Однако, если мы не будем вызывать эти методы, то ничего не будет происходить.
Итак, где нам следует разместить эти вызовы?
В виджетах?
В контроллерах?
Где‑нибудь в другом месте?
Давайте рассмотрим оба варианта.
Отслеживание событий в виджетах и контроллерах
Вот простой пример — кнопка + на главной странице:

Код отслеживания событий выглядит следующим образом:
IconButton( onPressed: () { // event tracking code unawaited(ref.read(analyticsFacadeProvider).trackNewAppHome()); // navigation code Navigator.of(context).pushNamed(AppRoutes.createApp); }, icon: Icon(Icons.add), )
В этом случае вызов аналитики помещается непосредственно в коллбек onPressed.
💡 Функция unawaited используется здесь для отправки события без блокирования выполнения. Это fire‑and‑forget вызовы — вам не нужно ждать их завершения. Подробнее об этом можно почитать здесь: Используйте unawaited для своих вызовов аналитики .
Однако, если ваша логика более сложная, рекомендуется перенести вызовы аналитики в контроллер.
Вот пример пользовательского класса контроллера:
/// This class holds the business logic for creating, editing, and deleting apps /// using the underlying AppDatabase class for data persistence. /// More info here: https://codewithandrea.com/articles/flutter-presentation-layer/ @riverpod class CreateEditAppController extends _$CreateEditAppController { @override void build() { // no-op } Future<void> createOrEditApp(App? existingApp, String newName) async { final db = ref.read(appDatabaseProvider); // * Update the DB if (existingApp != null) { await db.editAppName(appId: existingApp.id, newName: newName); } else { await db.createNewApp(name: newName); } // * Analytics code if (existingApp != null) { unawaited(ref.read(analyticsFacadeProvider).trackAppUpdated()); } else { unawaited(ref.read(analyticsFacadeProvider).trackAppCreated()); } } Future<void> deleteAppById(int appId) async { await ref.read(appDatabaseProvider).deleteAppById(appId); ref.read(analyticsFacadeProvider).trackAppDeleted(); } }
Этот контроллер отвечает за все изменения и взаимодействия с базой данных, что делает его идеальным местом для отслеживания связанных событий аналитики.
Рекомендации по отслеживанию событий
❌ Никогда не добавляйте отслеживание событий в
build(). Эта функция может вызываться десятки раз в секунду во время анимаций. То же самое касаетсяinitState()и других методов жизненного цикла.✅ Добавляйте отслеживание в колбеки виджетов типа
onPressed. Если логика сложная, перенесите ее в контроллер или служебный класс.✅ Идеальным вариантом для отслеживания событий являются контроллеры. В них нет логики пользовательского интерфейса, их проще тестировать, и в них уже заложена логика, которая инициирует события.
❌ Не отслеживайте события на уровне данных или сетей. События должны отслеживаться в источнике (уровень пользовательского интерфейса) для большей точности.
✅ Используйте
unawaited()для всех вызовов аналитики. Это позволит вам не блокировать пользовательский интерфейс и не заботиться о результатах — просто запустите и забудьте.
Интеграция Firebase
До сих пор мы использовали LoggerAnalyticsClient для вывода событий в консоль.
Однако для производственных приложений вам потребуется интеграция с реальной серверной аналитикой, такой как Firebase Analytics, Mixpanel или PostHog.
Благодаря нашему AnalyticsFacade мы можем легко справиться с этой задачей, не меняя код нашего приложения. Мы просто добавим новый клиент, зарегистрируем его, и все готово. В этом и заключается сила разделения ответственности.
Давайте рассмотрим процесс интеграции Firebase Analytics.
Добавление Firebase в наше Flutter-приложение
Официальное руководство очень хорошо объясняет процесс добавления Firebase в наше Flutter‑приложение.
Если ваше приложение поддерживает несколько вариантов сборок (например, dev, staging, prod), настройка может потребовать от вас дополнительных шагов. Я уже рассказывал об этом в другой статье:
Создание класса FirebaseAnalyticsClient
Это достаточно простая реализация интерфейса AnalyticsClient с использованием Firebase SDK:
import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:flutter_ship_app/src/monitoring/analytics_client.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'firebase_analytics_client.g.dart'; class FirebaseAnalyticsClient implements AnalyticsClient { const FirebaseAnalyticsClient(this._analytics); final FirebaseAnalytics _analytics; @override Future<void> trackNewAppHome() async { await _analytics.logEvent(name: 'new_app_home'); } @override Future<void> trackNewAppOnboarding() async { await _analytics.logEvent(name: 'new_app_onboarding'); } @override Future<void> trackAppCreated() async { await _analytics.logEvent(name: 'app_created'); } @override Future<void> trackAppUpdated() async { await _analytics.logEvent(name: 'app_updated'); } @override Future<void> trackAppDeleted() async { await _analytics.logEvent(name: 'app_deleted'); } @override Future<void> trackTaskCompleted(int completedCount) async { await _analytics.logEvent( name: 'task_completed', parameters: {'count': completedCount}, ); } } @Riverpod(keepAlive: true) FirebaseAnalyticsClient firebaseAnalyticsClient(Ref ref) { return FirebaseAnalyticsClient(FirebaseAnalytics.instance); }
Регистрация клиента в фасаде
Чтобы добавить клиент Firebase, обновите свой analyticsFacadeProvider следующим образом:
@Riverpod(keepAlive: true) AnalyticsFacade analyticsFacade(Ref ref) { final firebaseAnalyticsClient = ref.watch(firebaseAnalyticsClientProvider); return AnalyticsFacade([ firebaseAnalyticsClient, if (!kReleaseMode) const LoggerAnalyticsClient(), ]); }
И вот так, без каких‑либо изменений в остальной части вашего приложения, ваши события теперь отправляются в Firebase Analytics.
Вы можете увидеть, как они отображаются в консоли Firebase:

Вот как это выглядит в моем приложении Flutter Tips:

Аналитика Flutter-приложений: Заключение
В этой статье мы обсудили все, что необходимо знать для реализации базовой аналитики производственного уровня в вашем Flutter‑приложении:
Почему аналитика необходима для уверенных релизов и роста
Как продумать и правильно выбрать события для отслеживания
Простая архитектура для быстрой реализации аналитики
Масштабируемая типобезопасная архитектура для более крупных приложений и команд
Как отслеживать события из виджетов и контроллеров
Как интегрировать Firebase Analytics, не влияя на остальную логику приложения
Однако это лишь первый шаг к реализации аналитики в реальных приложениях.
Прежде чем публиковать ваше приложение, стоит учесть несколько важных моментов:
Отслеживание экранного вида: Используйте навигационный наблюдатель, чтобы автоматически фиксировать переходы между экранами.
Аналитика в разных режимах: Позвольте пользователям отключать отслеживание, если это необходимо (например, для соблюдения GDPR).
Идентификация пользователя: Привязывайте события к зарегистрированным пользователям, чтобы отслеживать их на разных устройствах и анализировать воронку конверсии.
Интеграция с Mixpanel или PostHog: Firebase является бесплатным решением, но такие инструменты, как Mixpanel, предлагают мощную фильтрацию и отчетность и гораздо более удобны для обеспечения конфиденциальности.
Хотите узнать, как встроить аналитику в Flutter‑приложение так, чтобы каждый экран и клик превращались в ценные продуктовые инсайты? Тогда приглашаем всех желающих на бесплатный открытый урок, который пройдет 20 мая в 20:00.
Немного практики в тему — попробуйте пройти вступительный тест по Flutter и получите обратную связь по своим знаниям.
