Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where do I place Firebase Check and Fix Dependencies code in Unity?

I wanted to use Firebase in my Unity game so one of the steps was to add the following code, but the place into which the code should be added wasn't specified. Any help?

Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => {
  var dependencyStatus = task.Result;
  if (dependencyStatus == Firebase.DependencyStatus.Available) {
    // Create and hold a reference to your FirebaseApp,
    // where app is a Firebase.FirebaseApp property of your application class.
       app = Firebase.FirebaseApp.DefaultInstance;

    // Set a flag here to indicate whether Firebase is ready to use by your app.
  } else {
    UnityEngine.Debug.LogError(System.String.Format(
      "Could not resolve all Firebase dependencies: {0}", dependencyStatus));
    // Firebase Unity SDK is not safe to use here.
  }
});

(This is the link to the instructions on Firebase) https://firebase.google.com/docs/unity/setup?authuser=0#confirm-google-play-version

like image 371
codexyz Avatar asked Nov 06 '25 19:11

codexyz


1 Answers

The best answer I can give is "before you do anything else" in Unity.

In a normal application, you'd have something like a main api entry point (application:didFinishLaunchingWithOptions in iOS, Activity.onCreate in Android, or literally void main(int,char**) in a typical C/C++ desktop application). But in Unity, you don't have any sort of "run this before everything else" logic. Whichever scene is first is up to you and subject to change, and scripts execute roughly in parallel (in an order that's best considered random but technically can be ordered).

Here are the patterns I've either used or have thought about using and a few associated pros and cons:

  1. [Recommended for beginners and small projects] In my videos, I typically recommend having a "loading" or "setup" scene. In that scene I place a FirebaseInit script that will initialize Firebase and raise an event when it's done. I can then either collect a bunch of initialization functionality (say downloading asset bundles or doing some initial setup processing) or just jump immediately into my main scene. Most of the time this will resolve to a no-op (on Android play services is up to date), so you can even shove it in the main menu if you're careful:
using System;
using Firebase;
using Firebase.Extensions;
using UnityEngine;
using UnityEngine.Events;

public class FirebaseInit : MonoBehaviour
{
    public UnityEvent OnInitialized = new UnityEvent();
    public InitializationFailedEvent OnInitializationFailed = new InitializationFailedEvent();

    void Start()
    {
        FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>
        {
            if (task.Exception != null)
            {
                OnInitializationFailed.Invoke(task.Exception);
            }
            else
            {
                OnInitialized.Invoke();
            }
        });
    }

    [Serializable]
    public class InitializationFailedEvent : UnityEvent<Exception>
    {
    }
}
  1. I'm not a big proponent of dependency injection (as in I typically don't use DI frameworks, but I do tend to use [SerializedField]s as a pseudo-DI system), so I don't have a good example to share. You can use ZenJect to create and inject the Firebase singletons to anything that needs them. The biggest issue you run into is that you have to await the dependencies to be initialized, which is possible but I just haven't gone through the steps of doing it in a sample project. The benefit is that you only need to express "I depend on Firebase", and ZenJect will take care of the rest (just avoid the DefaultInstance functions in this case).

  2. In more complex projects, I'll tend to wrap Firebase in a Coroutine (or an async task, but I prefer coroutines in Unity). So I'll have a Coroutine that will wait for check and fix dependencies to complete and return an instance of Realtime Database when it finishes (and intelligent logic to skip the waiting if not necessary). Again you have to avoid DefaultInstance outside of your management script, and every use of Firebase becomes a coroutine, but you can be sure that you always await on construction. Here is one example focusing on Realtime Database (I'm stripping unnecessary code to make it fit in a SO answer), and I'll reiterate that this is a lot of overhead for a small project:

public class FirebaseBehaviour : MonoBehaviour
{
    private IEnumerator _setupFirebase;
    private DatabaseReference _databaseReference;

    void Awake()
    {
        // everything depends on firebase being setup. Do this first.
        _setupFirebase = SetupFirebase();
        StartCoroutine(_setupFirebase);
    }

    private IEnumerator SetupFirebase()
    {
        // we need to fix dependencies on Android
        if (Application.platform == RuntimePlatform.Android && !Application.isEditor)
        {
            Debug.Log("Checking dependencies on Android");
            var checkDependencies = new TaskYieldInstruction<DependencyStatus>(FirebaseApp.CheckDependenciesAsync());
            yield return checkDependencies;
            Debug.Log($"Check Dependencies: {checkDependencies.Result}");
        }

        _databaseReference = FirebaseDatabase.DefaultInstance.RootReference;
    }

    /// <summary>
    /// Safely gets a database reference at the given path
    /// </summary>
    /// <param name="path">The path at which to get a reference</param>
    /// <returns>A yield instruction that can be yielded in a coroutine</returns>
    public GetDatabaseReferenceYieldInstruction GetDatabaseReference(string path)
    {
        return new GetDatabaseReferenceYieldInstruction(path, _setupFirebase);
    }

    /// <summary>
    /// Asynchronously gets a database reference at the given path after a predicate executes
    /// </summary>
    public class GetDatabaseReferenceYieldInstruction : IEnumerator
    {
        private IEnumerator _predicate;
        private readonly string _path;
        public DatabaseReference Root { get; private set; }

        public GetDatabaseReferenceYieldInstruction(string path, IEnumerator predicate)
        {
            _path = path;
            _predicate = predicate;
        }
        
        public bool MoveNext()
        {
            if (_predicate != null)
            {
                if (_predicate.MoveNext())
                {
                    return true;
                }

                _predicate = null;
                
                // TODO: this is a cross cutting concern to inject
                Root = FirebaseDatabase.DefaultInstance.RootReference.Child(_path);
            }

            return false;
        }

        public void Reset()
        {
        }

        public object Current => Root;
    }
}

Which you can use like this:

[SerializeField] private FirebaseSingleton _firebaseSingleton;
public void Awake()
{
    _firebase = _firebaseSingleton.Instance;
    _getDatabase = _firebase.GetDatabaseReference(DatabaseName);
}

private IEnumerator RegisterForEvents()
{
    yield return _getDatabase;
    _getPigDatabase.Root.ValueChanged += HandlePigValuesChanged;
}
  1. With Unity's new DOTS system, I've been flirting with the idea of moving Unity's initialization into the OnCreate function for a system. Because you have a clean entrypoint, you'd be able to block Firebase functionality until it comes online, and you could control Firebase by injecting specific entities into the world with custom Firebase-specific components on it. I don't have a good example yet, although it's on my project backlog.
like image 174
Patrick Martin Avatar answered Nov 09 '25 08:11

Patrick Martin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!