Reputation: 153
i am currently following this tutorial (https://www.youtube.com/watch?v=y6OlrO3Bzag) on how to create a flutter chat app. the problem that i am facing is that whenever i sign up a new account, it will display an error has occurred and doesn't direct me to the home screen. however, if i sign in or hot restart, i will be able to go to the home screen. i have the logs below but am not sure what is going wrong. any help would be greatly appreciated. the source code is found here: https://github.com/HayesGordon/chatter
firebase_functions/unauthenticated] UNAUTHENTICATED<…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m<…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m#0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:607:7)<…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m#1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:167:18)<…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m<asynchronous suspension><…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m#2 MethodChannelHttpsCallable.call (package:cloud_functions_platform_interface/src/method_channel/method_channel_https_callable.dart:23:24)<…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m<asynchronous suspension><…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m#3 HttpsCallable.call (package:cloud_functions/src/https_callable.dart:49:37)<…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m<asynchronous suspension><…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m#4 _SignUpScreenState._signUp (package:ibchat/screens/sign_up_screen.dart:368:25)<…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m<asynchronous suspension><…>
flutter: \^[[38;5;196m│ \^[[0m\^[[39m\^[[48;5;196m<…>
flutter: \^[[38;5;196m├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄<…>
flutter: \^[[38;5;196m│ #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:607:7)<…>
flutter: \^[[38;5;196m│ #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:167:18)<…>
flutter: \^[[38;5;196m│ #2 <asynchronous suspension><…>
flutter: \^[[38;5;196m│ #3 MethodChannelHttpsCallable.call (package:cloud_functions_platform_interface/src/method_channel/method_channel_https_callable.dart:23:24)<…>
flutter: \^[[38;5;196m│ #4 <asynchronous suspension><…>
flutter: \^[[38;5;196m│ #5 HttpsCallable.call (package:cloud_functions/src/https_callable.dart:49:37)<…>
flutter: \^[[38;5;196m│ #6 <asynchronous suspension><…>
flutter: \^[[38;5;196m│ #7 _SignUpScreenState._signUp (package:ibchat/screens/sign_up_screen.dart:368:25)<…>
flutter: \^[[38;5;196m├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄<…>
flutter: \^[[38;5;196m│ ⛔ Sign up error<…>
flutter: \^[[38;5;196m└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────<…>
Error: Do not use BuildContexts across async gaps. (with **)
Future<void> _signUp() async {
if (_formKey.currentState!.validate()) {
setState(() {
_loading = true;
});
try {
// Authenticate with Firebase
final creds =
await firebase.FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
);
final user = creds.user;
if (user == null) {
**ScaffoldMessenger.of(context)**.showSnackBar(
const SnackBar(content: Text('Member not found')),
);
return;
}
// Set Firebase display name and profile picture
List<Future<void>> futures = [
if (_profilePictureController.text.isNotEmpty)
creds.user!.updatePhotoURL(_profilePictureController.text),
creds.user!.updateDisplayName(_nameController.text),
];
await Future.wait(futures);
// Create Stream user and get token using Firebase Functions
final callable = functions.httpsCallable('createStreamUserAndGetToken');
final results = await callable();
// Connect user to Stream and set user data
final client = **StreamChatCore.of(context)**.client;
await client.connectUser(
User(
image: _profilePictureController.text,
id: creds.user!.uid,
name: _nameController.text,
/*designation: _designationController.text,
company: _companyController.text,*/
),
results.data,
);
// Navigate to home screen
await **Navigator.of(context)**.pushReplacement(HomeScreen.route);
} on firebase.FirebaseAuthException catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.red, content: Text(e.message ?? 'Auth error')),
);
} catch (e, st) {
logger.e('Sign up error', e, st);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(backgroundColor: Colors.red, content: Text('An error occured')),
);
}
setState(() {
_loading = false;
});
}
}
Future<void> _signIn() async {
if (_formKey.currentState!.validate()) {
setState(() {
_loading = true;
});
try {
// Authenticate with Firebase
final creds =
await firebase.FirebaseAuth.instance.signInWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
);
final user = creds.user;
if (user == null) {
**ScaffoldMessenger.of(context)**.showSnackBar(
const SnackBar(content: Text('Member not found')),
);
return;
}
// Get Stream user token from Firebase Functions
final callable = functions.httpsCallable('getStreamUserToken');
final results = await callable();
// Connnect stream user
final client = **StreamChatCore.of(context)**.client;
await client.connectUser(
User(id: creds.user!.uid),
results.data,
);
// Navigate to home screen
await **Navigator.of(context)**.pushReplacement(HomeScreen.route);
} on firebase.FirebaseAuthException catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: Colors.red,
content: Text(e.message ?? 'Authentication error')),
);
} catch (e, st) {
logger.e('Sign in error, ', e, st);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
backgroundColor: Colors.red, content: Text('Error occured')),
);
}
setState(() {
_loading = false;
});
}
}
Future<void> _handleAuthenticatedState() async {
final auth = firebase.FirebaseAuth.instance;
if (!mounted) {
return;
}
listener = auth.authStateChanges().listen((user) async {
if (user != null) {
// get Stream user token
final callable =
FirebaseFunctions.instance.httpsCallable('getStreamUserToken');
final results = await Future.wait([
callable(),
// delay to show loading indicator
Future.delayed(const Duration(milliseconds: 700)),
]);
// connect Stream user
final client = **StreamChatCore.of(context)**.client;
await client.connectUser(
User(id: user.uid),
results[0]!.data,
);
// authenticated
**Navigator.of(context)**.pushReplacement(HomeScreen.route);
} else {
// delay to show loading indicator
await Future.delayed(const Duration(milliseconds: 700));
// not authenticated
**Navigator.of(context)**.pushReplacement(SignInScreen.route);
}
});
}
Future<void> _signOut() async {
setState(() {
_loading = true;
});
try {
await StreamChatCore.of(context).client.disconnectUser();
await firebase.FirebaseAuth.instance.signOut();
**Navigator.of(context)**.pushReplacement(SplashScreen.route);
} on Exception catch (e, st) {
logger.e('Could not sign out', e, st);
setState(() {
_loading = false;
});
}
}
Upvotes: 0
Views: 341
Reputation: 271
I'm the author of the video tutorial you linked above.
For anyone reading this and who is interested in Firebase Auth + Stream, please see our updated Flutter guide: https://getstream.io/chat/docs/sdk/flutter/guides/token_generation_with_firebase/
Stream now has a Firebase extension to easily manage the heavy lifting for you. So the video above needs an updated version.
To answer your question:
It seems like the call to "createStreamUserAndGetToken" cloud function is happening even though the Firebase user is not authenticated. I see you created a ticket for this on the repo here: https://github.com/HayesGordon/chatter/issues/8
So let's discuss it further there.
With regards to your limiting issue for "BuildContexts across async gaps" see here: https://dart-lang.github.io/linter/lints/use_build_context_synchronously.html
Upvotes: 0