- Home /
Solved with other methods
C# function continues without waiting for called Google Play method to complete
Okay maybe I'm just missing something blatantly obvious here and sorry if that's the case, but I'm stumped. I'm trying to adjust my Google Play Services log-in and cloud save system to have a little more flexibility. This is my code (I'll only provide the relevant sections):
void Start () {
ActivateSocialPlatform ();
LoginSuccess = false;
Login ();
}
private void Login(){
DebugText.text += "Starting login process \n";
GooglePlaySignIn ();
if (LoginSuccess == true) {
LoadData();
} else {
DebugText.text += "Something went wrong \n";
}
}
public void GooglePlaySignIn(){
DebugText.text += "Signing into Google Play \n";
Social.localUser.Authenticate ((bool success) => {
if (success) {
DebugText.text += "Google Play authentification success \n";
LoginSuccess = true;
} else {
DebugText.text += "Google Play authentification failed \n";
LoginSuccess = false;
}
});
}
Basically, I call Login() to start the authentification process in GooglePlaySignIn(), which is supposed to set the variable LoginSuccess either true or false, and if it's true, I start loading savedata from the cloud. However I end up with a log like this:
Activating Social Platform
Starting login process
Signing into Google Play
Something went wrong
Google Play authentification success
As I understand, for some reason the function Login() doesn't wait until GooglePlaySignIn() completes and continues into the false state, AFTER which the user is actually signed on. Why does this happen? I thought all functions are supposed to wait until their called functions complete before continuing with their own code? Everything works just fine if I place the authentification code inside Login() itself, instead of having it in a separate function. I want to be able to reuse this code though, instead of having to duplicate it every time I need the user to log in again.
Thanks in advance.
Answer by hexagonius · Nov 23, 2016 at 09:56 PM
Login is just a method that does not know how to wait. it executes it's block in one go. the only part that is waiting here is Authenticate(). internally that's an asynchronous call, going all the way through the internet and when returning executes the lambda expression you passed in as a parameter. If you want log-in to wait make it a coroutine and yield for a success. or put LoadData into the Lambda callback where it checks for success. OR create your own callback that you pass to GooglePlaySignIn which you call on success.
Thanks for the reply! I guess I've misunderstood then? I thought all functions wait by default before they continue executing their code. Could've sworn I've read this somewhere. Anyhow, creating a callback was actually my initial idea, but Unity kept giving me "cannot convert bool to void" errors. This is the code:
public bool GooglePlaySignIn(){
DebugText.text += "Signing into Google Play \n";
Social.localUser.Authenticate ((bool success) => {
if (success) {
DebugText.text += "Google Play authentification success \n";
return true;
} else {
DebugText.text += "Google Play authentification failed \n";
return false;
}
});
}
How could I make something like this work? I only started coding in C# a few days ago so my apologies for asking stupid questions.
You seem to have problems reading that code of yours properly ^^. You actually pass a lambda expression into the Authenticate method. A lambda expression is just like an anonymous method. It's the same as if you have written this:
public bool GooglePlaySignIn()
{
DebugText.text += "Signing into Google Play \n";
Social.localUser.Authenticate(OnRequestCompleted);
}
void OnRequestCompleted (bool success)
{
if (success) {
DebugText.text += "Google Play authentification success \n";
} else {
DebugText.text += "Google Play authentification failed \n";
}
}
You actually pass a "reference" to the "OnRequestCompleted" method to the Authenticate method. The Authenticate method internally starts a new thread which runs independently from the main thread. This thread will perform a web request or something similar which might take some time to complete. Once it completed it will execute the method you passed to Authenticate. In the meantime the main thread has already continued. You might want to use a coroutine which polls the state of a boolean until the callback has been invoked.
I'm sorry, I keep trying and trying with coroutines but always run into issues. I just don't fully understand how to work around this lambda expression. Could you please point me in the right direction with actual code? Ignore the main post for now, I've decided to forego the Login() function. I'll try to give a clearer explanation to what I'm trying to do.
Basically, whenever I need to have communication with the Google Play servers, e.g through functions like SaveGame(), LoadGame(), Load$$anonymous$$erboard() etc, I need to first check whether the user is still logged in/authenticated. To do this, I wanted to create an AuthCheck() function that returns a boolean so the functions know whether to continue or display an error. I want AuthCheck() to first check whether the user is still authenticated, if yes return true, if no try to log in again, and if that should fail as well, return false. I realize I could just check authentication with a simple if(Social.localUser.authenticated){} in every function separately and my entire problem would be solved, but I don't want to copypaste the entire retry login process to all these separate functions. The code would be much cleaner if I could figure out how to get AuthCheck() to work. This way the initial login could also just be handled by AuthCheck() and I'd simply call LoadData() in the very beginning of the game. It all seems simple, except I just need for other functions to wait until the logging in is complete.
void Start () {
ActivateSocialPlatform ();
LoadData();
}
public void LoadData(){
if (AuthCheck ()) {
CloudSaving = false;
GetSaveFromCloud();
}
}
private bool AuthCheck(){
if (Social.localUser.authenticated) {
DebugText.text += "Authentication success \n";
return true;
} else {
// try to log in again
DebugText.text += "Authentication failed \n";
GooglePlaySignIn(); // I need this function to wait until GooglePlaySignIn is complete, AND receive an answer whether it worked or not (true/false). Then return this function to false. How?
}
}
private void GooglePlaySignIn(){
Social.localUser.Authenticate ((bool success) => {
if (success) {
DebugText.text += "Google Play authentification success \n";
// somehow make AuthCheck know login succeeded
} else {
DebugText.text += "Google Play authentification failed \n";
// somehow make AuthCheck know login failed
}
});
}
// other functions for context, I don't want any of these including LoadData to change though.
public void LoadAchievements(){
if (AuthCheck()){
Social.ShowAchievementsUI();
}
}
public void SaveData(){
if (AuthCheck ()) {
CloudSaving = true;
GetSaveFromCloud();
}
}