6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

グレンジAdvent Calendar 2024

Day 22

GameAnalyticsの導入からABテストの実装まで

Last updated at Posted at 2024-12-21

はじめに

はじめまして、株式会社グレンジでクライアントエンジニアをしている田島と申します🙇‍♂️
本投稿は グレンジ Advent Calendar 2024 の22日目の記事です

この記事の対象となる読者

  • 開発しているゲームにGameAnalyticsを導入したい人
  • GameAnalyticsを使ってABテストを実施したい人

ABテストとは

アプリを新規インストールしたユーザーを2つ以上のグループに割り振りグループごとにアプリの内容を分岐させる手法のことで、期間の違いによる影響を受けることなく複数のバージョンの数字の違いを見ることができます

GameAnalyticsにおいてはリモートコンフィグ機能を使用して一つのkeyに対して複数種類のvalueをGameAnalyticsサーバーから返すことで割り振られたグループをクライアント側で判別することができるようになっています

公式ドキュメント

About GameAnalytics

前提条件

  • Unity 2022 3.47f1
  • com.gameanalytics.sdk: 7.10.0
  • com.google.external-dependency-manager: 1.2.182
  • プラットフォーム: Android
  • GameAnalyticsを導入するUnityプロジェクトが作成済みであること

手順

GameAnalyticsプロジェクトの作成(ブラウザ)

それぞれの項目が済んでいる方は必要に応じてスキップしてください

GameAnalyticsアカウントの作成

GameAnalyticsのトップ画面 から右上の Sign up を選択し、メールアドレスもしくはGoogleアカウントで登録します

職種や利用する理由について聞かれるので回答してください

info.png

パスワードを設定します

password.png

組織に関する情報を入力し、組織を作成します

スクリーンショット 2024-12-19 午後10.02.24.png

プロジェクトの作成

アカウントの登録まで完了すると↓以下のような組織の管理画面に遷移します
プロジェクトを作成するために組織の下にスタジオを作る必要があるため、真ん中の + Create Studio ボタンを押下しスタジオ作成ダイアログを開きます

スクリーンショット 2024-12-19 午後10.09.38.png

スタジオが所属する組織、スタジオの名前を入力しスタジオを作成します

スクリーンショット 2024-12-19 午後10.12.41.png

組織の管理画面の真ん中に + Create Game というボタンが表示されるようになるのでこれを押下しプロジェクト作成ダイアログを開きます

スクリーンショット 2024-12-19 午後10.19.31.png

ゲームが所属する組織、スタジオ、タイトル、SDKを導入する環境、プラットフォームを入力しプロジェクトを作成します

ここではプラットフォームとしてAndroidを選択します
iOSもリリースする場合、iOS用のGameAnalyticsプロジェクトを作成する必要があります

スクリーンショット 2024-12-19 午後10.22.39.png

プロジェクトの作成を完了すると、組織の管理画面に作成したプロジェクトが表示されるようになります

プロジェクト作成後、最大1分ほどプロジェクトのページにアクセスできません

GameAnalytics SDKのインポート

Unityエディタでの作業に移ります

SDKのインポートはUnity Package Manager(以下upm)を使用する方法と .unitypackage ファイルを使用する方法がありますが、ここではupmを使用する方法を取ります

Setup/Unity Package Manager

External Dependency Managerのインポート

upmでのインポートではGoogleのExternal Dependency Managerが必要となるため ダウンロードページ からターボールファイル(.tgz)をダウンロードし Packages ディレクトリの下に配置します

manifest.jsonの更新

Packages/manifest.json

    "com.gameanalytics.sdk": "7.10.0",
    "com.google.external-dependency-manager": "file:com.google.external-dependency-manager-1.2.182.tgz"

を記載します

GameAnalytics SDKの最新バージョンについてはどうやらGameAnalyticsのドキュメント内には記載がないようなので OpenUPM を参照します

また、Packages/manifest.json にScoped Registryを追加します

  "scopedRegistries": [
    {
      "name": "Game Package Registry by Google",
      "url": "https://unityregistry-pa.googleapis.com/",
      "scopes": [
        "com.google"
      ]
    },
    {
      "name": "OpenUPM",
      "url": "https://package.openupm.com/",
      "scopes": [
        "com.gameanalytics"
      ]
    }
  ]

Unityエディタに戻るとリロードが走り、 Packages 以下に GameAnalytics ディレクトリが追加されているかと思います

スクリーンショット 2024-12-19 午後11.24.24.png

GameAnalytics Settingsの設定

GameAnalyticsの設定ファイルを更新していきます

Window > GameAnalytics > Select Settings を押すと Assets/Resources/GameAnalytics/Settings.asset というファイルが作成されます

すでにある場合は該当のファイルが選択されます

Inspector上にメールアドレスとパスワードを入力するフォームが表示されるかと思うのでGameAnalyticsに登録したアカウントのメールアドレス、パスワードを入力し Login を押します

GameAnalyticsで作成したプロジェクトと同じプラットフォームをプルダウンから選択し、 Add platform を押します

スクリーンショット 2024-12-19 午後11.13.23.png

組織、スタジオ、プロジェクト名をプルダウンから選択するとプロジェクトに紐づく Game Key および Secret Key が自動で入力されます

Buildの欄はデフォルトのままで問題ないですが、アプリのバージョンに対応させるとわかりやすいと思います

入力しただけだと .asset ファイルが更新されないので Cmd(Ctrl) + S で保存します

スクリーンショット 2024-12-19 午前10.30.59.png

GameAnalytics SDKの初期化

GameAnalytics SDKを初期化するプログラムはシンプルで

GameAnalytics.Initialize();

を呼び出すだけです

サンプルコードでは簡便のため、Awakeから初期化を呼び出していますがプロジェクトの初期化シーケンスの適切なタイミングで呼び出すことが望ましいです

疎通確認

このままABテストの実装に移ってもよいのですがABテスト作成時にGameAnalytics SettingsのBuild番号を指定する項目があり、アクティブユーザーが存在しているBuild番号しか選択肢として表示されないためここで一度実機による疎通確認を行います

アプリをビルドしプレイしたのちGameAnalyticsのプロジェクトのダッシュボードに移動します
左のタブから RealTime を選択し遷移したページで 👁️ Live Events を選択します

スクリーンショット 2024-12-19 午後11.37.19.png

疎通が完了していれば↓以下のようにイベントが送信されています

スクリーンショット 2024-12-19 午後11.35.19.png

ABテストの実装

内部の処理としては先述の通り、リモートコンフィグから値を取得しその値によってアプリ内部の処理を分岐させる、というものです

GameAnalyticsの初期化が完了するまではテストグループを判定できないため初期化が完了した際のコールバックでフラグを立てます

    private bool _initializedFlag;

    private void Awake()
    {
        GameAnalytics.onInitialize += OnInitialize;
        ...
    }

    private void OnInitialize(object sender, bool eventArgs)
    {
        _initializedFlag = true;
    }

また、リモートコンフィグが取得可能になるまでは同様にテストグループを判定できないためリモートコンフィグのステータスが更新された際のコールバックでフラグを立てます

    private bool _remoteConfigIsReady;

    private void Awake()
    {
        GameAnalytics.OnRemoteConfigsUpdatedEvent += OnUpdateRemoteConfigs;
        ...
    }

    private void OnUpdateRemoteConfigs()
    {
        _remoteConfigIsReady = GameAnalytics.IsRemoteConfigsReady();
    }

_initializedFlag および _remoteConfigIsReadytrue になるまで待機し true になったらリモートコンフィグから値を取得します

    private IEnumerator GetTestGroup()
    {
        yield return new WaitUntil(() => _initializedFlag && _remoteConfigIsReady);

        var testGroupRemoteConfigValue = GameAnalytics.GetRemoteConfigsValueAsString(
            "test_group",
            "group_a"
        );

        PlayerPrefs.SetString("test_group", testGroupRemoteConfigValue);
        PlayerPrefs.Save();
    }

サンプルコードでは簡便のため PlayerPrefs に値を保存していますがご自身のプロジェクトにユーザーデータを保存する機構などがあればそちらで保存することを推奨します
プロジェクトのサーバーが建てられているのであればそちらで保存するのがよいでしょう

取得したリモートコンフィグの値をフラグとしてラップして返すようにすると扱いやすくなるかと思います

例:

public class UserData
{
    private string _testGroup;

    // NOTE: グループBだったら難易度を上げたver
    public bool HardModeFlag => _testGroup == "group_b";
}

サンプルコードではABテストのグループによって画面に表示するテキストを分岐させるようにしています

    private IEnumerator GetTestGroup()
    {
        yield return new WaitUntil(() => _initializedFlag && _remoteConfigIsReady);

        var testGroupRemoteConfigValue = GameAnalytics.GetRemoteConfigsValueAsString(
            "test_group",
            "group_a"
        );

        PlayerPrefs.SetString("test_group", testGroupRemoteConfigValue);
        PlayerPrefs.Save();

        var testGroup = PlayerPrefs.GetString("test_group", "group_a");
        _testGroupText.text = testGroup;
    }

ABテストの作成

GameAnalyticsのプロジェクトのダッシュボードに移動します
左のタブから A/B Testing を選択し遷移したページで Create experiment を選択します

スクリーンショット 2024-12-20 午前12.35.23.png

↓以下の項目を入力します

  • ABテスト名
  • ビルド番号
  • ユーザー上限
  • ABテストに参加する割合
  • リモートコンフィグのkey
  • それぞれのグループがリモートコンフィグから取得する値
  • 開始時間
  • 比較する指標

入力後は↓以下のようになります

スクリーンショット 2024-12-20 午前12.38.36.png

スクリーンショット 2024-12-20 午前12.38.44.png

ABテストは新規インストールユーザーのみが対象となり、例えばABテストに参加する割合(Enrollment rate)を10にした場合、新規インストールユーザーの10%がABテストに参加することになります

Start test を押してABテストを開始します

ABテストの分岐の確認

アプリをビルドし、再インストールを繰り返してアプリの内容が分岐することを確認します

まとめ

最後までご覧いただきありがとうございます
SDKの導入は確認するまでにラグがあったりでしんどいことが多いイメージですがGameAnalyticsはほぼリアルタイムで確認できてその点はとてもありがたいです

この記事が1人でも多くの人の助けになれば幸いです
指摘、質問等ございましたら遠慮なくコメントしていただけますと幸いです🙇‍♂️

サンプルコード

StartScene.cs
using System;
using System.Collections;
using GameAnalyticsSDK;
using TMPro;
using UnityEngine;

public class StartScene : MonoBehaviour
{
    private const string DefaultTestGroupValue = "Default";

    private const string TestGroupRemoteConfigKey = "test_group";
    private const string TestGroupRemoteConfigDefaultValue = "group_a";

    private const string TestGroupPreferenceKey = "test_group";

    [SerializeField] private TextMeshProUGUI _testGroupText;

    private bool _initializedFlag;
    private bool _remoteConfigIsReady;

    private void Awake()
    {
        GameAnalytics.onInitialize += OnInitialize;
        GameAnalytics.OnRemoteConfigsUpdatedEvent += OnUpdateRemoteConfigs;

        GameAnalytics.Initialize();
    }

    private void Start()
    {
        var testGroup = PlayerPrefs.GetString(TestGroupPreferenceKey, "");
        if (!string.IsNullOrEmpty(testGroup))
        {
            _testGroupText.text = testGroup;
            return;
        }

        StartCoroutine(GetTestGroupCoroutine());
    }

    private void OnInitialize(object sender, bool eventArgs)
    {
        _initializedFlag = true;
    }

    private void OnUpdateRemoteConfigs()
    {
        _remoteConfigIsReady = GameAnalytics.IsRemoteConfigsReady();
    }

    private IEnumerator GetTestGroupCoroutine()
    {
#if UNITY_EDITOR
        _remoteConfigIsReady = true;
#endif

        yield return new WaitUntil(() => _initializedFlag && _remoteConfigIsReady);

        var testId = GameAnalytics.GetABTestingId();
        if (string.IsNullOrEmpty(testId))
        {
            SaveTestGroup(DefaultTestGroupValue);
            SetTestGroupText(DefaultTestGroupValue);

            yield break;
        }

        var testGroupRemoteConfigValue = GameAnalytics.GetRemoteConfigsValueAsString(
            TestGroupRemoteConfigKey,
            TestGroupRemoteConfigDefaultValue
        );

        SaveTestGroup(testGroupRemoteConfigValue);
        SetTestGroupText(testGroupRemoteConfigValue);
    }

    private void SaveTestGroup(string testGroup)
    {
        PlayerPrefs.SetString(TestGroupPreferenceKey, testGroup);
        PlayerPrefs.Save();
    }
    
    private void SetTestGroupText(string text)
    {
        _testGroupText.text = text;
    }
}
6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?