データを保存する

準備

Firebase Realtime Database を使用するには、Firebase プロジェクトを作成してから、Firebase Unity SDK パッケージを Unity プロジェクトに追加する必要があります。

設定:

前提条件

Android

iOS

  • Unity 5.0 以降
  • Xcode 7.0 以降

Unity プロジェクトをまだ用意していない場合は、いずれかのクイックスタート サンプルをダウンロードし、特定の Firebase 機能をお試しいただけます。 クイックスタートを使用する場合は、次のステップでバンドル識別子が必要になるため、プロジェクト設定からバンドル識別子を忘れずに取得してください。

Firebase コンソールでアプリを設定する

アプリに Firebase を追加するには、Firebase プロジェクトと、アプリ用の Firebase 設定ファイルが必要です。

Firebase プロジェクトをまだ用意していない場合は、Firebase コンソールで Firebase プロジェクトを作成します。モバイルアプリと関連付けられた既存の Google プロジェクトがある場合は、[Google プロジェクトをインポート] をクリックします。それ以外の場合は、[新規プロジェクトを作成] をクリックします。

Android

  1. [Android アプリに Firebase を追加] をクリックし、設定手順に沿って操作します。既存の Google プロジェクトをインポートする場合、このステップは自動的に実行されることがあります。その場合は、設定ファイルをダウンロードするだけでかまいません。
  2. プロンプトが表示されたら、アプリのパッケージ名を入力します。必ずアプリで使用しているパッケージ名を入力してください。パッケージ名を設定できるのは、アプリを Firebase プロジェクトに追加するときだけです。
  3. 指示されたら google-services.json ファイルをダウンロードします。このファイルはいつでも再ダウンロードできます。
  4. このファイルを、プロジェクトのアセット フォルダ内の任意の場所にコピーします。

iOS

  1. [iOS アプリに Firebase を追加] をクリックして設定手順に沿って操作します。既存の Google プロジェクトをインポートする場合、このステップは自動的に実行されることがあります。その場合は、設定ファイルをダウンロードするだけでかまいません。
  2. プロンプトが表示されたら、アプリのバンドル ID を入力してください。必ずアプリで使用しているバンドル ID を入力してください。バンドル ID を設定できるのは、アプリを Firebase プロジェクトに追加するときだけです。
  3. 指示されたら GoogleService-Info.plist ファイルをダウンロードします。このファイルはいつでも再ダウンロードできます。
  4. プロジェクトに GoogleService-Info.plist ファイルを追加します。

  5. Firebase コンソールからダウンロードした GoogleService-Info.plist を、Unity プロジェクトの任意のフォルダにドラッグします。

アプリに Firebase Unity SDK を追加する

  1. Firebase Unity SDK をダウンロードします。
  2. [Assets] > [Import Package] > [Custom Package] メニュー項目を選択します。
  3. 先にダウンロードした Firebase Unity SDK から FirebaseDatabase.unitypackage パッケージをインポートします。
  4. [Import Unity Package] ウィンドウが表示されたら [Import] ボタンをクリックします。

アプリをビルドする

Android

  1. [File] > [Build Settings] メニュー項目を選択します。
  2. [Platform] リストから [Android] を選択します。
  3. [Switch Platform] をクリックし、ターゲット プラットフォームとして [Android] を選択します。
  4. Unity ステータスバーの右下隅にあるスピナー(コンパイル中)アイコンが停止するまで待ちます。
  5. [Build and Run] をクリックします。

iOS

  1. [File] > [Build Settings] メニュー項目を選択します。
  2. [Platform] リストから [iOS] を選択します。
  3. [Switch Platform] をクリックし、ターゲット プラットフォームとして [iOS] を選択します。
  4. Unity ステータスバーの右下隅にあるスピナー(コンパイル中)アイコンが停止するまで待ちます。
  5. [Build and Run] をクリックします。

データの保存

Firebase Realtime Database にデータを書き込むメソッドは次のように 5 種類あります。

メソッド 一般的な使用例
SetValueAsync() users/<user-id>/<username> など、定義済みのパスへのデータの書き込みや、データの置換を行います。
SetRawJsonValueAsync() users/<user-id>/<username> など、未加工の Json へのデータの書き込みや、データの置換を行います。
Push() データのリストに追加します。Push() を呼び出すたびに、user-scores/<user-id>/<unique-score-id> のような一意の識別子としても使用できる一意のキーが生成されます。
UpdateChildrenAsync() データのすべてを置換することなく、定義済みのパスのキーの一部を更新します。
RunTransaction() 同時更新によって破損する可能性がある複合データを更新します。

DatabaseReference を取得する

データベースにデータを書き込むには、DatabaseReference のインスタンスが必要です。

using Firebase;
using Firebase.Database;
using Firebase.Unity.Editor;

public class MyScript: MonoBehaviour {
  void Start() {
    // Set up the Editor before calling into the realtime database.
    FirebaseApp.DefaultInstance.SetEditorDatabaseUrl("https://YOUR-FIREBASE-APP.firebaseio.com/");

    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

参照でのデータの書き込み、更新、削除

基本的な書き込み操作

基本的な書き込み操作では、SetValueAsync() を使用してデータを特定の参照に保存できます。そのパスにある既存のデータが置換されます。このメソッドを使用すると、次のような、使用可能な JSON 型に対応する型を渡すことができます。

  • string
  • long
  • double
  • bool
  • Dictionary<string, Object>
  • List<Object>

型付きの C# オブジェクトを使用する場合は、組み込みの JsonUtility.ToJson() を使用して、オブジェクトを未加工の Json に変換し、SetRawJsonValueAsync() を呼び出します。たとえば、次のような User クラスがあるとします。

public class User {
    public string username;
    public string email;

    public User() {
    }

    public User(string username, string email) {
        this.username = username;
        this.email = email;
    }
}

次のように SetRawJsonValueAsync() でユーザーを追加できます。

private void writeNewUser(string userId, string name, string email) {
    User user = new User(name, email);
    string json = JsonUtility.ToJson(user);

    mDatabaseRef.Child("users").Child(userId).SetRawJsonValueAsync(json);
}

この方法で SetValueAsync() または SetRawJsonValueAsync() を使用すると、指定された場所にあるデータ(子ノードを含む)が上書きされます。ただし、オブジェクト全体を書き換えずに子を更新することもできます。users に自分のプロフィールの更新を許可する場合、次のように username を更新できます。

mDatabaseRef.Child("users").Child(userId).Child("username").SetValueAsync(name);

データのリストへの追加

Push() メソッドを使用して、マルチユーザー アプリケーションでリストにデータを追加します。指定した Firebase 参照に新しい子が追加されるたびに、Push() メソッドは一意のキーを生成します。この自動生成されたキーをリスト内の新しい各要素に使用することで、書き込みの競合を伴わずに複数のクライアントが同時に子を同じ場所に追加できます。Push() によって生成される一意の ID がタイムスタンプに基づいているため、リストのアイテムは自動的に時系列で並べ替えられます。

Push() メソッドによって返された新しいデータを参照することで、子の自動生成されたキーの値を取得することも、子のデータを設定することもできます。Key 参照の Push() を呼び出すと、自動生成されたキーの値が返されます。

特定のフィールドの更新

他の子ノードを上書きすることなく、ノードの特定の複数の子に同時に書き込むには、UpdateChildrenAsync() メソッドを使用します。

UpdateChildrenAsync() の呼び出し時に、キーのパスを指定して下位レベルの子の値を更新できます。拡張性を向上させるためにデータが複数の場所に保存されている場合、データのファンアウトを使用してそのデータのすべてのインスタンスを更新できます。たとえば、次のようにゲームに LeaderboardEntry クラスが使用されていることがあります。

public class LeaderboardEntry {
    public string uid;
    public int score = 0;

    public LeaderboardEntry() {
    }

    public LeaderboardEntry(string uid, int score) {
        this.uid = uid;
        this.score = score;
    }

    public Dictionary&ltstring, Object&gt ToDictionary() {
        Dictionary&ltstring, Object&gt result = new Dictionary&ltstring, Object&gt();
        result["uid"] = uid;
        result["score"] = score;

        return result;
    }
}

LeaderboardEntry を作成するのと同時に、それを最新のスコアフィードとユーザー自身のスコアリストに更新するには、ゲームで次のようなコードを使用します。

private void WriteNewScore(string userId, int score) {
    // Create new entry at /user-scores/$userid/$scoreid and at
    // /leaderboard/$scoreid simultaneously
    string key = mDatabase.Child("scores").Push().Key;
    LeaderBoardEntry entry = new LeaderBoardEntry(userId, score);
    Dictionary&ltstring, Object&gt entryValues = entry.ToDictionary();

    Dictionary&ltstring, Object&gt childUpdates = new Dictionary&ltstring, Object&gt();
    childUpdates["/scores/" + key] = entryValues;
    childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

    mDatabase.UpdateChildrenAsync(childUpdates);
}

この例では、Push() を使用して /scores/$key にある全ユーザーのエントリを含んでいるノードでエントリを作成するのと同時に、Key でキーを取得しています。その後、このキーを使用して、/user-scores/$userid/$key にあるユーザーのスコアに別のエントリを作成できます。

これらのパスを使用すると、上記の例で両方の場所に新しいエントリを作成したように、UpdateChildrenAsync() を 1 回呼び出すだけで JSON ツリー内の複数の場所に対して更新を同時に実行できます。この方法による同時更新はアトミック(不可分)です。つまり、すべての更新が成功するか、すべての更新が失敗するかのどちらかです。

データの削除

データを削除する最も簡単な方法は、そのデータの場所への参照の RemoveValue() を呼び出すことです。

また、SetValueAsync()UpdateChildrenAsync() などの他の書き込み操作の値として null を指定することによって削除することもできます。この方法と UpdateChildrenAsync() を併用すると、API を 1 回呼び出すだけで複数の子を削除できます。

データが commit(確定)されたタイミングの把握

Firebase Realtime Database サーバーにデータが commit(確定)されたタイミングを把握するには、継続を追加します。SetValueAsync()UpdateChildrenAsync() はどちらも、操作が完了するタイミングを把握できる Task を返します。呼び出しがなんらかの理由で正常に完了しなかった場合、Task IsFaulted は true になり、Exception プロパティがその理由を示します。

トランザクションとしてのデータの保存

増分カウンタなど、同時変更によって破損する可能性があるデータを操作する場合は、transaction 操作を使用できます。この操作で Func を指定します。この update Func はデータの現在の状態を引数として取り、書き込む必要のある新しい状態を返します。新しい値が正常に書き込まれる前に別のクライアントがその場所に書き込んだ場合、update 関数が現在の新しい値で再度呼び出されて、書き込みが再試行されます。

例えば、ゲーム内でユーザーが上位の 5 つのスコアでリーダーボードを更新できるようにすることができます。

private void AddScoreToLeaders(string email,
                               long score,
                               DatabaseReference leaderBoardRef) {

    leaderBoardRef.RunTransaction(mutableData =&gt {
      List&ltobject&gt leaders = mutableData.Value as List&ltobject>

      if (leaders == null) {
        leaders = new List&ltobject&gt();
      } else if (mutableData.ChildrenCount &gt= MaxScores) {
        long minScore = long.MaxValue;
        object minVal = null;
        foreach (var child in leaders) {
          if (!(child is Dictionary&ltstring, object&gt)) continue;
          long childScore = (long)
                      ((Dictionary&ltstring, object&gt)child)["score"];
          if (childScore &lt minScore) {
            minScore = childScore;
            minVal = child;
          }
        }
        if (minScore &gt score) {
          // The new score is lower than the existing 5 scores, abort.
          return TransactionResult.Abort();
        }

        // Remove the lowest score.
        leaders.Remove(minVal);
      }

      // Add the new high score.
      Dictionary&ltstring, object&gt newScoreMap =
                       new Dictionary&ltstring, object&gt();
      newScoreMap["score"] = score;
      newScoreMap["email"] = email;
      leaders.Add(newScoreMap);
      mutableData.Value = leaders;
      return TransactionResult.Success(mutableData);
    });
}

トランザクションを使用することで、複数のユーザーが同時にスコアを記録した場合や、クライアントのデータが古くなった場合でも、リーダーボードを正確に保ちます。トランザクションが拒否された場合、サーバーは現在の値をクライアントに返します。クライアントは更新された値でトランザクションを再度実行します。この処理は、トランザクションが受け入れられるか、試行が上限の回数に達するまで繰り返されます。

オフラインでのデータの書き込み

クライアントでネットワーク接続が切断された場合でも、アプリは引き続き適切に機能します。

Firebase データベースに接続しているクライアントはそれぞれ、アクティブ データの内部バージョンを独自に保持しています。データが書き込まれると、まず、このローカル バージョンに書き込まれます。次に Firebase クライアントは、「ベスト エフォート」ベースでそのデータをリモート データベース サーバーや他のクライアントと同期します。

その結果、データベースへの書き込みはすべて、直ちにローカル イベントをトリガーします(これは、サーバーにデータが書き込まれる前の段階です)。つまり、ネットワークのレイテンシや接続に関係なく、アプリは応答性の高い状態を維持します。

接続が再確立されると、アプリは適切な一連のイベントを受信して、クライアントが現在のサーバー状態と同期するようにします。この処理のためにカスタムコードを記述する必要はありません。

次のステップ

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。