Closed og1337og closed 1 year ago
This issue does not seem to follow the issue template. Make sure you provide all the required information.
Fixed post to follow Template for the bot.
Hi @og1337og,
Thanks for reporting this issue. Based on the code you provided, it seems that you're declaring two Firestore instances in your app. This may be related to an issue (#928) with how persistence is implemented when running on desktop.
Could you confirm if disabling persistence makes a difference? You may do so by adding something like:
#if UNITY_EDITOR
FirebaseFirestore.DefaultInstance.Settings.PersistenceEnabled = false;
#endif
If the crash still occurs, please provide your Player.log
file.
Additionally, does the crash occur using an Android build?
Hello, Yes the issues was that I was calling two default instances. One for Auth to handle User Login, Register and UID check for Documnet Name but also another for the Firestore Database to have a listener on the user's database info. The 2 of them running at the same time using
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(async task => { }
in the Awake function was not compatible with 2 of them on the desktop and was freezing the app when testing in the editor.
Also, you were right, changing the build to Android allowed it to run without freezing. The only issue I had was it only allowed auth login and register and the write to firestore but the listener to read from firestore as updates came in was not working. I guess because it wouldn't allow two instances?
So I altered the code by adding the Get Player Data script to the Auth script both the declarations and the start function. Then modified the Awake function to
async void Awake() { //Check that all of the necessary dependencies for Firebase are present on the system // FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(async task => // { var dependencyStatus = await FirebaseApp.CheckAndFixDependenciesAsync(); if (dependencyStatus == DependencyStatus.Available) { //If they are avalible Initialize Firebase InitializeFirebase(); } else { Debug.LogError("Could not resolve all Firebase dependencies: " + dependencyStatus); } // }); }
You can see that I changed it to an async void Awake() and removed the
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(async task => { }
The last thing I did was I added "await" in front of the FirebaseApp.CheckAndFixDependenciesAsync();
Using this method I can now run the game in Unity editor without the game freezing and it runs on Desktop using both an Auth DefaultInstance and a Firestore DefaultInstance so I can register a new user, update the Firestore database with their info and and use the listener on button click to update that information on their screen and still login in and out again with out any interference from either Firebase product. Thank you so much for taking time to help. Without error codes I felt lost, I hope this code helps others trying to run authentication and Firestore at the same time and run into this problem that want to keep being able to test in the editor. Thank you again.
Glad to hear that you've found a solution, @og1337og. I'll be closing this for now. Let me know if a new issue arises with this,
The work around unfortunatley only works on desktop. On android neither one works. When I added the FirebaseFirestore.DefaultInstance.Settings.PersistenceEnabled = false; in the awake method like you recomended the application stops crashing in the editor but on android only Firebase Authentication works. Its like this bit of code just disabled Firestore when using that line of code. Is there some workaround for this because at this point I don't think it is possible to use both Firestore and Authentication in the same app due to the default instance being required for both Firestore as db and Authentication as auth.
Hi @og1337og,
Were you able to include the conditional compilation for the Unity editor (#if UNITY_EDITOR
) in your code? That should ensure that the persistence is only disabled when using the editor.
Also, when you mentioned "neither one works", do you mean that Firestore doesn't function regardless whether the workaround is there or not?
If the issue is still there, it would be helpful if you share a minimal, reproducible example of your implementation so that we could analyze this behavior.
Hello
The "neither one works" was in reference to the workaround I tried before that I thought worked but only worked on desktop, not in regards to the work around you suggested.
I did add all of what you said. At the start of the Awake function I added
FirebaseFirestore.DefaultInstance.Settings.PersistenceEnabled = false;
Like you recommended. This makes both work on desktop, just a delay on the write to firestore but can still register users and login. Unfortunately when using the android build Firestore no longer works and does not let me write to the database but Register and Login still work.
Here is just the parts of the code that would be relevant for reference 0 Declerations 1 Awake 2 Start 3 Initialize Firebase 4 AuthStateChanged 5 Register 6 Write to Firestore
//Relevant Declarations public FirebaseAuth auth; public FirebaseUser user; FirebaseFirestore db; Dictionary<string, object> users;
//Relevant code //Awake, Start, Initialize Firebase, AuthStateChanged, Register, Write to Firestore
private void Awake() {
FirebaseFirestore.DefaultInstance.Settings.PersistenceEnabled = false;
DontDestroyOnLoad(gameObject);
if (instance == null)
{
instance = this;
}
else if (instance != this)
{
Destroy(instance.gameObject);
instance = this;
}
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(checkDependancyTask =>
{
var dependancyStatus = checkDependancyTask.Result;
if (dependancyStatus == DependencyStatus.Available)
{
InitializeFirebase();
}
else
{
Debug.LogError($"Could not resolve all Firebase dependencies: {dependancyStatus}");
}
});
}
private void Start()
{
db = FirebaseFirestore.DefaultInstance;
}
private void InitializeFirebase() { auth = FirebaseAuth.DefaultInstance;
auth.StateChanged += AuthStateChanged;
AuthStateChanged(this, null);
}
private void AuthStateChanged(object sender, System.EventArgs eventArgs)
{
if(auth.CurrentUser != null)
{
bool signedIn = user != auth.CurrentUser && auth.CurrentUser != null;
if(!signedIn && user != null)
{
Debug.Log("Signed Out");
}
user = auth.CurrentUser;
if (signedIn)
{
Debug.Log($"Signed In: {user.DisplayName}");
}
}
}
//Register Method private IEnumerator RegisterLogic(string _username, string _email, string _password, string _confirmPassword) { if(_username == "") { registerOutputText.text = "Please Enter A Username"; } else if (_password != _confirmPassword) { registerOutputText.text = "Passwords Do Not Match"; } else { var registerTask = auth.CreateUserWithEmailAndPasswordAsync(_email, _password);
yield return new WaitUntil(predicate: () => registerTask.IsCompleted);
if(registerTask.Exception != null)
{
FirebaseException firebaseException = (FirebaseException)registerTask.Exception.GetBaseException();
AuthError error = (AuthError)firebaseException.ErrorCode;
string output = "Unkown Error, Please Try Again";
switch (error)
{
case AuthError.InvalidEmail:
output = "Invalid Email";
break;
case AuthError.EmailAlreadyInUse:
output = "Email Already In Use";
break;
case AuthError.WeakPassword:
output = "Weak Password";
break;
case AuthError.MissingEmail:
output = "Please Enter Your Email";
break;
case AuthError.MissingPassword:
output = "Please Enter Your Password";
break;
}
registerOutputText.text = output;
}
else
{
UserProfile profile = new UserProfile
{
DisplayName = _username,
//TODO Give Profile Default Photo
};
var defaultUserTask = user.UpdateUserProfileAsync(profile);
yield return new WaitUntil(predicate: () => defaultUserTask.IsCompleted);
if (defaultUserTask.Exception != null)
{
user.DeleteAsync();
FirebaseException firebaseException = (FirebaseException)defaultUserTask.Exception.GetBaseException();
AuthError error = (AuthError)firebaseException.ErrorCode;
string output = "Unkown Error, Please Try Again";
switch (error)
{
case AuthError.Cancelled:
output = "Update User Cancelled";
break;
case AuthError.SessionExpired:
output = "Session Expired";
break;
}
registerOutputText.text = output;
}
else
{
Debug.Log($"Firebase User Created Successfully: {user.DisplayName} ({user.UserId})");
//ToDo: Send Verification Email
}
}
}
}
//Write to FireStore Method
public void WriteStuff() { DocumentReference docRef = db.Collection("cities").Document("LA"); Dictionary<string, object> city = new Dictionary<string, object> { { "Name", "Los Angeles" }, { "State", "CA" }, { "Country", "USA" } }; docRef.SetAsync(city).ContinueWithOnMainThread(task => { Debug.Log("Added data to the LA document in the cities collection."); }); }
Hi @og1337og,
So far, I haven't successfully built and replicated the issue. Is it possible for you to upload a sample project that reproduces the issue? You may do so by uploading this to a GitHub repository and adding me as a collaborator.
I've created a repository that has the scripts used and the scenes used in the build and added you as a collaborator. Please let me know if there is anything else I can do to help. Thank you.
Thanks for this, @og1337og. I'm getting a warning that a certain AuthManager
is missing. Could you confrim if this script is needed?
The AuthManager is not being used currently, I instead am using the Auth script instead but I added the old AuthManager script now for reference to the repository if that helps.
Hi @og1337og,
After tinkering the repository you provided to make a working Unity project, I was able to replicate the issue you're facing. Upon inspecting your code, I noticed that Auth is being initialized in Awake()
function while Firestore is being initialized in Start()
function. Take note that Awake is called when an active GameObject that contains the script is initialized when a Scene loads while Start is called on the frame when a script is enabled.
With that, Firestore should work when you place its initializtion (followed by the conditional compilation) after the Auth initialization in the Awake()
function. It should look something like this:
private void InitializeFirebase()
{
auth = FirebaseAuth.DefaultInstance;
db = FirebaseFirestore.DefaultInstance;
#if UNITY_EDITOR
db.Settings.PersistenceEnabled = false;
#endif
...
}
Let me know if the solution doesn't apply to your use case or if an issue arises.
Hello, thank you so much that was 100% the problem calling one in the awake and one in the start. Works 100% now.
[REQUIRED] Please describe the issue here:
Followed the tutorial on the firebase youtube channel for Firestore listener that updates on firestore and on the game as a text field using a getCharacterData script that uses a characterData struct to listen for updates and a setCharacterData script for writing to firestore from input fields on button press. The game also has a Login and Registration function with Firebase Authentication in a seperate Auth script. Both the set of 3 Firestore Scripts and the 1 Authentication scripts work fine alone. The issue that keeps occurring is when both are included the unity editor freezes when running the game to test. Removing either of them solves this for the other. Is there a way to use Authentication and FireStore in the same App that will resolve this issue? I get no error codes. The editor just freezes on run. :/ Based on it crashing I assume the issue is the start function setting firestore as a default instance of firebase and running the listener on the GetPlayerData Script or the Initialize Firebase on the Awake function for Authentication on the Auth script. I am guessing they are clashing since removing the game object with the scripts solves the issues for the other and does not crash the game when running the unity editor. Sorry if this was too detailed or not detailed enough, this is my first question on here, I have honestly tried so hard to make this work and have hit a full dead end with no error codes to guide me and no documentation that solves this issue. Any help would be greatly appreciated.
Steps to reproduce:
Running a firestore listener with an authentication script and running the game in unity crashes unity
Relevant Code:
//Firestore Get Player Data Listener code snippet private ListenerRegistration listenerRegistration;
//Awake and Initialize Firebase Functions for Auth
void Awake() { //Check that all of the necessary dependencies for Firebase are present on the system FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => { dependencyStatus = task.Result; if (dependencyStatus == DependencyStatus.Available) { //If they are avalible Initialize Firebase InitializeFirebase(); } else { Debug.LogError("Could not resolve all Firebase dependencies: " + dependencyStatus); } }); }
//Code to reproduce
//The PlayerData Struct used for listener
[FirestoreData]
public struct PlayerData { [FirestoreProperty]
}
//The Set Player Data Script
public class SetPlayerData : MonoBehaviour {
}
//Get Player Data Script
public class GetPlayerData : MonoBehaviour { [SerializeField] private string playerPath = "Users/Player1";
} //End of Firestore Scripts
//The Auth Script
public class Auth : MonoBehaviour { //Firebase variables [Header("Firebase")] public DependencyStatus dependencyStatus; public FirebaseAuth auth; public FirebaseUser User;
}