Firebase problems getting uid within Flutter function - firebase

Hi I have reviewed previous answers to similar questions (eg here) but they do not fix my issue.
I have an app in which the user records and audio snippet which is then uploaded to firebase storage. Everything works in general, but currently there is no folder structure (so all users files would save to the same top level). Therefore I am trying to call a user uid to create a unique user foler. Since the user also logs in to firestore DB first I have a specified user.uid
I have a method to call the current user
Future getCurrentUser() async {
final FirebaseUser user = await _auth.currentUser(); # _auth is instance of FirebaseAuth
return user;
If I attach this to an onPressed event of a button I get the following
flutter: user Information is
flutter: D3sR4sKXXXXYToYQrmkkxmBNGvWq1
However if I call the same function within my 'stop' recording function I get a different result.
Stop recording () async {
// some audio commands....
var folder = _auth.getCurrentUser().toString();
print('Folder name is: ' + folder);
This gives me
flutter: folder name is: Instance of 'Future<dynamic>'
I don't know if this is connected but I noticed some differences in the firestore response compared to some older online tutorials. For example, if I change my current user method as suggested in other StackOverflow examples (eg here ) to
Future getCurrentUser() async {
final FirebaseUser user = await _auth.currentUser();
return user.uid;
I get the following exception whether called in code or via onPressed(though the command completes),
flutter: user Information is
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: Class 'String' has no instance getter 'uid'.
Receiver: "D3sR4sKXXXXYToYQrmkkxmBNGvWq1"
I do not get this message when calling user.uid directly from the response from the users initial firestore login.

This:
Stop recording () async {
// some audio commands....
var folder = _auth.getCurrentUser().toString();
print('Folder name is: ' + folder);
gives you a Future because the method that you created returns a Future which means it is asynchronous, that's why you use async/await to get the data from the future operation:
Future<FirebaseUser> getCurrentUser() async {
return await _auth.currentUser();
}
And now when you call this method you can do the following:
FirebaseUser userResult = await getCurrentUser();
print(userResult.uid);
Basically currentUser() returns a Future<FirebaseUser>, and the FirebaseUser class extends the class UserInfo which contains the property uid.
https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_auth/firebase_auth/lib/src/user_info.dart

Related

Flutter Firebase DocumentReference.set() is not completing

My application was writing to Firestore but suddenly stopped working. When I try to write to Firestore my write method does not complete. I have made the following simple test method to troubleshoot my problem but can't seem to figure out what is going on:
//In database.dart
Future<void> testSet() async {
final reference = FirebaseFirestore.instance.doc('users/test');
await reference.set({'TEST': 'Value'});
print('This is never printing');
}
//In home_page.dart called via clicking a button
Future<void> _testSet(context) async {
final database = Provider.of<Database>(context, listen: false);
await database.testSet();
}
I have tried emptying my Firestore Database as well as adding a users collection; however nothing has worked. Why am I unable to write to Firestore?

Firebase Auth authStateChanges trigger

I'm using firebase to authenticate a user and create a user in firestore database :
final auth.FirebaseAuth _firebaseAuth;
Future<void> signUp(
{#required String email, #required String password}) async {
assert(email != null && password != null);
try {
await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
await createUserInDatabaseIfNew();
} on Exception {
throw SignUpFailure();
}
}
With firebase, once the method .createUserWithEmailAndPassword() is executed, it triggers right after the authStateChanges which I am using in my code to send the new user in the user stream, and eventually retrieve its data from the database
Stream<User> get user {
return _firebaseAuth.authStateChanges().map((firebaseUser) {
return firebaseUser == null ? User.empty : firebaseUser.toUser;
});
}
StreamSubscription<User> _userSubscription = _authenticationRepository.user.listen((user) {
return add(AuthenticationUserChanged(user));}
if(event is AuthenticationUserChanged){
if(event.user != User.empty){
yield AuthenticationState.fetchingUser();
User userFromDatabase;
try{
var documentSnapshot = await _firebaseUserRepository.getUser(event.user.id);
userFromDatabase = User.fromEntity(UserEntity.fromSnapshot(documentSnapshot));
yield AuthenticationState.authenticated(userFromDatabase);
}
The problem that I am facing, is that because of _firebaseAuth.createUserWithEmailAndPassword, _firebaseAuth.authStateChanges is triggerd before the user is created in the database, and eventually when I try to retrieve that user, it still does not exist in the database.
I would like _firebaseAuth.authStateChanges() to be triggered after my method createUserInDatabaseIfNew runs.
How could I achieve that ?
I would like _firebaseAuth.authStateChanges() to be triggered after my method createUserInDatabaseIfNew runs.
The auth state change listener fires when the user's authentication state change, which is when their sign in completes. There's no way to change this behavior, nor should there be.
If you want to trigger when the user's registration in your app has completed, you should respond to events that signal that. So if registration means that the user is written to the database, you can use a onSnapshot listener on the database to detect user registration.
You could even combine the two:
Use an auth state change listener to detect when the sign in completes.
Inside that auth state listener, then attach a snapshot listener for the user's registration document.

Error: 'currentUser' isn't a function or method and can't be invoked [duplicate]

This question already has answers here:
Undefined class 'FirebaseUser'
(6 answers)
Closed 2 years ago.
I just updated Google Firebase Auth in Flutter app because I was getting some wried SDK errors but now I'm getting:
Error: 'currentUser' isn't a function or method and can't be invoked.
User currentFirebaseUser = await FirebaseAuth.instance.currentUser();
I looked at the migration guide and understand that currentUser() is now synchronous via the currentUser getter. but I'm not sure how I should change my code now to fix this.
static void getCurrentUserInfo() async{
User currentFirebaseUser = await FirebaseAuth.instance.currentUser();
String userid = currentFirebaseUser.uid;
DatabaseReference userRef = FirebaseDatabase.instance.reference().child('users/$userid');
userRef.once().then((DataSnapshot snapshot){
if(snapshot.value != null){
}
});
}
you need to remove await and change currentUser() to currentUser.
So
User currentFirebaseUser = await FirebaseAuth.instance.currentUser();
Becomes
User currentFirebaseUser = FirebaseAuth.instance.currentUser;
Source: Verify email link and sign in
Let me know if this works ^_^
Its done like this :
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String userid = user.getUid();

How to listen firebase updates in real time in Flutter

I have a stream which read user data from firebase. I trigger it after signin, it works perfectly. I show the data in my appbar. When I update firebase manually, I want to see the new date instantly on my appbar. First, I guessed there is something wrong with my appbar but then I noticed that my stream do not triggered when I update firebase data. Here is my stream code snippet. What am I missing?
static Future<User> userDataStream(userID) async {
print("userDataStream");
final databaseReference = Firestore.instance;
User currentUser = User();
await for (var snapshot in databaseReference
.collection('users')
.where('userID', isEqualTo: userID)
.snapshots()) {
currentUser.userName = snapshot.documents.first.data['userName'];
currentUser.email = snapshot.documents.first.data['email'];
currentUser.userID = snapshot.documents.first.data['userID'];
currentUser.level = snapshot.documents.first.data['level'];
currentUser.balance = snapshot.documents.first.data['balance'];
print(currentUser.balance);
return currentUser;
}
return currentUser;
}
How you are using this stream matters. await for starts listening to the user, then you do return currentUser; in it and break the await for. Therefore, it cannot keep listening to the stream in the future.
Instead of the return currentUser; inside await for, you can do something like setState((){this.renderedUser = currentUser;}) so that the user that comes from the server becomes the rendered one. If you do that, also add if (!mounted) return; inside the await for so that you stop listening to it when you realize you are in a different screen.
A better alternative may be to use the StreamBuilder widget.
If you run your current code, and make a change to the database, the print statement should be run again. That's because the snapshots is already listening for changes to the database, and calling your code when those happens.
The problem is that you return a Future<User> and a future can only be resolved (get a value) once. If you want to return live data that'd be a Stream<User> (and typically a StreamBuilder instead of a FutureBuilder to build a UI from it).

Google Firestore Database: Where are phantom document reads coming from? [duplicate]

there guys, I do have an interesting problem here and I would be really glad if any of you it will be able to help me with that.
What's my app flow:
Register with the email, password and some other details:
User firebase in order to auth the user and create an account via email and password, at the same time I'm writing the custom data of the user to the database.
Log in the user.
That's it, that's all my basic logic, and how you can see I'm not doing any reading from the DB so far as I know.
Now... the problem is that from some weird reason when I'm registering my user I'm going to the firebase console to see the usage of my DB and I will see something like... for one user which was created I will have 1 write (which is fine as I was expected) but also 13-20 READS FROM DB.
Now that's my question, WHY on earth I have reads on firestorm when I'm doing just auth and writes?
Here it's my DB code which I'm using right now.
class DatabaseFirebase implements BaseDataBase {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final FirebaseStorage _storage = FirebaseStorage.instance;
FirebaseUser _firebaseUser;
Firestore _firestore = Firestore.instance;
#override
Future<String> login(String email, String password) async {
_firebaseUser = await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
return _firebaseUser.uid;
}
#override
Future<String> register(String email, String password) async {
_firebaseUser = await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
return _firebaseUser.uid;
}
#override
Future<UserData> getCurrentUser() async {
if (_firebaseUser == null)
_firebaseUser = await _firebaseAuth.currentUser();
UserData user = UserData();
user.email = _firebaseUser?.email;
user.name = _firebaseUser?.displayName;
return user;
}
#override
Future<void> logout() async {
_firebaseAuth.signOut();
}
#override
Future<void> onAuthStateChanged(void Function(FirebaseUser) callback) async {
_firebaseAuth.onAuthStateChanged.listen(callback);
}
#override
Future<void> writeUser(UserData user) async {
_firestore.collection("Users").add(user.toMap()).catchError((error) {
print(error);
});
}
}
If some of you know could you explain to me where/how I need to search in order to find this bug? Because how you can see I'm not using any read what so ever.
It's impossible to know for sure given that we don't understand all possible routes of access into your database, but you should be aware that use of the Firebase console will incur reads. If you leave the console open on a collection/document with busy write activity, the console will automatically read the changes that update the console's display. This is very often the source of unexpected reads.
Without full reproduction steps of exactly all the steps you're taking, there's no way to know for sure.
Firebase currently does not provide tools to track the origin of document reads. If you need to measure specific reads from your app, you will have to track that yourself somehow.

Resources