如何在Unity中的哪里放置Firebase Check and Fix Dependencies代码?

问题描述

我想在Unity游戏中使用Firebase,因此步骤之一是添加以下代码,但未指定应添加代码的位置。有帮助吗?

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.
  }
});

(这是Firebase上的说明的链接) https://firebase.google.com/docs/unity/setup?authuser=0#confirm-google-play-version

解决方法

我能给出的最佳答案是在Unity中“先做其他事情”。

在普通应用程序中,您会遇到类似主api入口点(iOS中为application:didFinishLaunchingWithOptions,Android中为Activity.onCreate或典型C / C ++桌面中为void main(int,char**)的东西。应用)。但是在Unity中,您没有任何“先执行此操作”逻辑。哪种情况取决于您,并且可能会发生变化,并且脚本大致并行执行(最好以随机的顺序执行,但从技术上讲可以顺序执行)。

以下是我使用过或考虑过使用的模式以及一些相关的利弊:

  1. [推荐给初学者和小型项目]在我的视频中,我通常建议使用“加载”或“设置”场景。在该场景中,我放置了一个FirebaseInit脚本,该脚本将初始化Firebase并在完成后引发一个事件。然后,我可以收集一堆初始化功能(例如下载资产捆绑包或进行一些初始设置处理),也可以立即进入我的主要场景。在大多数情况下,这会变为无操作状态(在Android Play服务上是最新的),因此,如果您小心一点,甚至可以在主菜单中将其推入:
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. 我不是依赖注入的主要支持者(因为我通常不使用DI框架,但是我确实倾向于使用[SerializedField]作为伪DI系统)没有可供分享的示例。您可以使用ZenJect创建Firebase单例并将其注入任何需要它们的对象。您遇到的最大问题是,您必须等待要初始化的依赖项,这是可能的,但我只是没有在示例项目中完成这些步骤。好处是您只需要表达“我依赖Firebase”,ZenJect将负责其余的工作(在这种情况下,只需避免使用DefaultInstance函数即可。

  2. 在更复杂的项目中,我倾向于将Firebase包装在Coroutine中(或异步任务,但我更喜欢Unity中的协程)。因此,我将有一个Coroutine,它将等待检查和修复依赖项完成,并在完成时返回Realtime Database实例(并在必要时使用智能逻辑跳过该等待)。同样,您必须避免在管理脚本之外使用DefaultInstance,并且Firebase的每次使用都会成为协程,但是您可以确保始终等待构建。这是一个专注于实时数据库的示例(我正在剥离不必要的代码以使其适合SO答案),并且我重申,这对于一个小型项目来说是很多开销:

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;
    }
}

您可以这样使用:

[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. 对于Unity's new DOTS system,我一直在想将Unity的初始化转移到系统的OnCreate函数中。因为您拥有一个干净的入口点,所以您可以阻止Firebase功能,直到它联机为止,并且您可以通过将特定的实体注入到具有自定义Firebase特定组件的世界来控制Firebase。尽管尚在我的项目积压中,但我还没有一个很好的例子。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...