firebase / quickstart-unity

Firebase Quickstart Samples for Unity
https://firebase.google.com/games
Apache License 2.0
836 stars 430 forks source link

[Bug] Unity Editor Freezes when I press play after updating Firebase to 8.2.0 and fixing deprecated code in RemoteConfig #1147

Closed nhhuynh closed 3 years ago

nhhuynh commented 3 years ago

[REQUIRED] Please fill in the following fields:

[REQUIRED] Please describe the issue here:

Unity Editor Freezes when I press play after updating Firebase to 8.2.0 and fixing deprecated code in RemoteConfig

  1. Upgrade firebase by dragging in unity packages.
    • Add androidPackage spec="com.google.firebase:firebase-inappmessaging-display:20.1.0"> </androidPackage to messagingDependencies script
  2. Used Android Resolver to resolve dependencies.
  3. Fixed old script to work with new version of Firebase remote config.

(Please list the full steps to reproduce the issue. Include device logs, Unity logs, and stack traces if available.)

Steps to reproduce:

Have you been able to reproduce this issue with just the Firebase Unity quickstarts (this GitHub project)? I have not tried reproducing on the quickstarts project yet.

What's the issue repro rate? (eg 100%, 1/5 etc) 100%

What happened? How can we make the problem occur? This could be a description, log/console output, etc.

  1. Upgrade firebase by dragging in unity packages.
    • Add to messagingDependencies script
  2. Used Android Resolver to resolve dependencies.
  3. Fixed old script to work with new version of Firebase remote config.(check code snippet to see changes made)

If you have a downloadable sample project that reproduces the bug you're reporting, you will likely receive a faster response on your issue.

Relevant Code:

// TODO(you): code here to reproduce the problem

Old Script before changes(Has deprecated code):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Firebase.Extensions;
using System.Threading.Tasks;
using System;
using Constants;
using Firebase.RemoteConfig;

public class RemoteConfig : Singleton<RemoteConfig>
{
    protected bool IsServerRemoteConfigInitialized = false;
    protected bool IsDefaultRemoteConfigInitialized = false;

    private readonly string RecordRemoteConfigFunc = "recordRemoteConfig";

    private FirebaseManager firebaseManager;

    private UserDataManager userDataManager;

    private Dictionary<string, string> cachedRemoteData = new Dictionary<string, string>();

    private void Awake()
    {
        Debug.Log("RemoteConfig.Awake()");
        // Init
        firebaseManager = FirebaseManager.Instance;

    }

    private void OnDestroy() {
        UserDataManager.UserSignin -= OnUserSignin;
    }

    // Start is called before the first frame update
    IEnumerator Start()
    {
        ULog.Log("RemoteConfig.cs: Start()");
        userDataManager = UserDataManager.Instance;
        UserDataManager.UserSignin += OnUserSignin;
        //If this is in the editor, we will use developer mode for testing
        //which will stop throttling issues
#if UNITY_EDITOR
        ConfigSettings cs = FirebaseRemoteConfig.Settings;
        cs.IsDeveloperMode = true;
        FirebaseRemoteConfig.Settings = cs;
#endif

        InitializeDefaults();
        while (!IsDefaultRemoteConfigInitialized) {
            yield return null;
        }
        UpdateConfigs();
    }

// Initialize remote config, and set the default values.
    void InitializeDefaults() {
        ULog.Log("RemoteConfig.cs: InitializeDefaults() - Initializing...");
        Dictionary<string, object> defaults = new Dictionary<string, object>();
        // These are the values that are used if we haven't fetched data from the
        // server yet, or if we ask for values that the server doesn't have:
        InitializeDefaults(defaults);
        FirebaseRemoteConfig.SetDefaults(defaults);
        ULog.Log("RemoteConfig.cs: InitializeDefaults() - RemoteConfig defaults are set.");
        IsDefaultRemoteConfigInitialized = true;
    }

    private void InitializeDefaults(Dictionary<string, object> defaults) {
        //If we cannot get this value, then we assume the current build num
        //as the default
        defaults.Add(Configs.LATEST_LIVE_BUILD, Application.version);
        defaults.Add(Configs.INTERSTITIAL_RATE, -1.0f);
        defaults.Add(Configs.MAX_AUTH_ATTEMPTS, 5);
        defaults.Add(Configs.AUTH_WAIT_TIME_MINUTES, 2);
    }

    public bool IsReady()
    {
        return IsServerRemoteConfigInitialized;
    }

    public void UpdateConfigs() {
        ULog.Log("RemoteConfig.cs: UpdateConfigs()");
        if (IsDefaultRemoteConfigInitialized)
        {
            FetchDataAsync();
        }
    }

    private Task FetchDataAsync() {
        ULog.Log("RemoteConfig.cs: FetchDataAsync() - Fetching data...");
        // FetchAsync only fetches new data if the current data is older than the provided
        // timespan.  Otherwise it assumes the data is "recent enough", and does nothing.
        // By default the timespan is 12 hours, and for production apps, this is a good
        // number.  For this example though, it's set to a timespan of zero, so that
        // changes in the console will always show up immediately.

        //We also have a special case where we use a timespan zero fetch for the first pull
        //on a new build
        Task fetchTask;
        if (PlayerPrefs.GetString(Constants.Prefs.LAST_APPLICATION_VERSION, "") != Application.version)
        {
            fetchTask = FirebaseRemoteConfig.FetchAsync(TimeSpan.Zero);
        }
        else
        {
#if UNITY_EDITOR
            fetchTask = FirebaseRemoteConfig.FetchAsync(TimeSpan.Zero);
#else
            fetchTask = FirebaseRemoteConfig.FetchAsync();
#endif
        }

        //Set application version in player prefs to match current so that we don't keep fetching
        //causing a throttle from Google
        PlayerPrefs.SetString(Constants.Prefs.LAST_APPLICATION_VERSION, Application.version);

        return fetchTask.ContinueWithOnMainThread(FetchComplete);
    }

    void FetchComplete(Task fetchTask) {
      if (fetchTask.IsCanceled) {
        ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch canceled.");
      } else if (fetchTask.IsFaulted) {
        ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch encountered an error. Timespan may not be done.");
      } else if (fetchTask.IsCompleted) {
        ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch completed successfully!");
      }
      //Ready = true;
      var info = FirebaseRemoteConfig.Info;
      switch (info.LastFetchStatus) {
        case LastFetchStatus.Success:
                ActivateAndRecord();
          ULog.Log(string.Format("RemoteConfig.cs: FetchComplete() - Remote data loaded and ready (last fetch time {0}).",
                                 info.FetchTime));
          break;
        case LastFetchStatus.Failure:
          switch (info.LastFetchFailureReason) {
            case FetchFailureReason.Error:
              ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch failed for unknown reason");
              break;
            case FetchFailureReason.Throttled:
              ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch throttled until " + info.ThrottledEndTime);
              break;
          }
          break;
        case LastFetchStatus.Pending:
          ULog.Log("RemoteConfig.cs: FetchComplete() - Latest Fetch call still pending.");
          break;
        default:
          ULog.Log("RemoteConfig.cs: FetchComplete() - Default case - remote config status: " + info.LastFetchStatus);
          break;
        }
        ULog.Log("RemoteConfig.cs: Remote Config is ready!");
      IsServerRemoteConfigInitialized = true;
    }

    private void ActivateAndRecord()
    {
        IsServerRemoteConfigInitialized = true;
        if (FirebaseRemoteConfig.ActivateFetched())
        {
            ULog.Log("RemoteConfig.cs: ActivateAndRecord() - Recording");
            //Send remoteconfig to the back end for later use
            SendData();
        }
        else
        {
            ULog.Log("RemoteConfig.cs: ActivateAndRecord() - Activate failed");
        }
    }

    private void OnUserSignin(UserEventArgs args) {
        //new user. clear the cache, send configs to server
        cachedRemoteData = new Dictionary<string, string>();
        UpdateConfigs();
        //try to send again just in case sending failed
        SendData();
    }

    private void SendData() {
        ULog.Log("RemoteConfig.cs: SendData()");
        if(userDataManager.IsSignedIn()) {
            Dictionary<string, string> remotedata = new Dictionary<string, string>();
            foreach (string key in FirebaseRemoteConfig.Keys)
            {
                remotedata[key] = FirebaseRemoteConfig.GetValue(key).StringValue;
            }

            //compare to see if any values have changed
            if (!doesDictMatchCache(remotedata))
            {
                Debug.Log("RemoteConfig.SendData() changes being sent");
                //encapsulate dictionary into child
                Dictionary<string, object> data = new Dictionary<string, object>();
                data["remoteConfig"] = remotedata;
                firebaseManager.CallHttpsFunctionAsync(RecordRemoteConfigFunc, data);
                cachedRemoteData = remotedata;
            }
            else
            {
                Debug.Log("RemoteConfig.SendData() no changes to remotes detected");
            }
        }
    }

    private bool doesDictMatchCache(Dictionary<string, string> remotedata)
    {
        if (remotedata.Count != cachedRemoteData.Count)
        {
            Debug.Log("RemoteConfig.doesDictMatchCache() count mismatch");
            return false;
        }

        foreach(string key in remotedata.Keys)
        {
            string cached;
            if(!cachedRemoteData.TryGetValue(key, out cached))
            {
                Debug.Log("RemoteConfig.doesDictMatchCache() value missing");
                return false;
            }

            if(remotedata[key].ToString()!=cached.ToString())
            {
                Debug.Log("RemoteConfig.doesDictMatchCache() value mismatch");
                return false;
            }
        }

        return true;
    }

    public string GetConfig(string config) {
        return FirebaseRemoteConfig.GetValue(config).StringValue;
    }

}

NEW CODE WITH CHANGES:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Firebase.Extensions;
using System.Threading.Tasks;
using System;
using Constants;
using Firebase.RemoteConfig;

public class RemoteConfig : Singleton<RemoteConfig>
{
    protected bool IsServerRemoteConfigInitialized = false;
    protected bool IsDefaultRemoteConfigInitialized = false;

    private readonly string RecordRemoteConfigFunc = "recordRemoteConfig";

    private FirebaseManager firebaseManager;

    private UserDataManager userDataManager;

    private Dictionary<string, string> cachedRemoteData = new Dictionary<string, string>();

    private void Awake()
    {
        Debug.Log("RemoteConfig.Awake()");
        // Init
        firebaseManager = FirebaseManager.Instance;

    }

    private void OnDestroy() {
        UserDataManager.UserSignin -= OnUserSignin;
    }

    // Start is called before the first frame update
    IEnumerator Start()
    {
        ULog.Log("RemoteConfig.cs: Start()");
        userDataManager = UserDataManager.Instance;
        UserDataManager.UserSignin += OnUserSignin;
        //If this is in the editor, we will use developer mode for testing
        //which will stop throttling issues
#if UNITY_EDITOR
        ConfigSettings cs = FirebaseRemoteConfig.DefaultInstance.ConfigSettings;
        cs.MinimumFetchInternalInMilliseconds = 0; // new way to set to developer mode
        //cs.IsDeveloperMode = true;
        FirebaseRemoteConfig.DefaultInstance.SetConfigSettingsAsync(cs);
#endif

        InitializeDefaults();
        while (!IsDefaultRemoteConfigInitialized) {
            yield return null;
        }
        UpdateConfigs();
    }

// Initialize remote config, and set the default values.
    void InitializeDefaults() {
        ULog.Log("RemoteConfig.cs: InitializeDefaults() - Initializing...");
        Dictionary<string, object> defaults = new Dictionary<string, object>();
        // These are the values that are used if we haven't fetched data from the
        // server yet, or if we ask for values that the server doesn't have:
        InitializeDefaults(defaults);
        FirebaseRemoteConfig.DefaultInstance.SetDefaultsAsync(defaults);
        //FirebaseRemoteConfig.SetDefaults(defaults);
        ULog.Log("RemoteConfig.cs: InitializeDefaults() - RemoteConfig defaults are set.");
        IsDefaultRemoteConfigInitialized = true;
    }

    private void InitializeDefaults(Dictionary<string, object> defaults) {
        //If we cannot get this value, then we assume the current build num
        //as the default
        defaults.Add(Configs.LATEST_LIVE_BUILD, Application.version);
        defaults.Add(Configs.INTERSTITIAL_RATE, -1.0f);
        defaults.Add(Configs.MAX_AUTH_ATTEMPTS, 5);
        defaults.Add(Configs.AUTH_WAIT_TIME_MINUTES, 2);
    }

    public bool IsReady()
    {
        return IsServerRemoteConfigInitialized;
    }

    public void UpdateConfigs() {
        ULog.Log("RemoteConfig.cs: UpdateConfigs()");
        if (IsDefaultRemoteConfigInitialized)
        {
            FetchDataAsync();
        }
    }

    private Task FetchDataAsync() {
        ULog.Log("RemoteConfig.cs: FetchDataAsync() - Fetching data...");
        // FetchAsync only fetches new data if the current data is older than the provided
        // timespan.  Otherwise it assumes the data is "recent enough", and does nothing.
        // By default the timespan is 12 hours, and for production apps, this is a good
        // number.  For this example though, it's set to a timespan of zero, so that
        // changes in the console will always show up immediately.

        //We also have a special case where we use a timespan zero fetch for the first pull
        //on a new build
        Task fetchTask;
        if (PlayerPrefs.GetString(Constants.Prefs.LAST_APPLICATION_VERSION, "") != Application.version)
        {
            fetchTask = FirebaseRemoteConfig.DefaultInstance.FetchAsync(TimeSpan.Zero);
            //fetchTask = FirebaseRemoteConfig.FetchAsync(TimeSpan.Zero);
        }
        else
        {
#if UNITY_EDITOR
            fetchTask = FirebaseRemoteConfig.DefaultInstance.FetchAsync(TimeSpan.Zero);
            //fetchTask = FirebaseRemoteConfig.FetchAsync(TimeSpan.Zero);
#else
            fetchTask = FirebaseRemoteConfig.DefaultInstance.FetchAsync();
            //fetchTask = FirebaseRemoteConfig.FetchAsync();
#endif
        }

        //Set application version in player prefs to match current so that we don't keep fetching
        //causing a throttle from Google
        PlayerPrefs.SetString(Constants.Prefs.LAST_APPLICATION_VERSION, Application.version);

        return fetchTask.ContinueWithOnMainThread(FetchComplete);
    }

    void FetchComplete(Task fetchTask) {
      if (fetchTask.IsCanceled) {
        ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch canceled.");
      } else if (fetchTask.IsFaulted) {
        ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch encountered an error. Timespan may not be done.");
      } else if (fetchTask.IsCompleted) {
        ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch completed successfully!");
      }
      //Ready = true;
      var info = FirebaseRemoteConfig.DefaultInstance.Info;
      switch (info.LastFetchStatus) {
        case LastFetchStatus.Success:
                ActivateAndRecord();
          ULog.Log(string.Format("RemoteConfig.cs: FetchComplete() - Remote data loaded and ready (last fetch time {0}).",
                                 info.FetchTime));
          break;
        case LastFetchStatus.Failure:
          switch (info.LastFetchFailureReason) {
            case FetchFailureReason.Error:
              ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch failed for unknown reason");
              break;
            case FetchFailureReason.Throttled:
              ULog.Log("RemoteConfig.cs: FetchComplete() - Fetch throttled until " + info.ThrottledEndTime);
              break;
          }
          break;
        case LastFetchStatus.Pending:
          ULog.Log("RemoteConfig.cs: FetchComplete() - Latest Fetch call still pending.");
          break;
        default:
          ULog.Log("RemoteConfig.cs: FetchComplete() - Default case - remote config status: " + info.LastFetchStatus);
          break;
        }
        ULog.Log("RemoteConfig.cs: Remote Config is ready!");
      IsServerRemoteConfigInitialized = true;
    }

    private void ActivateAndRecord()
    {
        IsServerRemoteConfigInitialized = true;
        if (FirebaseRemoteConfig.DefaultInstance.ActivateAsync().Result)
        {
            ULog.Log("RemoteConfig.cs: ActivateAndRecord() - Recording");
            //Send remoteconfig to the back end for later use
            SendData();
        }
        else
        {
            ULog.Log("RemoteConfig.cs: ActivateAndRecord() - Activate failed");
        }
    }

    private void OnUserSignin(UserEventArgs args) {
        //new user. clear the cache, send configs to server
        cachedRemoteData = new Dictionary<string, string>();
        UpdateConfigs();
        //try to send again just in case sending failed
        SendData();
    }

    private void SendData() {
        ULog.Log("RemoteConfig.cs: SendData()");
        if(userDataManager.IsSignedIn()) {
            Dictionary<string, string> remotedata = new Dictionary<string, string>();
            foreach (string key in FirebaseRemoteConfig.DefaultInstance.Keys)
            {
                remotedata[key] = FirebaseRemoteConfig.DefaultInstance.GetValue(key).StringValue;
            }

            //compare to see if any values have changed
            if (!doesDictMatchCache(remotedata))
            {
                Debug.Log("RemoteConfig.SendData() changes being sent");
                //encapsulate dictionary into child
                Dictionary<string, object> data = new Dictionary<string, object>();
                data["remoteConfig"] = remotedata;
                firebaseManager.CallHttpsFunctionAsync(RecordRemoteConfigFunc, data);
                cachedRemoteData = remotedata;
            }
            else
            {
                Debug.Log("RemoteConfig.SendData() no changes to remotes detected");
            }
        }
    }

    private bool doesDictMatchCache(Dictionary<string, string> remotedata)
    {
        if (remotedata.Count != cachedRemoteData.Count)
        {
            Debug.Log("RemoteConfig.doesDictMatchCache() count mismatch");
            return false;
        }

        foreach(string key in remotedata.Keys)
        {
            string cached;
            if(!cachedRemoteData.TryGetValue(key, out cached))
            {
                Debug.Log("RemoteConfig.doesDictMatchCache() value missing");
                return false;
            }

            if(remotedata[key].ToString()!=cached.ToString())
            {
                Debug.Log("RemoteConfig.doesDictMatchCache() value mismatch");
                return false;
            }
        }

        return true;
    }

    public string GetConfig(string config) {
        return FirebaseRemoteConfig.DefaultInstance.GetValue(config).StringValue;
    }

}
paulinon commented 3 years ago

Hi @nhhuynh,

Thanks for letting us know about this issue. In order to identify what's causing this, could you provide a minimal, reproducible example of your project? I can't seem to replicate the issue with just the code you provided.

nhhuynh commented 3 years ago

Hi @paulinon, I wasn't able to reproduce the problem within a different project. I did manage to narrow down where the issue is freezing. It calls freezes on this line: return fetchTask.ContinueWithOnMainThread(FetchComplete); None of the debug logs inside FetchComplete get outputted. I'm thinking that it is a problem with the fetch? Do you have any ideas of what could be happening?

paulinon commented 3 years ago

Hi @nhhuynh,

That line of code can also be found in our quickstart when you click "Fetch Remote Data". Could you confirm if your Unity editor freezes when using the quickstart as well?

nhhuynh commented 3 years ago

@paulinon I tried it in the quickstart project, but the editor does not freeze. It is able to fetch and display data using the UIHandler buttons.

paulinon commented 3 years ago

Hi @nhhuynh,

Could you try if version 8.3.0 of the SDK makes a difference? If it doesn't, it's possible that the cause of the issue lies within your implementation, and a minimal, reproducible example is needed in identifying what's causing this.

nhhuynh commented 3 years ago

@paulinon I've tried updating to v8.3.0 before creating this thread, but It didn't change anything. I looked into unity editor logs and this is what appears when the editor freezes:

''' (Filename: Assets/BlingSDK/Scripts/Logging/ULog.cs Line: 62)

Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.dylib Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.so Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.dylib Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.so Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.dylib Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.so Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.dylib Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.so Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.dylib Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.so Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.dylib Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle.so Fallback handler could not load library /Applications/Unity/Hub/Editor/2020.3.18f1/Unity.app/Contents/Frameworks/Mono/lib/libAssets/Firebase/Plugins/x86_64/FirebaseCppApp-8_2_0.bundle '''

nhhuynh commented 3 years ago

I found a similar issue here

https://github.com/firebase/quickstart-unity/issues/628

As per the instructions in that thread I attached XCode to the Unity process and got the debug info after freeze:

(lldb) bt all

paulinon commented 3 years ago

Hi @nhhuynh,

It would be great if you could provide a minimal, reproducible example of your project so that we can isolate the cause of your issue and hopefully find a solution. You may upload this in a GitHub repository and add me as a collaborator.

nhhuynh commented 3 years ago

@paulinon

I reproduced the issue in the quickstart project and invited you as a collaborator

nhhuynh commented 3 years ago

Thank you for your help. I ended up figuring out the bug: Needed to add this to the fetchcomplete method

Firebase.RemoteConfig.FirebaseRemoteConfig.DefaultInstance.ActivateAsync()
                        .ContinueWithOnMainThread(task => {
                            IsServerRemoteConfigInitialized = true;
                            if (task.Result)
                            {
                                ULog.Log("RemoteConfig.cs: ActivateAndRecord() - Recording");
                            //Send remoteconfig to the back end for later use
                            SendData();
                            }
                            else
                            {
                                ULog.Log("RemoteConfig.cs: ActivateAndRecord() - Activate failed");
                            }
                            ULog.Log(string.Format("RemoteConfig.cs: FetchComplete() - Remote data loaded and ready (last fetch time {0}).",
                                               info.FetchTime));
                        });

Turns out that just calling FirebaseRemoteConfig.DefaultInstance.ActivateAsync().Result caused a deadlock and would freeze the editor