📈

Flutter アプリに Google Analytics を導入する

2023/11/29に公開
1

こんにちは、 kenty(ケンティー) です。
今回は Flutter アプリに Google Analytics を導入する方法をご紹介します。

Google Analytics とは?

WEBサイトやモバイルアプリの分析ができるサービスです。導入すると、👤ユーザー数の増減とか、🛠️新機能の利用数とか、あなたが作ったサービスを改善していく為の数値が分かるようになります!!Flutter アプリなら、 基本的に Firebase を使って Google Analytics を導入します。

以下、公式のサービス説明です。

https://firebase.google.com/docs/analytics?hl=ja

これによると、実装の流れとして 「1. アプリを Firebase に接続する」「2. カスタムデータを記録する」「3. ユーザーリストの作成」「4. ターゲット ユーザー」が示されています。今回は 〜2 の導入までを目標とします。

実装パス

公式の解説がめちゃいい

状態管理やルーティングに特段パッケージを導入していないなら、公式の解説を見るのが一番良いです。
仮に導入している場合も、まずは公式を一読するべきでしょう。ちゃんと Flutter のクイックスタートが用意されていますし、個人ブログなどでは情報が古い場合があります。

https://firebase.google.com/docs/analytics/get-started?platform=flutter&hl=ja

始める前に
firebase_core をインストールし、初期化コードをアプリに追加します(まだ行っていない場合)。
Firebase コンソールでアプリを Firebase プロジェクトに追加します。
...

まだアプリが Firebase と未連携なら、先に以下の記事等を参考にして連携して下さい。

https://firebase.google.com/docs/flutter/setup?hl=ja
https://qiita.com/tokkun5552/items/cd70c65dd06935d8c751
https://qiita.com/kazakago/items/e1027619d0361848f3b8

導入

公式の解説で、特段パッケージを導入していない場合はすぐに導入ができたはずです。なので以降の実装例は、状態管理に Riverpod を使っているケースを想定して解説していきます。

パッケージを追加する

Firebase と連携済み = firebase_core はインストールされている前提で記載します。以下コマンドで analytics のパッケージをインストールしてください。

flutter pub add firebase_analytics

https://pub.dev/packages/firebase_analytics

MaterialApp の navigatorObservers に observer を渡す

analytics インスタンス、 observer インスタンスを作成し、

analytics_repository.dart
// ファイル名などは、プロジェクトの規則に沿って適宜変更してください。

import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

/// FirebaseAnalyticsのインスタンス
final analyticsRepository = Provider((ref) => FirebaseAnalytics.instance);

/// FirebaseAnalyticsObserverのインスタンス
final analyticsObserverRepository = Provider((ref) =>
    FirebaseAnalyticsObserver(analytics: ref.watch(analyticsRepository)));

navigatorObservers に observer を渡す。

main.dart
/* import 文は省略 */

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Firebase の初期化などは済んでいる前提
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  // riverpod 利用しているので、 ProviderScope で囲んでいる
  runApp(ProviderScope(child: App()));
}

// インスタンスを ref.watch で取得したいので、 ConsumerWidget にする
class App extends ConsumerWidget { 
  
  Widget build(BuildContext context, WidgetRef ref) {
    var analytics = ref.watch(analyticsRepository);
    var analyticsObserver = ref.watch(analyticsObserverRepository);

    return MaterialApp(
      /* ...theme の設定とかは割愛 */
      home: LoginPage(),
      // Navigator の画面遷移を検出して通知する
      navigatorObservers: [analyticsObserver],
    );
  }
}

アプリが開かれたイベントを入れる

analytics.logAppOpen(); を App で呼ぶ。

main.dart
/* 上記まま。 */

Future<void> main() async {
  /* 省略 */
}

class App extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    var analytics = ref.watch(analyticsRepository);
    var analyticsObserver = ref.watch(analyticsObserverRepository);
    
    // アプリが開かれたことをFirebaseAnalyticsに送信
    analytics.logAppOpen();

    return MaterialApp(
       /* 省略 */
    );
  }

analytics に app_open イベントとして記録される。(ただし、ダッシュボードに反映されるまで1日ほどかかります。すぐに確認したいなら、デバッグビューを利用しましょう。この記事とか参考になるはずです。)

firebase_analytics

app_open

最低限の設定

画面遷移箇所に screenName を仕込む

MaterialApp で observer をセットしたので、このままでも画面遷移は送信されます。
しかし、何もしないとこの送信結果がめちゃくちゃ見づらいです。

スクリーンクラスでは、ユーザーが何をしているかまるで分かりません。。。

そこで、 screenName を指定してあげ、画面名がわかるようにしてあげます。

スクリーン名指定前はこんな感じです。
(not set) となり、 observer が送信しているが、画面名がわからない状態です。

以下のようにして 画面遷移の各場所に screenName を設定することができます。

画面遷移の箇所
ElevatedButton(
  onPressed: () => {
    Navigator.push(
      context,
      // settings に RouteSetttings を指定する
      MaterialPageRoute(
        builder: (context) => ProfileSetupPage(),
        settings: RouteSettings(name: '/profile_setup_page'),
      ),
    ),
  },   child = Text('画面遷移が発生するボタン'),
);

named routes を使っているなら、以下のようにできます。

Navigator.pushNamed(context, '/profile_setup_page');

参考:
https://qiita.com/hiko1129/items/c639fd69308c031aa900

スクリーン名指定後はこんな感じです。
(not set) だったところが名前を取得できて、画面毎にどれくらい表示されたかわかるようになりました。

option: ナビバーを利用している場合

ナビバー内のページ変更 ( index の変更) は、Navigatorの処理ではないので observer の監視対象ではありません。 ナビバー内でのページ変更も分析したいアプリがほどんどだと思うので、一工夫して対応します。

具体的には、現在表示されているページが切り替わったら analytics.setCurrentScreen() を呼び出します。

私は screenName/${ナビバーを持つPage名}/${ナビバーで管理しているitem名} になるように調整してます。

home_navigation_page.dart
// 今回は hooks を利用しているが、プロジェクトに合わせて適宜変更する

/* import 省略 */

/// フッターナビゲーションで管理するページのenum
enum HomeNavigationItems {
  home(icon: Icons.home, destination: HomePage()),
  profile(icon: Icons.person, destination: ProfilePage()),
  other(icon: Icons.more_horiz, destination: OtherPage()),
  ;
  const HomeNavigationItems({required this.icon, this.destination});
  final IconData icon;
  final Widget? destination;
}

class HomeNavigationPage extends HookConsumerWidget {
  const HomeNavigationPage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context, WidgetRef ref) {
    // フッターナビゲーションの現在のタブを管理する
    final items = useState<HomeNavigationItems>(HomeNavigationItems.home);

    // items の値が変更されたときに、現在のタブを FirebaseAnalytics に送信する
    // ナビバーの切り替えもページ遷移として扱いたい為
    useEffect(() {
      final analytics = ref.read(analyticsRepository);
      final screenName = '/home_navigation_page/${items.value.name}';
      analytics.setCurrentScreen(screenName: screenName);
      return null;
    }, [items.value]);

    return Scaffold(
      body: items.value.destination,
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: items.value.index,
        items: HomeNavigationItems.values
            .map(
              (item) => BottomNavigationBarItem(
                icon: Icon(item.icon),
                label: item.name,
              ),
            )
            .toList(),
        onTap: (index) {
          items.value = HomeNavigationItems.values[index];
        },
      ),
    );
  }
}

アプリを改善していく

アプリによって、意味のあるデータを記録できるようカスタマイズする

上記までが、スタートラインに立つための設定です。ここまで終わったら、次はアプリにとって意味のあるデータを記録しましょう。
例えば SNS だったら post や共有のタイミング、 EC アプリならカートへの商品追加や購入確定のタイミングを記録したいと言ったように、アプリによって計測したい内容は変わってきます。公式 docs を見ながら、イベントのロギングを仕込んでいきましょう。

Google の推奨イベントは以下の通りです。迷ったらこの中からサービスに合うように導入しましょう。

https://support.google.com/analytics/answer/9267735?hl=ja

ここまで終われば、冒頭で紹介した公式の実装パス〜2まで対応したと言えるでしょう!!
お疲れ様でした。

BIツールと連携しよう

Firebase の ダッシュボードでもデータは一覧できますが、前述の通りアプリによって確認・比較したいデータは変わってきます。BIツールと連携してデータの可視化を行うことで、一目でアプリの分析から気づきを得られるようになります。これは特に、営業さんやクライアントにお見せする際に役立ったりします。

おすすめは Looker Studio との連携です。Google さんのサービスなので、連携がめちゃ楽だと思います。AWS QuickSight のような他サービスでも analytics のデータを吸い上げる為に一手間かかりますが連携可能です。

参考:
https://solutions.dac.co.jp/blog/ga4_lookerstudio
https://webtan.impress.co.jp/e/2022/12/26/43801
https://aws.amazon.com/jp/blogs/news/analyze-google-analytics-data-using-upsolver-amazon-athena-and-amazon-quicksight/

得られたデータからアプリを改善しよう

アプリにあった有効なデータを収集し、BIツールで可視化されたデータから得られる気づきをもとに、アプリをより良くする為の仮説を立てましょう。仮説を立てたら実装してみて、再度データを収集し、その仮説が正しかったか分析します。それを繰り返し、どんどんアプリを改善していきましょう。

まとめ

  • analytics パッケージをインストールするだけではデータ分析が困難。最低限の設定を行う。
  • 画面遷移を記録し、画面名を設定することがスタートライン。上記をやれば一通り設定できる。
  • ナビバーやタブを利用しているなら、画面遷移にカウントされないので一工夫必要。
  • 一通り設定したら、そのアプリにあった有効なデータの収集データの可視化を行う。
  • 分析結果から仮説を立て、アプリを改善していこう!

追記

記事を公開後、Flutter大学の人が書いたanalyticsの記事を読みました。
みんな興味はあると思う。参考に添付しておきます。

https://zenn.dev/flutteruniv_dev/articles/655e73eec52a1c
https://zenn.dev/flutteruniv_dev/articles/6ed3d3a120b3f9

追記その2

動画のわかりやすい記事:

https://www.filledstacks.com/post/firebase-analytics-and-metrics-in-flutter/


追記その3

Flutter大学

Discussion

kenty (ケンティー)kenty (ケンティー)

画面遷移が増える度に RouteSettings に記載するの面倒なので、どこかで一括で設定して幸せになりたい。。