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.
Related
I am trying to make an app with a login function and I want to keep the user logged in.
I'm using Firebase auth and android studio.
This is what I tried:
auth.signInWithEmailAndPassword(txt_email, txt_password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()){
Intent intent = new Intent(login.this, sendForm.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
}
else {
Toast.makeText(login.this, "cant sing in", Toast.LENGTH_SHORT).show();
}
}
});
First you need to check if the user exists when you log in to the app from second time. If the user exists you directly take him to the MainActivity else you'll take him to the LoginActivity.
So, your launchActivity should be something that is other then Login/Main activities. Typically, it would be a splash screen. So, let's say you're launch activity is SplashActivity.
Now, in your SplashActivity.java onCreate() do this:
FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
if (Objects.nonNull(currentUser)) {
// This means that user has already logged into the app once.
// So you can redirect to MainActivity.java
startActivity(new Intent(this, MainActivity.class));
} else {
// This means no user logged into the app before.
// So you can redirect to LoginActivity.java
startActivity(new Intent(this, LoginActivity.class));
}
If you don't want to use a SplashScreen, you can check for the user existence in LoginActivity.java using FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); and redirect him to MainActivity if currentUser is nonNull.
I want to keep the user logged in.
This is happening by default. There is nothing special that you need to do in order to keep your users logged in. They will be logged in until they explicitly sign out. Here is the official documentation for Android:
https://firebase.google.com/docs/auth/android/start/
If you want to keep track of the auth state, then please check my answer from the following post:
One time login in app - FirebaseAuth
Besides that, please also note that the state of being "signed in" doesn't depend on internet connectivity but on the user token currently in use, which is present locally and has not expired after one hour since the last refresh.
This question already has answers here:
How to redirect multiple types of users to their respective Activities?
(3 answers)
Checking if a particular value exists in the Firebase database
(6 answers)
Closed 2 years ago.
First, I will tell the flow of my App.
Login Screen(SignInActivity.java) -> Enter details(MainActivity.java) ->Home Screen(HomeScreenActivity.java)
In my app, I have used Firebase Authentication and Firebase Database. When the user is new, then it should go to Main Activity from SignInActivity where user enters his name, a short description and his hobby. The details are stored in Firebase Database and then HomeScreenActivity opens where user details are shown in Recycler View.
But currently what happens is when same user does login again, it again asks user for details. I want to check if users Google Account already exists in Firebase Auth, then instead of asking details, it should directly go to HomeScreenActivity.
I checked many answers on StackOverflow, but nothing seems to work. One thing that i tried was additionalUserInfo.isNewUser but in this app crashes when user does login again, showing null error where I display user details in HomeScreenActivity.
SignInActivity.java
private void firebaseAuthWithGoogle(String idToken) {
AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null);
mAuthIn.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");
startActivity(new Intent(SignInActivity.this, MainActivity.class));
finish();
} else {
// If sign in fails, display a message to the user.
Toast.makeText(SignInActivity.this, "Authentication Failed", Toast.LENGTH_SHORT).show();
}
}
});
}
MainActivity.java
public void init() {
hobbiesContinueButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String name=user.getText().toString().trim();
String desc=description.getText().toString().trim();
String hobby=spinner.getSelectedItem().toString();
String image="default";
String thumbnail="default";
if(!TextUtils.isEmpty(name))
{
FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
assert currentUser != null;
String userId=currentUser.getUid();
User user=new User(name,hobby,desc,image,thumbnail);
dbRef.child(userId).setValue(user);
startActivity(new Intent(getApplicationContext(), HomeScreenActivity.class));
finish();
}
else
{
Toast.makeText(getApplicationContext(), "Enter a name",Toast.LENGTH_SHORT).show();
}
}
});
}
HomeScreenActivity.java
dbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
imgvw = headerView.findViewById(R.id.imageView);
imgvw.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//to open gallery
Intent galleryIntent = new Intent();
galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(galleryIntent, "SELECT IMAGE"), GALLERY_PICK);
}
});
TextView nameDrawer = findViewById(R.id.navName);
TextView descDrawer = findViewById(R.id.navDescription);
User change = snapshot.getValue(User.class);
assert change != null;
//This is where null error occurs
nameDrawer.setText(change.getUserName());
descDrawer.setText(change.getUserDesc());
//change profile picture
image= Objects.requireNonNull(snapshot.child("userImage").getValue()).toString();
Log.d(TAG, "onComplete: "+image);
if(!image.equals("default")){
Picasso.get().load(image).placeholder(R.drawable.avatar).into(imgvw);
}
}
The solution is to save your user details in shared preferences for the first time when the user sign in , then after the user signs out and sign it again , you get data from shared preferences and set them directly to your edittexts
Try this Code :
///save sharedpreferences
SharedPreferences sharedPreferences =
getSharedPreferences("prefs",Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("username","put here your username"); //
editor.putString("email","put your email here"); //you can add more details
editor.apply();
///get sharedpreferences
SharedPreferences sharedPreferences1 =
getSharedPreferences("prefs",Context.MODE_PRIVATE);
String username = sharedPreferences1.getString("username","");
String email = sharedPreferences1.getString("email","");
//then here set the valeus from sharedpreferences to your edittexts
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).
This question already has answers here:
One time login in app - FirebaseAuth
(3 answers)
Closed 3 years ago.
I have an application there is user login screen sends to an activity if logging action is OK. But everytime I closed the application, app asks for email and password, I want to stay logged in like instagram or facebook. Have can I do that? And also how can I do that, do I have to change the code in signin activity or create another class for saving the current user, I am so much confused. There is my login code for firebase:
SignInActivity;
public class SignInActivity extends AppCompatActivity {
private EditText SignInMail, SignInPass;
private FirebaseAuth auth;
private Button SignInButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Get Firebase auth instance
auth = FirebaseAuth.getInstance();
// set the view now
setContentView(R.layout.activity_signin);
SignInMail = (EditText) findViewById(R.id.SignInMail);
SignInPass = (EditText) findViewById(R.id.SignInPass);
SignInButton = (Button) findViewById(R.id.SignInButton);
//Get Firebase auth instance
auth = FirebaseAuth.getInstance();
SignInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String email = SignInMail.getText().toString();
final String password = SignInPass.getText().toString();
if (TextUtils.isEmpty(email)) {
Toast.makeText(getApplicationContext(), "Mail", Toast.LENGTH_SHORT).show();
return;
}
if (TextUtils.isEmpty(password)) {
Toast.makeText(getApplicationContext(), "Password", Toast.LENGTH_SHORT).show();
return;
}
//authenticate user
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(SignInActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
// 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.
// progressBar.setVisibility(View.GONE);
if (!task.isSuccessful()) {
// there was an error
if (password.length() < 8) {
Toast.makeText(getApplicationContext(),"pass min 8",Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(),"error",Toast.LENGTH_SHORT).show();
}
} else {
Intent intent = new Intent(SignInActivity.this, CampaignActivity.class);
startActivity(intent);
finish();
}
}
});
}
});
}
public void NavigateSignUp(View v) {
Intent inent = new Intent(this, SignupActivity.class);
startActivity(inent);
}
public void NavigateForgetMyPassword(View v) {
Intent inent = new Intent(this, ResetPasswordActivity.class);
startActivity(inent);
}
}
In the onCreate function, you need to add this piece of code
FirebaseUser user=FirebaseAuth.getInstance().getCurrentUser();
This code will fetch you the currently logged in user if the user has previously signed in, else will return null.
Check this link for further understanding.
Get the currently signed-in user - Firebase Docs
I hope this solved your problem. If you feel this answer is correct, please accept the answer.
When a user logged in successfully store the LOGIN TYPE of User SharedPreferenceence and check that flag again when user restart app. If Shared Preference contains value then just take him to Main Screen.
Like this on each login update this value and check
PreferencesManager.getInstance().getString(ANNONYMOUS_SIGNUP_DATE, "")) && (PreferencesManager.getInstance().getInt(LOGIN_TYPE, 0) == LOGIN_TYPE_ANNONYMOUS)
Since you authenticated the user, then you can create a splash screen before your sign in activity, and write the following code:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null){
Intent i = new Intent(SplashActivity.this, HomeActivity.class);
} else{
Intent i = new Intent(SplashActivity.this, SignInActivity.class);
}
Here, you check if currently there is a logged in user and then navigate to the right activity according to the condition.
I would recommend you to use splash screen first and check it user is logged in by the following
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
// User is signed in
// go to main page
} else {
// No user is signed in
// go to loging page
}
I have a firebase app for which I don't need or want user signup or login but I want to setup Auth to make sure database can only be accessed through my app. Is there any way to do so?
You can use Anonymous Authentication for that purpose. Users don't need to enter any details for sign up or login, Firebase will simply give them an uid to access your database and you can still keep your Firebase Security Rules set to auth!=null.
Go ahead, add Firebase Auth to your app and then on your Activity:
Grab an instance of the FirebaseAuth Object:
private FirebaseAuth mAuth; mAuth = FirebaseAuth.getInstance();
Sign the user in, anonymously:
mAuth.signInAnonymously()
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>(){
#Override
public void onComplete(#NonNull Task<AuthResult> task){
if(task.isSuccessful()){
Log.d(TAG, "signInAnonymously:success");
}
else
{
Log.w(TAG, "signInAnonymously:failure", task.getException());
Toast.makeText(AnonymousAuthActivity.this, "Failed", Toast.LENGTH_SHORT).show();
}
}
});