Firebase Authentication with Google Play Games - java

I am creating a game for android. Each user needs to be authenticated.
Currently, when a new user launches the game, it requests an identification code from my server, and stores it to SharedPreferences. Next time user launches the game, it uses this stored identification code to authenticate. The problem is, when user clears data of this app, there's no way he can get his ID back, so he lost his progress forever.
Is there a way how to generate something like Identification code which is unique and always the same for one player using Firebase Play games auth method?
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
.requestServerAuthCode("MyCID")
.build();
mAuth = FirebaseAuth.getInstance();
super.onCreate(savedInstanceState);
final FirebaseAuth auth = FirebaseAuth.getInstance();
AuthCredential credential = PlayGamesAuthProvider.getCredential("MyCID");
auth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
currentUser = auth.getCurrentUser();
} else {
Toast.makeText(MainActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
}
});
if (currentUser == null) {
cu = "NO UID";
} else {
cu = currentUser.getUid();
}
I tried this code (Where is MyCID: I used the CID from the image below), but no Google Play Games pop-up is shown, I get Authentication Failed toast and cu is set to "NO UID".
Can someone explain how does this work please?
EDIT
Thanks to #crysxd , My app now shows the green google play games popup. But instead of expected "Select an account" popup, as I see in other games which uses google games sign in, I get an error, which says "com.google.android.gms.common.api.ApiException: 4:".
Is there a function which I need to run to show this dialog? Am I missing something or just I have incorrectly configured the game in google play console?
My current code: link

You are skipping an essential step here. The Firebase docs are usually very good, but the Play sign in is poorly described.
You got the first step right: You need to set up GoogleSignInOptions but you miss to pass them to a GoogleSignInClient.
Create a client in onCreate:
private static final int RC_SIGN_IN = 543;
private GoogleSignInClient mGoogleSignInClient;
public void onCreate(Bundle savedInstancestate) {
super.onCreate(savedInstancestate)
// ...
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
.requestServerAuthCode("MyCID")
.build();
mGoogleSignInClient= GoogleSignIn.getClient(this, gso)
}
Call this method when the sign in button is clicked or you want to start sign in. This will cause the sign in dialog to be shown.
private void signIn() {
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
Get the sign in response and handle it
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from
GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
// Google Sign In was successful, authenticate with Firebase
GoogleSignInAccount account = task.getResult(ApiException.class);
firebaseAuthWithGoogle(account);
} catch (ApiException e) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e);
}
}
}
Finally, your code comes into play. Now we have the GoogleSignInAccount which is required to call PlayGamesAuthProvider.getCredential(...). You passed your Client ID here, but that's the wrong thing. This is how it works: You give your client ID to Google just to tell them who (or which app) you are. They will let the user sign in and give you a special token ("id token") which Firebase can then use to get information about the user from Google Play Games. And that's the token you need to give to Firebase here:
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = mAuth.getCurrentUser();
updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Snackbar.make(findViewById(R.id.main_layout), "Authentication Failed.", Snackbar.LENGTH_SHORT).show();
updateUI(null);
}
// ...
}
});
}
Hope that helps! You can find the entire code referenced in the docs here and here (these are the files they show the snippets from in the docs).

Related

Unable to sign-in using Google in Android App

I've tried many solutions mentioned here but I'm still unable to fix this. I'm receiving:
"Google sign in failed. com.google.android.gms.common.api.ApiException: 10"
I've verified my OAuth auto-generated 'web client key' in Google Cloud Console is same as what I'm using in my code. But I'm getting the same error. I've also verified that project name is same in Google Cloud Console and Firebase.
Here's my code:
public class LoginActivity extends Activity {
private GoogleSignInClient mGoogleSignInClient;
private FirebaseAuth mAuth = FirebaseAuth.getInstance();
private static final int RC_SIGN_IN = 1;
static LoginActivity loginActivity;
private FirebaseUser currentUser;
public static LoginActivity getInstance(){
return loginActivity;
}
public FirebaseUser getCurrentUser() {
return currentUser;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
GoogleSignInOptions gso = new
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
mAuth = FirebaseAuth.getInstance();
View signInButton = findViewById(R.id.sign_in_button);
signInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
//Here resultCode is 0 & requestCode is 1.
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
// This line of code is throwing exception.
GoogleSignInAccount account = task.getResult(ApiException.class);
Log.w(TAG, task.getException());
Log.d(TAG, "firebaseAuthWithGoogle:" + account.getId());
firebaseAuthWithGoogle(account.getIdToken());
} catch (ApiException e) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e);
}
}
}
I'm following this tutorial from official docs. Any help is appreciated.
P.S. I'm also using Firestore database in the same project. And I've successfully saved the google-services.json in the app's folder.
Make sure you add your SHA1 to the firebase project and Make sure you complete Android Device Check API requirements. This will enable your devices to be recognized. use https://console.cloud.google.com/apis/library/androidcheck.googleapis.com?project=capital-insider&folder=&organizationId=https://console.cloud.google.com/apis/library/androidcheck.googleapis.com?project=capital-insider&folder=&organizationId=
check this out Google sign in failed com.google.android.gms.common.api.ApiException: 10:
After Uploading to play store, Play store generate its own SHA1 which we have to replace in second key in google console and Make sure you add your SHA1 to the firebase project.
Go to google console>app signing> copy SH1 generate by console. Add that in google sign in console replace it from 2nd key.
look at this if it help you: Google sign in failed com.google.android.gms.common.api.ApiException: 10:

Firebase user registration with google

I am trying to implement google sign-in feature in my app. I have followed this documentation, problem is - if I use previously used google account, it is not showing an error like "the e-mail is already registered in this app". As a result, previously stored data with the account are deleted & the google account is registered again. Here is my code :
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = mAuth.getCurrentUser();
int coins = 100;
String name, email;
name = user.getDisplayName();
email = user.getEmail();
//updateUI(user);
storeUserCredentials(name, email, coins);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(SignUpActivity.this, "Error : " + task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
}
public void storeUserCredentials(String name, String email, int coins){
progressBar.setVisibility(View.VISIBLE);
User user = new User(name, email, coins);
mDatabase.getReference("Users")
.child(mAuth.getCurrentUser().getUid())
.setValue(user)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
progressBar.setVisibility(View.GONE);
if (task.isSuccessful()){
Toast.makeText(SignUpActivity.this, "Registration Successful!", Toast.LENGTH_SHORT).show();
startActivity(new Intent(SignUpActivity.this, MainActivity.class));
finish();
} else {
if (task.getException() instanceof FirebaseAuthUserCollisionException){
Toast.makeText(SignUpActivity.this, "The email is already used", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SignUpActivity.this, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
});
}
What is wrong with my code, please explain.
When you call signInWithCredential the SDK returns a task that successfully completes when the user is signed in. Since you call storeUserCredentials on that condition, it will get called each time the user is signed in. This is actually a quite normal flow.
If you want to detect if this account is new to Firebase Authentication, you can check the creation time of the user. See Firebase Auth, how to know new user signed up, rather than existing user sign in?
If you want to detect whether you've already seen the user before, you'll want to check in the database before calling storeUserCredentials. But what you now have is a pretty idiomatic flow, since it for example ensures you store the up-to-date display name each time you ask the user to sign in.

Android Firebase Removing all user data with relogin

I'm trying to create users table in Firebase realtime database.However, everytime user re-logins his previously entered data is being removed or overwritten.Couldnt understand how should I change it.
private void firebaseAuthWithGoogle(GoogleSignInAccount account) {
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(RegisterActivity.this,"Registration Is Succesfull",Toast.LENGTH_LONG).show();
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user=mAuth.getCurrentUser();
final String databaseUserName=user.getDisplayName();
String name=mAuth.getCurrentUser().getDisplayName();
DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users");
DatabaseReference userNameRef = myRootRef.child(databaseUserName);
//after that user is redirected to the main account activity.
Intent accountIntent = new Intent(RegisterActivity.this,UserAccountActivity.class);
accountIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(accountIntent);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(RegisterActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
// if signing up task is unsuccesfull we do make a error indication pretty much.
FirebaseAuthException e = (FirebaseAuthException )task.getException();
Toast.makeText(RegisterActivity.this, "Failed Registration: "+e.getMessage(), Toast.LENGTH_SHORT).show();
Log.e("LoginActivity", "Failed Registration", e);
}
}
});
}
So once I run the code, for the very first time it works perfectly fine and say I edit&add additional user info but once the user logs out and re-enters, everything is cleared out and node is again created.
Here you are saving the data in the database:
DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users");
DatabaseReference userNameRef = myRootRef.child(databaseUserName);
Now on the second time, the data is not getting deleted or cleared, it cannot be deleted magically, the data is getting overridden. All you need to do is add a push() that will create a random id for each log in.
So like this:
DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users").push();
DatabaseReference userNameRef = myRootRef.child(databaseUserName)
Edit:
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(Activity_name_here.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Toast.makeText(getApplicationContext(), "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show();
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "Authentication failed." + task.getException(),
Toast.LENGTH_SHORT).show();
} else {
Here is the working version of the source code. You can use the very same code for facebook login as well. This code simply prevents user from overwriting when logging in again.
private void firebaseAuthWithGoogle(GoogleSignInAccount account) {
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(SignInActivity.this,"Registration Is Succesfull",Toast.LENGTH_LONG).show();
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
//getting current users account
FirebaseUser user=mAuth.getCurrentUser();
//getting the display name of the current user to store them in our real time database
final String databaseUserName=user.getDisplayName();
//creating a child called users
final DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users");
//here we make a control such that, if logged in user is exist in the realtime database
//if not exists, then we save them , if exists we continue with the else statement and break it.
myRootRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.hasChild(databaseUserName)){
DatabaseReference userNameRef = myRootRef.child(databaseUserName);
//value is also set to user display name however it doenst have to be so
userNameRef.setValue(databaseUserName);
} else{
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//after that user is redirected to the main account activity.
Intent accountIntent = new Intent(SignInActivity.this,UserAccountActivity.class);
accountIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(accountIntent);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(SignInActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
// if signing up task is unsuccesfull we do make a error indication pretty much.
FirebaseAuthException e = (FirebaseAuthException )task.getException();
Toast.makeText(SignInActivity.this, "Failed Registration: "+e.getMessage(), Toast.LENGTH_SHORT).show();
Log.e("LoginActivity", "Failed Registration", e);
}
}
});
}

Android Firebase AuthStateListener Email Verified

I have a SignInActivity with Firebase AuthStateListener.
final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
final FirebaseAuth.AuthStateListener firebaseAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(FirebaseAuth auth) {
FirebaseUser user = auth.getCurrentUser();
if (user != null && user.isEmailVerified()) {
firebaseAuth.removeAuthStateListener(this);
startActivity(new Intent(LoginActivity.this, MainActivity.class));
}
}
};
firebaseAuth.addAuthStateListener(firebaseAuthListener);
When I successfully registered a new Account, I setVisibity(View.Visible) a verify page with EditTextEmail & VerifyButton inside the activity (in case someone wants to resend the email verification).
What I want to do is when I verify my email from my email account, I want the page to automatically start my MainActivity instead of just staying idle in my LoginActivity, like SMS verification, when verification code received in SMS, the app reads the SMS and navigate to MainActivity. Is it possible to achieve this with email verification? Because the FirebaseAuthState never changed even after I click on verification link on my email.
I need something like OnFirebaseAuthUserEmailVerifiedListener
I'm new to firebase, please kindly give me advice on how to achieve this or if it is not possible.
This link is really useful.
Because the FirebaseAuthState never changed even after I click on verification link on my email.
That's because the user is cached, and you need to reload the user:
Do note that the FirebaseUser object is cached within an app session, so if you want to check on the verification state of a user, it's a good idea to call .getCurrentUser().reload() for an update.
You need something like this
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user.isEmailVerified())
{
// user is verified, so you can finish this activity or send user to activity which you want.
finish();
Toast.makeText(LoginActivity.this, "Successfully logged in", Toast.LENGTH_SHORT).show();
}
else
{
// email is not verified, so just prompt the message to the user and restart this activity.
sendVerificationEmail();
}
}
And method to get emailVerification
private void sendVerificationEmail(){
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
// email sent
// after email is sent just logout the user and finish this activity
FirebaseAuth.getInstance().signOut();
startActivity(new Intent(SignupActivity.this, LoginActivity.class));
finish();
}
else{
// email not sent, so display message and restart the activity or do whatever you wish to do
}
}
});
}
Hope this helps you.

Installing app from Google Play Store gives a Firebase Authentication Error but installing the same APK from my computer works perfectly

I'm having a problem
I have an app that uses Firebase Auth to sign in with Google. I uploaded the Release APK to Google Play Store as an Alpha version but when I download it to test it on my phone it give an Authentication error, however, when I download the same apk from my computer to my phone it works perfectly.
In my main
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
mAuth = FirebaseAuth.getInstance();
findViewById(R.id.signIn).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
signIn();
}
});
onStart:
FirebaseUser currentUser = mAuth.getCurrentUser();
if(currentUser!=null)
{
startActivity(new Intent(LoginActivity.this, MainActivity.class));
}
private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
GoogleSignInAccount account = result.getSignInAccount();
firebaseAuthWithGoogle(account);
} else {
Toast.makeText(LoginActivity.this, "Authentication failed, please try again",
Toast.LENGTH_SHORT).show();
}
}
}
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = mAuth.getCurrentUser();
startActivity(new Intent(LoginActivity.this, MainActivity.class));
} else {
// If sign in fails, display a message to the user.
System.out.println(task.getResult().toString());
Toast.makeText(LoginActivity.this, "Authentication failed, please try again",
Toast.LENGTH_SHORT).show();
}
}
});
}
I had your same problem, and I solved it adding a new SHA-1 key in the Firebase Console. If you enable Google Play App Signing for your app, you can find the SHA-1 to add to the Firebase Console in the Google Play Developer Console.
In the console, if you open the "Release Management" section, you will find the "App signing" tab, as you can see in the image below.
In this page you will find a section called "App signing certificate", where you can see a MD5 certificate fingerprint, a SHA-1 certificate fingerprint and a SHA-256 certificate fingerprint, as you can see in the image below.
You have to copy the SHA-1 certificate fingerprint in the Firebase Console, together with the debug SHA-1 and the release SHA-1 of your Keystore.

Categories

Resources