I need to create and use a database entry with all details (uid, name etc) for each user that logs in to the application
I am having trouble storing user data in order to use and retrieve user profile info using Firebase in Android. I found this documentation on the old version of Firebase but this does not seem to work any longer.
Does anyone know how to reproduce the above code so it works with the new version of Firebase? Many thanks in advance.
Edit - code below:
final Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.authWithPassword("jenny#example.com", "correcthorsebatterystaple",
new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
// Authentication just completed successfully :)
Map<String, String> map = new HashMap<String, String>();
map.put("provider", authData.getProvider());
if(authData.getProviderData().containsKey("displayName")) {
map.put("displayName", authData.getProviderData().get("displayName").toString());
}
ref.child("users").child(authData.getUid()).setValue(map);
}
#Override
public void onAuthenticationError(FirebaseError error) {
// Something went wrong :(
}
});
For creating user in firebase database (new Version) ,you need to do changes as followning..
private FirebaseAuth mAuth;
String mUserEmail = "jenny#example.com";
String mPassword = "correcthorsebatterystaple"
mAuth.createUserWithEmailAndPassword(mUserEmail, mPassword)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(LOG_TAG, getString(R.string.log_message_auth_successful) + " createUserWithEmail:onComplete:" + task.isSuccessful());
// if task is not successful show error
if (!task.isSuccessful()) {
try {
throw task.getException();
} catch (FirebaseAuthUserCollisionException e) {
// log error here
} catch (FirebaseNetworkException e) {
// log error here
} catch (Exception e) {
// log error here
}
} else {
// successfully user account created
// now the AuthStateListener runs the onAuthStateChanged callback
}
}
});
}
now Add following method in onCreate() .
final DatabaseReference ref = FirebaseDatabase.getInstance().
getReferenceFromUrl(https://<YOUR-FIREBASE-APP>.firebaseio.com");
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
Map<String, String> map = new HashMap<String, String>();
map.put("provider", user.getProvider());
if(user.getProviderData().containsKey("displayName")) {
map.put("displayName",
user.getProviderData().get("displayName").toString());
}
ref.child("users").child(user.getUid()).setValue(map);
} else {
// User is signed out
Log.d(LOG_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);
}
}
To authenticate users with email and password (Google, Facebook) use Firebase Auth
To use Firebase database to store different data than use Firebase Realtime Database
If you want to Manage Auth users from your backend
User Management - Retrive user's full data and change a user's password or email address
Custom Authentication - You can integrate an external user system with Firebase.
Identity Verification - Use the service to identify these users on your own server.
Firebase Auth has a NODE JS sdk which you can use. If you want to access this features from Android, than you have to create a web service (eg.Restful API) and communicate with it through network.
If you want to access registered Auth users in Realtime Database i dont think you can because they are separated from each other. You can register users in Realtime Database but i dont understund why you want to do that since Auth provides you this feature in an easier way.
Firebase Realtime Database also has an Admin SDK (Java and Node JS)
Please check documentation before asksing.
Please use the latest Firebase SDK, found here: firebase.google.com/docs. Using the legacy SDK (as you are doing now) is just going to lead to a harder time than needed.
you can get user information as follows:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
for (UserInfo profile : user.getProviderData()) {
// Id of the provider (ex: google.com)
String providerId = profile.getProviderId();
// UID specific to the provider
String uid = profile.getUid();
// Name, email address, and profile photo Url
String name = profile.getDisplayName();
String email = profile.getEmail();
Uri photoUrl = profile.getPhotoUrl();
};
}
Related
I want when user click to admin profile, user can see the admin info.
Im using the currentUser to get the id of current user who logged in already in applications.
I'm trying to know how get the another user data.
String currentuser = FirebaseAuth.getInstance().getCurrentUser().getUid();
// init firebase database
mUserDatabaseReference = FirebaseDatabase.getInstance().getReference("Users");
mUserDatabaseReference.child(currentuser).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
// here using Picasso for get the image url and set in ImageView
String imageUrl = dataSnapshot.child("profile_pic").getValue().toString();
Picasso.with(AboutCompany_for_users.this).load(imageUrl).into(companyPhoto);
String name = dataSnapshot.child("name").getValue().toString();
String email = dataSnapshot.child("email").getValue().toString();
String phone = dataSnapshot.child("mobile").getValue().toString();
String busesNumbers = dataSnapshot.child("buses_numbers").getValue().toString();
String lineName = dataSnapshot.child("bus_line").getValue().toString();
// here we get the data from
companyName.setText(name);
companyEmail.setText(email);
companyPhone.setText(phone);
companyBusesNumbers.setText(busesNumbers);
companyLineName.setText(lineName);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
driversInformations.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent driversInfo = new Intent(AboutCompany_for_users.this, CompanyDrivers.class);
startActivity(driversInfo);
}
});
I expect when user click on admin profile show the admin info not current user info
You can't query other user accounts in Firebase Authentication from client code. You will have to either
Store the other user's data in a database, and query that database.
Call some backend code and use the Firebase Admin SDK to perform the query, and return that to the client.
Usually people choose option 1.
Create a Cloud Functions and use the Firebase Admin SDK.
You can get another user data by uid or email or phone number.
And you can list user each by max 1000.
If you create a Cloud Functions using node.js then code is like this.
// get another user data by uid
exports.getUser = functions.https.onCall(async (data, context) => {
try {
// if you want to deny unauthorized user
// - context.auth.token.xxx is customClaims. (if you use)
// if (context.auth || context.auth.uid || context.auth.token.xxx) {
// return Promise.reject("unauthorized");
// }
const user = await admin.auth().getUser(data.uid);
return {
displayName: user.displayName,
email: user.email,
photoURL: user.photoURL
};
} catch (error) {
// If user does not exist
if (error.code === "auth/user-not-found") {
return {};
}
throw error;
}
});
See:
https://firebase.google.com/docs/functions/callable
https://firebase.google.com/docs/auth/admin/manage-users#retrieve_user_data
You can create a Firebase cloud functions and you can call that function from your Android app
Next, under that function, you can retrieve the data of the corresponding user and return it as a result to your Android app.
I'm making an Android application with FireBase and FireBaseAuth for Google Sign in. I have no user-table in my database, so FireBaseAuth doesn't do much other than authenticate the users.
I have a NavigationDrawer in the MainScreen (HomeScreen), where I wish to display the user's profile picture, name and email. Like this example (but with only 1 account / picture):
The user is not Required to sign in to use the app, but some Activities (like Write a Review) requires a user to be signed in. If the user is not signed in, nothing has to be displayed about the user in the NavigationDrawer. However, if there is a signed in user, it's info should be displayed as in the example.
Here is my FireBaseAuth code in ReviewActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reviews);
// Setting up the toolbar:
Toolbar toolbar = findViewById(R.id.Activity_Review_Toolbar);
toolbar.setTitle("Write a review");
// Setting up the database:
firebaseDatabase = FirebaseDatabase.getInstance();
firebaseAuth = FirebaseAuth.getInstance();
reviewDatabaseReference = firebaseDatabase.getReference().child("Reviews");
firebaseAuthStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
if (firebaseUser != null) {
// Already logged in
}
else {
onSignedOutCleanup();
// Not signed in
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setIsSmartLockEnabled(false)
.setAvailableProviders(
Arrays.asList(new AuthUI.IdpConfig.Builder(AuthUI.EMAIL_PROVIDER).build(),
new AuthUI.IdpConfig.Builder(AuthUI.GOOGLE_PROVIDER).build()))
.build(),
RC_SIGN_IN);
}
}
};
}
User sign-in works great, but my question is, how can I store a user's information, based on the Google information from FireBaseAuth? (I'm confident that I will have to create a User-model and a table for users).
Any help is appreciated, thanks!
Assuming you are saving data on firebase realtime database.
Step 1.Get user information from signup.
I'm using a simple email and password. Check the firebase auth docs for federated logins
SignUpService
public void signUpWithEmail(String email, String password) {
this.firebaseAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(task -> {
if(task.isSuccessful()) {
//Has the means to create a user (code step 3)
UserService userService = new UserService();
//A simple firebase user
FirebaseUser firebaseUser = task.getResult().getUser();
//Your version of a user that is optionally converted from a firebase user
UserEntity userEntity = userService.convertFirebaseUserToUser(firebaseUser);
//create the user (code below)
userService.create(userEntity).subscribe(reference -> Log.i(SignUpService.TAG, reference.toString()));
}else{
Log.e(TAG, "Couldnt sign user up");
}
});
return;
}
Step 2. (Optional) Convert FirebaseUser to a user that fits your business rules
//Takes a firebase user and converts them into a user based on your business rules
public UserEntity convertFirebaseUserToUser(FirebaseUser firebaseUser)
{
UserEntity userEntity = new UserEntity();
userEntity.setDisplayName(firebaseUser.getDisplayName());
userEntity.setEmail(firebaseUser.getEmail());
userEntity.setDisplayPhoto(firebaseUser.getDisplayName());
userEntity.setKey(firebaseUser.getUid());
return userEntity;
}
3. Create the user
/**
* Takes a user entity and creates one
* #param userEntity
* #return
*/
public void create(UserEntity userEntity) {
//initialise your backend
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference databaseReference;
//retrieve the firebase key for the user you are about to add
databaseReference = firebaseDatabase.getReference(BASE_PATH).push();
String key = databaseReference.getKey();
//create a user hashmap, with the user key as the hashmaps key, and the user entity as the value <K,V>
Map<String, Object> userEntityHashMap = new HashMap<>();
userEntityHashMap.put(key, userEntity);
//create a listenner for your result
DatabaseReference.CompletionListener completionListener = new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
//returns the reference to your newly created user
if(databaseError != null) {
//handle the incoming user creation error
}
}
};
databaseReference.setValue(userEntity, completionListener);
return;
}
In my opinion a better way of doing this would be to have firebase cloud functions do this work for you on user sign up. If you're curious about moving the actual user profile fetching to your database without having to do it on your client, checkout the authentication triggers for firebase cloud functions. It will push all that functionality to the firebase servers to do for you
How usually its done, you will store it on the SharedPreference to store the user details such as firebaseToken, userId, firstname..etc
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 I signIn with my google account and get the name with the getDisplayName(), my name appear correctly, but in the AuthStateListener doesn't.
here part of my code:
private void handleSignInResult(GoogleSignInResult result) {
Alert.dismissProgress();
if (result.isSuccess()) {
GoogleSignInAccount acct = result.getSignInAccount();
if(acct != null) {
Log.i("NAME", acct.getDisplayName()); <-- RETURN MY NAME CORRECTLY
credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
fuser.linkWithCredential(credential).addOnCompleteListener(authResult);
} else {
//ERROR
}
} else {
//ERROR
}
}
But in my AuthStateListener
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser nuser = firebaseAuth.getCurrentUser();
if (nuser != null) {
Log.i("NAME", nuser.getDisplayName()); <--- RETURN NULL
}
}
Somebody know why this can happen?
This is a tricky one since it is not so clear in the documentation...
Check the getProviderData()
as defined here:
https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseUser#public-method-summary
You can iterate that List and it will have all the providers associated with that account, included a provider with the providerId = "google.com" with a display Name = YOUR_GOOGLE_USERNAME
let me know if you cannot make it work
Just to add to Ymmanuel's answer (Thank you!) with some example code for anyone else looking for a quick copy and paste:
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
String displayName = user.getDisplayName();
Uri profileUri = user.getPhotoUrl();
// If the above were null, iterate the provider data
// and set with the first non null data
for (UserInfo userInfo : user.getProviderData()) {
if (displayName == null && userInfo.getDisplayName() != null) {
displayName = userInfo.getDisplayName();
}
if (profileUri == null && userInfo.getPhotoUrl() != null) {
profileUri = userInfo.getPhotoUrl();
}
}
accountNameTextView.setText(displayName);
emailTextView.setText(user.getEmail());
if (profileUri != null) {
Glide.with(this)
.load(profileUri)
.fitCenter()
.into(userProfilePicture);
}
}
The above will try to use the first display name and photo url from the providers if it wasn't initially found in the User object.
Bonus: Using glide for images: https://github.com/bumptech/glide .
Edmund Johnson is right. This issue was introduced in Firebase Auth 9.8.0. A workaround includes downgrading to 9.6.1 or forcing 're-login' as the info is populated after the user logs out and logs back in. The problem is described in the Firebase issue
It has been reported as a bug to Firebase by one of the Firebase UI contributors - Alex Saveau.
I had the same issue, I solved it by signing out the user and resigning them back in.
Call FirebaseAuth.getInstance().signOut(); to sign them out, then try again.
As I've discovered, this issue is common with using email/password authentication and Social login (Facebook in my case) at the same time.
I found a solution for this problem, in the Firebase documentation!
The solution is to update the user profile using the: UserProfileChangeRequest:
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(mUser.getName())
.setPhotoUri(Uri.parse("https://example.com/mario-h-user/profile.jpg"))
.build();
firebaseUser.updateProfile(profileUpdates)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "User profile updated.");
}
}
});
The variable mUser is already filled with the content from the fields.
I used this piece of code inside the FirebaseAuth.AuthStateListener() -> onAuthStateChanged()
This issue is resolved in the latest verison of firebase ui
compile 'com.firebaseui:firebase-ui:1.2.0'
First let me say there's no need to downgrade the Gradle files or logout and login the user multiple times as stated by others just to display the user name. I've solved the issue a different way while still keeping the latest Gradle files and not having to log the user out and in multiple times. The issue with getDisplayName() is a very big one so I want to be as descriptive as possible for future users of Firebase to spare them the headache.
Here are the details of the solution:
Solution 1:
For users who authenticate(sign-in) with multiple providers such as Facebook, Google etc. and/or Email/Password that they created at sign-up:
The first thing you want to ensure is that when you have a user sign-up with the app for the first time you store their name of course to the database under their unique id. Which may look something like this:
// Method signature. Write current user's data to database
private void writeNewUser(String userId, String name, String email) {
DatabaseReference current_user_database = mDatabaseRef.child(userId);
current_user_database.child("username").setValue(name);
// Email here is not mandatory for the solution. Just here for clarity of the
// method signature
current_user_database.child("email").setValue(email);
}
After the user's name has been stored in your Firebase database and you have them sign into your app you can get their username something like this:
// Method that displays the user's username
private void showUserName() {
// Get instance of the current user signed-in
mFirebaseUser = mAuth.getCurrentUser();
// Check if user using sign-in provider account is currently signed in
if (mFirebaseUser != null) {
// Get the profile information retrieved from the sign-in provider(s) linked to a user
for (UserInfo profile : mFirebaseUser.getProviderData()) {
// Name of the provider service the user signed in with (Facebook, Google, Twitter, Firebase, etc.)
String name = profile.getDisplayName();
// If displayName() is null this means that the user signed in using the email and password they created. This is the null issue we shouldn't get that we are gonna be solving below.
if(name == null){
mDatabaseRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get the name the user signed-up with using dataSnapshot
String nameOfCurrentUser = (String) dataSnapshot.child("name").getValue();
// Set username we retrieved using dataSnapshot to the view
mTestUsernameTextView.setTitle(nameOfCurrentUser);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
// If the name is not null that means the user signed in with a social Auth provider such as Facebook, Twitter, Google etc.
if(name != null) {
// Set the TextView (or whatever view you use) to the user's name.
mTestUsernameTextView.setText(name);
}
} // End for
} // End if
}
That's it. Now you just call that method showUserName() or whatever your method is gonna be called inside your onCreate and hopefully this helps.
Solution 2:
For users who sign into your app using ONLY a social media service provider such as Facebook, Twitter, Google or whatever other option Firebase allows:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
for (UserInfo profile : user.getProviderData()) {
// Id of the provider (ex: google.com)
String providerId = profile.getProviderId();
// UID specific to the provider
String uid = profile.getUid();
// Name, email address, and profile photo Url
String name = profile.getDisplayName();
String email = profile.getEmail();
Uri photoUrl = profile.getPhotoUrl();
};
}
That's it for solution 2, just follow the guidelines on Firebase for that and you should be good.
Here's a link to it if you're curious:
Get a user's profile information
I truly hope this helps anyone struggling with the getDisplayName() issue.
Conclusion:
If your app only has Facebook, Twitter, Google or whatever else social media sign-in options Firebase provides then just simply calling getDisplayName()method on the currently signed in user should be enough to show their username.
Otherwise if your app allows the user to sign in using an email/password they created then make sure you got their name/username at sign-up so that you can use it later on to display it.
I was getting this problem when I had:
implementation 'com.google.firebase:firebase-auth:10.0.0'
implementation 'com.firebaseui:firebase-ui-auth:1.0.1'
A workaround that fixed it for me was to replace that with:
implementation 'com.google.firebase:firebase-auth:9.6.0'
implementation 'com.firebaseui:firebase-ui-auth:0.6.0'
Iterating through user.getProviderData() as suggested elsewhere didn't fix it for the later versions.
Based on Alan's and Ymmanuel's answers here's the 2 helper methods that I'm using:
public static String getDisplayName(FirebaseUser user) {
String displayName = user.getDisplayName();
if (!TextUtils.isEmpty(displayName)) {
return displayName;
}
for (UserInfo userInfo : user.getProviderData()) {
if (!TextUtils.isEmpty(userInfo.getDisplayName())) {
return userInfo.getDisplayName();
}
}
return null;
}
public static Uri getPhotoUrl(FirebaseUser user) {
Uri photoUrl = user.getPhotoUrl();
if (photoUrl != null) {
return photoUrl;
}
for (UserInfo userInfo : user.getProviderData()) {
if (userInfo.getPhotoUrl() != null) {
return userInfo.getPhotoUrl();
}
}
return null;
}
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