How can store additional user properties in firebase like user's name, phone number programatically? Do I need to create additional document for every user to store their properties?
I'm creating user using like
userAuth.createUserWithEmailAndPassword(userBO.getUserPhoneNumber(),userBO.getUserPassword()).addOnCompleteListener(
getActivity(), new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
//TODO: set user properties here
}
else{
}
}
}
);
You should not use User Properties for saving static data like name, Phone number etc. As this data is specifically used for analytics purpose. Instead I would suggest you to create another document in firebase for storing user specific details.
You can set userName and photo as:-
UserProfileChangeRequest userProfileChangeRequest = new UserProfileChangeRequest.Builder().setPhotoUri(uri).setDisplayName(name).build();
userAuth.getCurrentUser().updateProfile(userProfileChangeRequest).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
}
});
Related
I am a newbie in Firebase. Recently I am trying to save users into Firebase but I can't. When I generate the APK and run it onto the real device(Not Emulator), the new user does not add it into the Firebase. Also, no errors shown up. Task executed properly and go to OTPActivity. Here is my complete code:
public void saveUser()
{
firebaseAuth.createUserWithEmailAndPassword(emailAddress.getText().toString(),password.getText().toString()).addOnCompleteListener(ChatUserSignUpActivity.this,new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful())
{
FirebaseUser user = firebaseAuth.getCurrentUser();
Intent intent = new Intent(ChatUserSignUpActivity.this, OTPActivity.class);
intent.putExtra("phoneNum",emailAddress.getText().toString());
startActivity(intent);
}
else
{
Toast.makeText(ChatUserSignUpActivity.this, task.getException().toString(), Toast.LENGTH_SHORT).show();
}
}
});
}
Please help me. Thanks in advance.
When you authenticate your users with email and password, no data is saved into Firestore, nor in the Realtime Database. If you need to save the database in the database, you need to write code for that. So once your user is authenticated, you can get the data from the FirebaseUser object and write it to the database of your choice.
I want to use custom function in my android application for sign up in firebase. Currently I am using the createUserWithEmailAndPassword function. It takes two parameters by default i.e Email & Password but my sign up form includes other attributes also like, phone number, name etc. So what should I do? Currently I am using the below code.
firebaseAuth.createUserWithEmailAndPassword(Email,Password).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful())
{
progressDialog.cancel();
Toast.makeText(SignUp.this,"Registration Successful",Toast.LENGTH_SHORT).show();
}
else
{
progressDialog.cancel();
Toast.makeText(SignUp.this,"Could Not Register. Try Again.",Toast.LENGTH_SHORT).show();
}
}
});
Thank You :)
Users are created using Email and Password. This is how I do the Sign-up:
mSignup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mEmailStr = removeSpaces(mEmail.getText().toString());
mPasswordStr = mPassword.getText().toString();
mUsernameStr = mUsername.getText().toString();
mIsSgl = mSglCheckBox.isChecked();
mUsernameStr=mUsername.getText().toString();
final User mUser = new User();
mUser.setEmail(mEmailStr);
mUser.setPassword(mPasswordStr);
mUser.setIsSgl(mIsSgl);
mUser.setStudyGroupName(mStudyGroupName);
mUser.setUsername(mUsernameStr);
FirebaseAuth.getInstance().createUserWithEmailAndPassword(mUser.getEmail(), mUser.getPassword()).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(getActivity(), "Sucsses", Toast.LENGTH_SHORT).show();
generateUser(mUser);
startActivity(new Intent(getActivity(), MainActivity.class));
} else {
Toast.makeText(getActivity(), "not Sucsses", Toast.LENGTH_SHORT).show();
}
}
});
}
});
This is how I push the data into database:
public void generateUser(User user)
{
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference users;
if(user.getIsSgl())
{
users = database.getReference(user.getStudyGroupName()).child("SGL");
}
else
{
users = database.getReference(user.getStudyGroupName()).child("Student");
}
users.push().setValue(user);
}
This is how I Sign-in:
mSignin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mEmailStr = SignupActivityFragment.removeSpaces(mEmail.getText().toString());
mPasswordStr = mPassword.getText().toString();
mAuth.signInWithEmailAndPassword(mEmailStr, mPasswordStr).addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(Task<AuthResult> task) {
if (task.isSuccessful()){
FirebaseDatabase database = FirebaseDatabase.getInstance();
// thats not worked for me
database.getReference("StudyGroups").child("Student").orderByChild("email").equalTo(mEmailStr).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapShot : dataSnapshot.getChildren()) {
userKey = childSnapShot.getKey();
}
Toast.makeText(getContext(),"Userkey: " + userKey,Toast.LENGTH_LONG).show();
Log.v("himaAbousalem",userKey);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Toast.makeText(getActivity(), "Sucsses ", Toast.LENGTH_SHORT).show();
startActivity (new Intent(getActivity(),Controller.class));
}else {
Toast.makeText(getActivity(), "not sucsses", Toast.LENGTH_SHORT).show();
}
}
});
}
});
I want to query the database so that when a user signs-in by Email and password, it returns all the data of that user from the database.
How can I make the key of userId in Auth equal to the userId in database and how do I use that feature?
tl;dr - In this case, store each user using their associated uid generated by Fireabase Auth instead of using a push ID.
In your situation the challenge with using a push ID to store info specific to each user is that when a user signs in you don't know the push ID you used when you first stored their info. To find a user each time they sign in you would have to search through every user in your database until you find a matching email/password to retrieve their correct profile information - the more users you have, the longer it would take to do the search. One alternative, which would probably be faster, is to use Firebase Authentication to create users and the Firebase Database to store any user specific information.
When you create a new user using Firebase Authentication it will assign a unique user id to the user that will be the same throughout the lifetime of the user. You then use the unique user id generated by Firebase Auth instead of a push ID to store user info in the database. The next time a user signs in you get the user's uid from Firebase Auth and use it to query the database to get that user's information.
Check the guide for how to create a password-based user and how to sign a user in using Firebase Auth: Create a password-based account
In order to use the unique uid generated by Firebase Auth I suggest a few changes to your code.
Update database structure
I suggest you update your database structure by adding a new location (maybe "allUsers") for use when you create/sign in users. Right now it looks like your are breaking up students into groups. If you need to keep this structure, for reasons beyond authentication, you can use it along with my suggestion. The reason for a single location which stores all users is that you need a definite location to query when a user signs in. When using Firebase Auth, without a single location which stores all users there is no way to tell what group a user belongs to when they first sign in. You would have to check every group in order to find a match and that may take a long time. Having a location which stores all users solves that problem. Also, the query for retrieving user information from that single location is much simpler. If you do need to keep a user's information in multiple places just be sure to update their information in both places if any changes occur.
Create a class variable used to distinguish between create user and sign in existing user.
If you use the same Activity to create a new user and sign in an existing user then create a boolean variable to make a distinction between when a new user is being created and when an existing user is signing in. It will be used later in the AuthStateListener. If you handle user creation in a separate activity from general sign in then you shouldn't need this variable because each activity would have a separate AuthStateListener.
boolean mIsNewUser = false;
Move the call to generateUser() from the create user completion listener to an AuthStateListener. Also move your database query from the sign in completion listener to the AuthStateLisener
Whenever you create a user successfully they will automatically be signed in too. So, if you move your call to generateUser() from the createUserWithEmailAndPassword OnCompleteListener to your AuthStateListener you can get access to the created user's uid. When signing an existing user move your database query to the AuthStateListener as well, again so we can access the user's uid. I'm also going to create a helper method for the database query called getExistingUserInfo. As an FYI, the onComplete() callback in the OnCompleteListeners for creating and signing in users gives you access to an AuthResult which according to the API has a method for returning the current user but the documentation says to access user information in the AuthStateListener.
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
mAuth = FirebaseAuth.getInstance();
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
if(mIsNewUser){
//call to generate user using Uid instead of pushID
generateUser(mUser, user.getUid());
} else{
getExistingUserInfo(user.getUid());
}
startActivity(new Intent(getActivity(), MainActivity.class));
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
}
// ...
}
};
// ...
}
}
#Override
public void onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
#Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}
Update your generateUser() helper method to use the uid instead of a push ID:
I'm going to assume you want to keep you existing database structure and add the single location for all users as suggested. Based on this I've made a couple of changes to the write operation you were using in generateUser(). Mainly, instead of using setValue() to write to the database I'm using updateChildren(). By using updateChildren() we can take advantage of Firebase's ability to do atomic updates. This will allow us to write to the appropriate student group location and the location storing all users simultaneously. By taking this approach if the write operation to either location fails neither location will be updated. This way you can be certain if a student is added to a group they will also be listed in the allUsers location.
private void generateUser(User user, String uid)
{
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
String userType;
String allusers = "allUsers/" + uid;
Map<String, Object> newUserUpdate = new HashMap<>();
if (user.getUsername() != null) {
if (user.isSgl()) {
userType = user.getStudyGroupName() + "/" + "SGL" + "/" + uid;
} else {
userType = user.getStudyGroupName() + "/" + "Student" + "/" + uid;
}
newUserUpdate.put(userType, user.serialize());
newUserUpdate.put(allusers, user.serialize());
database.updateChildren(newUserUpdate);
}
}
Update database query to use new location which stores all users
As I mentioned above, by creating a single location for all users you can reduce the complexity of the query used to find a user's info when they sign in. Again, if you need to store users by group you can keep that but be sure to update both locations if a users info changes.
public void getExistingUserInfo(String uid){
FirebaseDatabase database = FirebaseDatabase.getInstance();
database.getReference("allUsers").child(uid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//get user data from dataSnapshot
Toast.makeText(getContext(),"Userkey: " + userKey,Toast.LENGTH_LONG).show();
Log.v("himaAbousalem",userKey);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Set the variable used to distinguish between existing user sign in and new user creation in the create user completion listener
FirebaseAuth.getInstance().createUserWithEmailAndPassword(mUser.getEmail(), mUser.getPassword()).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(Task<AuthResult> task) {
if (task.isSuccessful()) {
//set boolean used in the AuthListener
mIsNewUser = true;
Toast.makeText(getActivity(), "Sucsses", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "not Sucsses", Toast.LENGTH_SHORT).show();
}
}
});
When creating a user, I want to be able to set his/her display name. How do I do this in Android? Here is an example of what I want to achieve:
mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
FirebaseUser.getCurrentUser().setDisplayName(mName); //I want to do this
}
});
Assume all variables have been declared and/or initialized correctly.
You can set the user's Firebase display name by writing the following three lines of code:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(mName).build();
user.updateProfile(profileUpdates);
By doing so, your original code should look like this:
mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
// Sign in is successful
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(mName).build();
user.updateProfile(profileUpdates)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "User profile updated.");
}
}
});
}
});
Official Firebase Documentation:
Firebase Update a User's Profile
What the above code does is that when the user's account is successfully created using Email and Password authentication, it will then sign-in the user.
Once the user is signed-in, you can access the user's Firebase User Object Properties and set the display name property to any string you want.
This is great for testing the user's profile name in Verification Emails.
Note: A Firebase User Object has a fixed set of basic properties—a unique ID, a primary email address, a name, and a photo URL. These basic properties are stored in the project's User Database.
Furthermore, these properties can be updated programmatically.
However, you cannot add other properties to the Firebase User Object directly; instead, you can store any additional properties (i.e. user information) in your Firebase Realtime Database, and reference them from there.
(Firebase User Object Properties Doc)
I found the answer in the Firebase docs. I will quote it here: "If sign-in succeeded, the AuthStateListener runs the onAuthStateChanged callback. In the callback, you can use the getCurrentUser method to get the user's account data." Here is the link: https://firebase.google.com/docs/auth/android/password-auth#sign_in_a_user_with_an_email_address_and_password
So that means, if you do the above code (minus the FirebaseUser line), and then declare and initialize a Firebase AuthStateListener like shown below, you can set the user's display name and then move on to any other activity you want:
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if(user!=null){
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(mName).build();
user.updateProfile(profileUpdates);
Intent intent = new Intent(currentActivity.this, nextActivity.class);
startActivity(intent);
}
}
};
And don't forget to add the AuthStateListener in onResume() like so:
#Override
public void onResume(){
super.onResume();
mAuth.addAuthStateListener(mAuthListener);
}
Likewise, don't forget to remove it in the onStop method like so:
#Override
public void onStop(){
super.onStop();
if(mAuthListener != null){
mAuth.removeAuthStateListener(mAuthListener);
}
}
And done! You set the user's display name so you can use it in other activities. This would be useful if you want to greet the user or access any other user data tied to the display name.
So I have the following code that I got from the firebase documentation (which I implemented in my app already and it's working fine):
Firebase ref = new Firebase("https://myapp.firebaseio.com");
ref.createUser("bobtony#firebase.com", "correcthorsebatterystaple", new Firebase.ValueResultHandler<Map<String, Object>>() {
#Override
public void onSuccess(Map<String, Object> result) {
System.out.println("Successfully created user account with uid: " + result.get("uid"));
}
#Override
public void onError(FirebaseError firebaseError) {
// there was an error
}
});
after I create a user it prints on the console its uid. However, when I enter in my myapp.firebaseio.com there is nothing there.. So I have some questions:
Where does firebase stores this new user created?
How can I add some custom fields? (this functions uses just email and password) i.e Username
So, What I have tried to do was inside the onSuccess() I used ref.push() some values to myapp.firebaseio.com but then .. how can I check if the users uid created by the createUser() is the same as the one who I pushed? (the id's are differente!)
I hope my text it's clear, if isn't asked and I can try to explain again!
Thanks a bunch!
User information is not stored inside your Firebase database. For anonymous and OAuth users, no information is stored anywhere. The information for email+password users is kept in a separate database that you don't have access to. The email+password users are visible in the Login & Auth tab of your dashboard of course, just not in your database.
If you want to store user information in your own Firebase database, you have to store it there yourself when you create or authenticate the user. There is a section on storing user data in the Firebase documentation that shows how to do this.
One advantage of having to store the information yourself, is that you get to determine exactly what is and what isn't stored.
As Frank said; no user information is automatically put in the firebase itself on creating a user (have a look in Login&Auth in the dashboard sidebar instead). The new user is not even logged in after creation. This is the code I use to login and put a new user in the firebase when registering:
static void createUser(final String username, final String password) {
final Firebase rootRef = new Firebase("YOUR_FIREBASE_URL");
rootRef.createUser(
username,
password,
new Firebase.ResultHandler() {
#Override
public void onSuccess() {
// Great, we have a new user. Now log them in:
rootRef.authWithPassword(
username,
password,
new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
// Great, the new user is logged in.
// Create a node under "/users/uid/" and store some initial information,
// where "uid" is the newly generated unique id for the user:
rootRef.child("users").child(authData.getUid()).child("status").setValue("New User");
}
#Override
public void onAuthenticationError(FirebaseError error) {
// Should hopefully not happen as we just created the user.
}
}
);
}
#Override
public void onError(FirebaseError firebaseError) {
// Couldn't create the user, probably invalid email.
// Show the error message and give them another chance.
}
}
);
}
This is working well for me so far. I guess something could go wrong if the connection is interrupted right in the middle of everything (might end up with a user without it's initial info). Don't depend too much on it getting set...
May be previous one deprecated as per Firebase . They are create new concept
//create user
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(SignupActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Toast.makeText(SignupActivity.this, "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
// 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(SignupActivity.this, "Authentication failed." + task.getException(),
Toast.LENGTH_SHORT).show();
} else {
Log.e("task",String.valueOf(task));
getUserDetailse(auth);
}
}
});
/get user Detailse against FirebaseAuth auth/
public static void getUserDetailse(FirebaseAuth auth)
{
//
auth.addAuthStateListener(new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull final FirebaseAuth firebaseAuth) {
final FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
Log.i("AuthStateChanged", "User is signed in with uid: " + user.getUid());
String name = user.getDisplayName();
String email = user.getEmail();
Uri photoUrl = user.getPhotoUrl();
// The user's ID, unique to the Firebase project. Do NOT use this value to
// authenticate with your backend server, if you have one. Use
// FirebaseUser.getToken() instead.
String uid = user.getUid();
Log.e("user",name+email+photoUrl);
} else {
Log.i("AuthStateChanged", "No user is signed in.");
}
}
});
}
check for detailse