Flutter - firebase_auth updateProfile method is not working - firebase

I'm creating app using Flutter with Firebase. I have some weird issues. I'm creating authentication and it is working fine but when i try to add some collections to my Firestore Database, the record of displayName is set to null.
Future<FirebaseUser> createUser(email, password, displayName) async {
final FirebaseUser user = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
UserUpdateInfo info = new UserUpdateInfo();
info.displayName = displayName;
_auth.updateProfile(info);
Firestore.instance.collection('users').document().setData({
'name': user.displayName,
'uid': user.uid,
'email': user.email,
'isEmailVerified': user.isEmailVerified,
'photoUrl': user.photoUrl,
});
return user;
}
this is Future class that creates user.
void _handleSubmitted() {
userAuth
.createUser(
emailController.text, passwordController.text, nameController.text)
.then((onValue) {
print("Sign Up button clicked: $onValue");
});
}
this method is handle when sign up button is clicked.
and collection looks like this picture.

If I recall correctly, the local user profile is not immediately updated when you call updateDisplayName or updatePhotoURL. This means you should either just write the local values to the database (easiest) or force a reload of the profile (safest).
Write the local values
As said, this is the simplest approach:
FirebaseFirestore.instance.collection('users').doc().set({
'name': displayName,
'uid': user.uid,
'email': user.email,
'isEmailVerified': user.emailVerified, // will also be false
'photoUrl': user.photoURL, // will always be null
});
Note that emailVerified will always be false, and photoUrl will always be null on a newly created email+password account.
Force a reload of the profile
You can force a reload of the user data by calling FirebaseUser.reload():
await _auth.currentUser!.updateDisplayName(displayName);
await _auth.currentUser!.updateEmail(newEmail);
await _auth.currentUser!.updatePhotoURL(photoURL);
await _auth.currentUser!.reload();
user = _auth.currentUser;

To Update users display name and photo url this will definitely helpful.
FirebaseUser user = await FirebaseAuth.instance.currentUser();
UserUpdateInfo userUpdateInfo = new UserUpdateInfo();
userUpdateInfo.displayName = name;
userUpdateInfo.photoUrl = url;
user.updateProfile(userUpdateInfo);

It's inconvenient the way Firebase Auth works, and they say it won't change for now, so I made a package to address this, grab it here: firebase_user_stream
In the Readme I explain the issues and how the package fixes them, there are examples and etc, enjoy!
EDIT (Jul/2020):
Firebase Auth for Flutter now has a userChanges stream:
which triggers whenever auth state, id token or profile changes occur. Essentially, this acts as a way to obtain realtime changes on currently stateless functionality (such as updateProfile).

I also tried everything but however, this works for me! Just call the FirebaseAuth.instance twice like the one in the code.
FirebaseUser currentUser = await _auth.currentUser();
await currentUser.reload();
currentUser = await _auth.currentUser();
print("Current User ${currentUser.displayName}");
print("Current User ${currentUser.photoUrl}");
hope this helps you!

Related

Registered user not showing in firebase firestore

In short, I want my Authenticated user by Email and Password in firebase firestore,
After successfully register my users only appears in a authentication pannel.
I am currently working with Flutter application where I use firebase_auth: ^1.1.1 package.
So I expect that after
UserCredential userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: "abc#example.com",
password: "SuperSecretPassword!"
);
The function called from firebase_auth package which is createUserWithEmailAndPassword
I want this registed user in Firebase Database.
Firebase authentication is used to register a user while firestore is used for storing data. If you want to add the user to firestore also then you need to add the cloud_firestore plugin to your pubspec.yaml file:
dependencies:
flutter:
sdk: flutter
cloud_firestore: ^1.0.7
Then you can do:
final firestoreInstance = FirebaseFirestore.instance;
var firebaseUser = FirebaseAuth.instance.currentUser;
firestoreInstance.collection("users").doc(firebaseUser.uid).set(
{
"email" : "abc#example.com",
}).then((_){
print("success!");
});
This will create a collection called users with a document id equal to the authenticated user id, and inside of it you will have the email of the user.
.createUserWithEmailAndPassword creates a user in auth, if you check your auth tab you should see created user. It does not create user in firestore
for this you have to implement yourself .
below is a sample example
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
User user = (await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password))
.user;
//if create user succeeds
var user =UserModel(
userID:user.uid,
email:user.email)
FirebaseFirestore.instance
//save user based on their id from auth
.doc("users/${user.uid}")
.set(user.toJson());
Edit
you can create a user model
example:
class UserModel {
final String userID;
final String displayName;
final String email, pushToken;
final String phoneNumber;
final String profilePictureURL, dateJoined;
UserModel({
this.dateJoined,
this.userID,
this.email,
});
Map<String, Object> toJson() {
return {
'userID': userID,
'email': email == null ? '' : email,
'appIdentifier': 'my app',
'dateJoined': DateTime.now(),
};
}
}
....
check how to use json
In addition to the griffins answer, you could use a cloud function to respond to the user creation event (trigger onCreated). Then you can create the users collection, asynchronously, without overloading the flutter client. For example, an index.ts with the createUserInFirestore function:
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp();
const db = admin.firestore();
export const createUserInFirestore = functions.auth.user().onCreate(
async (user) => {
return db.collection('users').doc(user.uid).set({
"email" : user.email,
"name" : user.displayName,
});
}
);

How can i check user id in login section?

I use Google sign in button with google package.
If user choose sign in with google, and if user login first time, then i want to create his/her account, but my code create when she/he login to app, everytime create like new user. I want to check with if statement, but how i do not know. If user uid exist in firestore, then it have not to be create new account.
This is my google sign in login function:
Future login() async {
isSigningIn = true;
final user = await googleSignIn.signIn();
if (user == null) {
isSigningIn = false;
return;
} else {
final googleAuth = await user.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
await FirebaseAuth.instance.signInWithCredential(credential);
FirebaseFirestore.instance.collection('users').add({
'email': user.email,
'username': user.displayName,
'uid': user.id,
'userPhotoUrl': user.photoUrl
});
isSigningIn = false;
}
}
Firestore console image here
If you want to store per-user information in Firestore, you should use the user's UID as the ID of the document. It's guaranteed to be unique per user. Don't use add() to add the document with a random ID, use set() with the known ID to read and create the document.
Also, you should know that signInWithCredential returns the known user object, which lets you get their UID.
UserCredential userCrediental = await FirebaseAuth.instance.signInWithCredential(credential);
String uid = userCredential.user.uid;
await FirebaseFirestore.instance.collection('users').doc(uid).set(...)
If you want to check if the document was already created for that user, you can simply try to get() it first and see if it exists.
I solve this problem with my friend which is good person.
I replace this code :
await FirebaseAuth.instance.signInWithCredential(credential);
because there is a logical problem.

How can I add some data to firestore as per user logged in, as well as how can I create the profile of the user?

I'm developing a restaurant application with flutter, I want to use firestore as my database and I've already authenticated with firebase with the help of Andrea Bizzotto's YouTube tutorial of authentication but I'm not able to understand any tutorial or either not able to integerate into the login/signup page for creating a user info in cloud firestore, can someone give me a way to do this, just give a basic introduction or direction to find a way to complete it. Thanks in advance.
after you sign up the user with firebase auth if it's successful you should then run this method to update his data.
Future<dynamic> updateUserData(FirebaseUser user, String photoUrl, String displayName) async {
final Firestore _db = Firestore.instance;
DocumentSnapshot snapshot =
await _db.collection('users').document(user.uid).get();
DocumentReference ref = _db.collection('users').document(user.uid);
if (snapshot.exists) {
return ref;
} else {
return Firestore.instance.runTransaction((Transaction tx) async {
return tx.set(
ref,
{
'uid': user.uid,
'email': user.email,
'name': displayName,
'photo': photoUrl,
'lastSeen': DateTime.now()
},
);
}).then((val) => val.length);
}
}

Flutter: Firebase authentication create user without logging In

I have a user management feature in my flutter app that uses firebase authentication. I can register new user accounts using firebase_auth's createUserWithEmailAndPassword() function.
return await FirebaseAuth.instance.
createUserWithEmailAndPassword(email: email, password: password);
The problem is when the registration is successful it automatically authenticates my FirebaseAuth instance as the new user even though I am already logged in.
I came across this answer: Firebase kicks out current user but it's in javascript and has a slightly different api.
How can I do the equivalent in dart?
Updated: firebase_core ^0.5.0 and firebase_auth ^0.18.0+1 has deprecated some of the old classes.
Below is code updated for firebase_core ^0.5.1 and firebase_auth ^0.18.2.
static Future<UserCredential> register(String email, String password) async {
FirebaseApp app = await Firebase.initializeApp(
name: 'Secondary', options: Firebase.app().options);
try {
UserCredential userCredential = await FirebaseAuth.instanceFor(app: app)
.createUserWithEmailAndPassword(email: email, password: password);
}
on FirebaseAuthException catch (e) {
// Do something with exception. This try/catch is here to make sure
// that even if the user creation fails, app.delete() runs, if is not,
// next time Firebase.initializeApp() will fail as the previous one was
// not deleted.
}
await app.delete();
return Future.sync(() => userCredential);
}
Original Answer
I experimented with the firebase authentication api and my current working solution is:
// Deprecated as of `firebase_core ^0.5.0` and `firebase_auth ^0.18.0`.
// Use code above instead.
static Future<FirebaseUser> register(String email, String password) async {
FirebaseApp app = await FirebaseApp.configure(
name: 'Secondary', options: await FirebaseApp.instance.options);
return FirebaseAuth.fromApp(app)
.createUserWithEmailAndPassword(email: email, password: password);
}
Essentially it comes down to creating a new instance of FirebaseAuth so the automatic login from createUserWithEmailAndPassword() do not affect the default instance.
Based on Swift's answer I post updated code for this work around.
Future signUpWithEmailPasswordAdminPastor(String email, String password, String role, String nama, String keuskupan, String kevikepan, String paroki) async {
try {
FirebaseApp tempApp = await Firebase.initializeApp(name: 'temporaryregister', options: Firebase.app().options);
UserCredential result = await FirebaseAuth.instanceFor(app: tempApp).createUserWithEmailAndPassword(
email: email, password: password);
// create a new document user for the user with uid
await DatabaseService(uid: result.user.uid).updateUserDataSelf(
true,
role,
nama,
keuskupan,
kevikepan,
paroki,
'',
DateTime.now(),
DateTime.now());
tempApp.delete();
return 'OK';
} catch (e) {
print(e.toString());
return null;
}
}
Above code works for firebase_core: ^0.5.0 and firebase_auth: ^0.18.0+1.

Example of Firebase Auth with Email and Password on Flutter?

First time implementing Firebase Auth, also new to Flutter dev, and I'm looking to use email and passwords, not Google sign-in. The only examples I see of Firebase Auth being used are anonymously or with Google. Is there a resource / tutorial that shows how to properly set up the calls with the signInWithEmailAndPassword method?
Many thanks!
In my app I have an auth class because I don't like to litter my widget classes with non-widget code, but you can plop this code inside your widget class if you want.
In auth.dart I have:
import 'package:firebase_auth/firebase_auth.dart';
class Auth {
final FirebaseAuth auth = FirebaseAuth.instance;
Future<User> handleSignInEmail(String email, String password) async {
UserCredential result =
await auth.signInWithEmailAndPassword(email: email, password: password);
final User user = result.user!;
return user;
}
Future<User> handleSignUp(email, password) async {
UserCredential result = await auth.createUserWithEmailAndPassword(
email: email, password: password);
final User user = result.user!;
return user;
}
}
Then in my login/register screen I create an instance of my auth class:
var authHandler = new Auth();
Finally, in my login buttons onPressed callback I have:
onPressed: () {
authHandler.handleSignInEmail(emailController.text, passwordController.text)
.then((FirebaseUser user) {
Navigator.push(context, new MaterialPageRoute(builder: (context) => new HomePage()));
}).catchError((e) => print(e));
}
Here is one example from my service. I ask for the email, name and password fields.
registerWithEmail(String name, String email, String password) async {
First I check if the email is already registered with facebook or something.
List<String> providers = await firebaseAuth.fetchProvidersForEmail(email: email);
This is not ideal solution, but you want to handle if the user is already registered, and than link email with current user
if (providers != null && providers.length > 0) {
print("already has providers: ${providers.toString()}");
return handleProviders(providers);
}
Create new User
FirebaseUser newUser = await firebaseAuth.createUserWithEmailAndPassword(email: email, password: password);
await newUser.sendEmailVerification();
This is basically it. I update the name filed of the user, since I have it.
var userUpdateInfo = new UserUpdateInfo();
userUpdateInfo.displayName = name;
await firebaseAuth.updateProfile(userUpdateInfo);
await newUser.reload();
And later You can save the user inside your firestore, where user uid is document ID. So I can get it later.
Git repo with full explanation example for Email/Password Sign in Firebase using flutter
This may help you.
Git Repo: https://github.com/myvsparth/firebase_email_signin
Full Article Step by Step: https://www.c-sharpcorner.com/article/how-to-do-simple-login-with-email-id-in-flutter-using-google-firebase/
This code is for register new user
fb_auth.UserCredential userCredential = await fb_auth
.FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
And this is for login previous user
fb_auth.UserCredential userCredential = await fb_auth
.FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password)
And that fb_auth is
import 'package:firebase_auth/firebase_auth.dart' as fb_auth;

Resources