🧑‍💻

Google Analytics for Firebase Flutter

2023/04/15に公開

どんなことができるのか?

FlutterとFirebaseを使用して、GoogleAnalyticsを使用することができるそうなのですが、使ったことがなかったので、キャッチアップしたいことから、やってみました。

こちらが公式ページ
https://firebase.google.com/docs/analytics?hl=ja

わかりやすく説明すると、ボタンを押すイベントが起きたら、ユーザーがアプリを使用している情報を収集することができたり、すごい機能だと、購入ボタンを押すと、ユーザーが例えばですけど、北欧製のオシャレな椅子を4個購入している情報を収集できます。
ECアプリは作ったことないので、イメージはできませんが、何らかのイベントが発生したらアプリから情報を収集してくれる機能だと解釈すれば良いかなと思います。

早速使ってみた

それでは、いつも通りにFlutterとFirebaseのプロジェクトを作成して、設定をしていきましょう。デモアプリは、Riverpod2.0を使用して状態管理をしています。

こちらのパッケージを追加してください
https://pub.dev/packages/firebase_core
https://pub.dev/packages/firebase_core
https://pub.dev/packages/firebase_analytics


FlutterでGoogleAnalyticsを使用するためのロジックを作ります。analytics_provider.dartを作成して、以下のコードを記述してください。

analytics_provider.dart
// Package imports:
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'analytics.g.dart';

// firebase_analytics provider

FirebaseAnalytics firebaseAnalytics(FirebaseAnalyticsRef ref) {
  return FirebaseAnalytics.instance;
}

// GoogleAnalyticsを使用するためのサービスクラス
class AnalyticsService {
  // ボタンイベント
  Future<void> eventPush() async {
    await analytics.logEvent(
      name: '押したよ!',
      parameters: <String, dynamic>{
        'button_name': 'example_button',
      },
    );
  }

  // 好きな食べ物の情報を収集する
  Future<void> foodEvent() async {
    const favoriteFood = 'Apple';
    await FirebaseAnalytics.instance.setUserProperty(
      name: 'favorite_food',
      value: favoriteFood,
    );
  }
}

次にアプリを実行するコードを書きます。main.dartのコードを以下のコードに修正してください。
ボタンを押すと、イベントが発生してGoogleAnalyticsで、ユーザーがアプリを使用しているか確認をすることができます。
イベントが起きたのを検知して、結果が表示されるまで、時間がかかるので、Firebaseのコンソールで確認するときは、長く待たないと確認できないようです。

main.dart
// ignore_for_file: unused_local_variable

import 'package:anlytics_tutorial/analytics_provider.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  runApp(ProviderScope(child: MyApp()));
}

// FirebaseAnalytics の instance ゲッターを呼び出して、
//Firebase 向け Google アナリティクスの新しいインスタンスを作成します。
final FirebaseAnalytics analytics = FirebaseAnalytics.instance;

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      // FirebaseAnalyticsObserverは、Navigatorのイベントを監視し、
      //Firebase Analyticsに画面遷移を報告します。
      // 今回は、画面遷移をしないので、必要ないかなと思います。
      navigatorObservers: [
        FirebaseAnalyticsObserver(analytics: analytics),
      ],
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends ConsumerWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    final analyticsService = ref.read(analyticsServiceProvider);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Google Analytics'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // ボタンを押すとイベントを検知して、GoogleAnalyticsに
            // ユーザーがアプリを使用していることが通知される
            ElevatedButton(
              child: const Text('ボタンを押してね'),
              onPressed: () async {
                analyticsService.eventPush();
              },
            ),
            const SizedBox(height: 20.0),
            ElevatedButton(
              child: const Text('好きなたべもの'),
              onPressed: () async {
                analyticsService.foodEvent();
              },
            ),
          ],
        ),
      ),
    );
  }
}

こちらが表示された結果です

画面左のメニューの分析のところから印をつけているところ、Realtime Analyticsを選択してください。そこから、どこに住んでいるユーザーが、何人ぐらいアプリを使用しているか確認することができます。

最後に

いかがでしたでしょうか皆様。これで多分、GoogleAnalyticsの導入の仕方と使い方を理解することができるようになったと思います。

今回学習の参考になった動画
https://www.youtube.com/watch?v=BWTQkkLC-Mo

GoRouterの場合は設定が違う?

go_routerを使っているとどうやら設定方法が違うようです???

https://github.com/firebase/flutterfire/discussions/8297
https://github.com/flutter/flutter/issues/120102

昔設定した方法のメモ書き:

import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:sugary_map/presentation/router/auth_provider.dart';
import 'package:sugary_map/presentation/ui/page/auth_page/forget_password.dart';
import 'package:sugary_map/presentation/ui/page/auth_page/signin_page.dart';
import 'package:sugary_map/presentation/ui/page/auth_page/signup_page.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/map_page/home_page.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/mypage/account/create_user.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/mypage/account/delete_account_page.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/mypage/account/mail_reset_page.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/mypage/account/password_reset_page.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/mypage/account/update_user.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/mypage/mypage.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/mypage/mypage_list/accont_page.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/mypage/mypage_list/profile_test.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/notification_page/notification_page.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/post_page/post_page.dart';
import 'package:sugary_map/presentation/ui/page/user/navigation_page/scaffold_navbar.dart';

final GlobalKey<NavigatorState> _rootNavigatorKey =
    GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> _shellNavigatorKey =
    GlobalKey<NavigatorState>(debugLabel: 'shell');

final goRouterProvider = Provider<GoRouter>((ref) {
  final authChange = ref.watch(authProvider);
  return GoRouter(
    observers: [
      // GoogleAnalyticsの設定
      FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance),
    ],
    redirect: (BuildContext context, GoRouterState state) {
      if (authChange.isLoading || authChange.hasError) return null;

      // GoRouterStateの機能でログインしていなければ
      // 最初に表示されるページへ画面遷移する
      final isStart = state.location == '/';
      // ログインしているか判定する変数
      final isAuth = authChange.valueOrNull != null;

      // ユーザーがスタートページへ来ようとしていて、ログインしてなければ素通りさせる。
      if (isStart && !isAuth) {
        return null;
      }
      // isStartでなければ素通りさせて良い。
      if (!isStart) {
        return null;
      }

      // ユーザーがログインしていたら、HomePageへリダイレクト
      if (isAuth) {
        return '/';
      }
    },
    navigatorKey: _rootNavigatorKey,
    initialLocation: '/',
    routes: <RouteBase>[
      // 通常のルート
      GoRoute(
          path: '/login',
          builder: (BuildContext context, GoRouterState state) {
            return const SignInPage();
          }),
      GoRoute(
        path: '/new',
        builder: (BuildContext context, GoRouterState state) {
          return const SignUpPage();
        },
      ),
      GoRoute(
        path: '/reset',
        builder: (BuildContext context, GoRouterState state) {
          return const ForgetPassword();
        },
      ),
      // ボトムナビゲーションバーのルート
      ShellRoute(
        navigatorKey: _shellNavigatorKey,
        pageBuilder: (BuildContext context, GoRouterState state, Widget child) {
          return NoTransitionPage(child: ScaffoldWithNavBar(child: child));
        },
        routes: <RouteBase>[
          GoRoute(
            name: HomePage.routeName,
            path: '/',
            builder: (BuildContext context, GoRouterState state) {
              return const HomePage();
            },
          ),
          GoRoute(
            name: PostPage.routeName,
            path: '/post',
            builder: (BuildContext context, GoRouterState state) {
              return const PostPage();
            },
          ),
          GoRoute(
            name: NotificationPage.rootName,
            path: '/push',
            builder: (BuildContext context, GoRouterState state) {
              return const NotificationPage();
            },
          ),
          GoRoute(
              name: MyPage.routeName,
              path: '/my_page',
              builder: (BuildContext context, GoRouterState state) {
                return const MyPage();
              },
              routes: [
                // TODO: TestPage
                GoRoute(
                    name: ProfileTest.rootName,
                    path: 'test',
                    builder: (BuildContext context, GoRouterState state) {
                      return ProfileTest();
                    }),
                // TODO: UpdateTest
                GoRoute(
                    name: UpdateUser.routeName,
                    path: 'update_user',
                    builder: (BuildContext context, GoRouterState state) {
                      return UpdateUser();
                    }),
                GoRoute(
                    name: UserAccountSettings.routeName,
                    path: 'user_account',
                    builder: (BuildContext context, GoRouterState state) {
                      return const UserAccountSettings();
                    },
                    routes: [
                      GoRoute(
                          name: UserEmailUpdate.routeName,
                          path: 'email_reset',
                          builder: (BuildContext context, GoRouterState state) {
                            return UserEmailUpdate();
                          }),
                      GoRoute(
                          name: UserPasswordUpdate.routeName,
                          path: 'password_update',
                          builder: (BuildContext context, GoRouterState state) {
                            return const UserPasswordUpdate();
                          }),
                      GoRoute(
                          name: CreateUser.routeName,
                          path: 'create_user',
                          builder: (BuildContext context, GoRouterState state) {
                            return const CreateUser();
                          }),
                      GoRoute(
                          name: DeleteAccountPage.rootName,
                          path: 'delete_user',
                          builder: (BuildContext context, GoRouterState state) {
                            return const DeleteAccountPage();
                          }),
                    ]),
                GoRoute(
                    name: SignInPage.routeName,
                    path: 'sign_in',
                    builder: (BuildContext context, GoRouterState state) {
                      return const SignInPage();
                    },
                    routes: [
                      GoRoute(
                        name: SignUpPage.routeName,
                        path: 'sign_up',
                        builder: (BuildContext context, GoRouterState state) {
                          return const SignUpPage();
                        },
                      ),
                      GoRoute(
                        name: ForgetPassword.routeName,
                        path: 'forget',
                        builder: (BuildContext context, GoRouterState state) {
                          return const ForgetPassword();
                        },
                      ),
                    ]),
              ]),
        ],
      ),
    ],
  );
});

Discussion