This question already has answers here:
Undefined class 'FirebaseUser'
(6 answers)
Closed 2 years ago.
I am in the process of migrating this code to the latest version of firebase and the only part I am struggling with at the moment is this code from my auth.dart file.
#override
Stream<Users> get onAuthStateChanges {
return _firebaseAuth.onAuthStateChanges.map(_userFromFirebase);
}
To migrate to the latest version, I wrote it this way:
#override
Stream<Users> get authStateChanges {
return _firebaseAuth.authStateChanges.map(_userFromFirebase);
}
I keep getting this error:
The method 'map' isn't defined for the type 'Function'.
I can't seem to find any documentation on how to write it properly. Would someone happen to know how to fix this?
Thanks in advance for your help
PS
In case you're wondering why I'm migrating this code, my Emulator keeps complaining that the Firebase Core plugin is missing (I guess due to the Google-services.json file) and none of the authentication buttons work. Upon clicking I get this "return firebase.google.cms" error". The Simulator was working fine until I did a recent update on Xcode and now it's giving me this weird error code and will not complete the flutter run. So I figured if I get the latest version of firebase and update the code, accordingly, I can use my Simulator and/or Emulator again. Then I encountered the above problem with the authStateChanges.map code and here we are.
Here is my auth.dart file in its entirety for your reference:
class Users {
final String uid;
Users({#required this.uid});
}
abstract class AuthBase {
Stream<Users> get authStateChanges;
Future<Users> currentUser();
Future<Users> signInAnonymously();
Future<Users> signInWithEmailAndPassword(String email, String password);
Future<Users> createUserWithEmailAndPassword(String email, String password);
Future<Users> signInWithGoogle();
Future<void> signOut();
}
class Auth implements AuthBase {
final _firebaseAuth = FirebaseAuth.instance;
//To avoid confusion due to updates, "Users" come from the class Users and "User" replaces the deprecated "FirebaseUser".
Users _userFromFirebase(User user) {
if (user == null) {
return null;
}
return Users(uid: user.uid);
}
#override
Stream<Users> get authStateChanges {
return _firebaseAuth.authStateChanges.map(_userFromFirebase);
}
#override
Future<Users> currentUser() async {
final user = _firebaseAuth.currentUser;
return _userFromFirebase(user);
}
#override
Future<Users> signInAnonymously() async {
final authResult = await _firebaseAuth.signInAnonymously();
return _userFromFirebase(authResult.user);
}
#override
Future<Users> signInWithEmailAndPassword(String email, String password) async {
final authResult = await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
return _userFromFirebase(authResult.user);
}
#override
Future<Users> createUserWithEmailAndPassword(
String email, String password) async {
final authResult = await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
return _userFromFirebase(authResult.user);
}
#override
Future<Users> signInWithGoogle() async {
final googleSignIn = GoogleSignIn();
final googleAccount = await googleSignIn.signIn();
if (googleAccount != null) {
final googleAuth = await googleAccount.authentication;
if (googleAuth.accessToken != null && googleAuth.idToken != null) {
final authResult = await _firebaseAuth.signInWithCredential(
GoogleAuthProvider.credential(
idToken: googleAuth.idToken, accessToken: googleAuth.accessToken),
);
return _userFromFirebase(authResult.user);
} else {
throw PlatformException(
code: 'ERROR_MISSING_GOOGLE_AUTH_TOKEN',
message: 'Missing Google Auth Token');
}
} else {
throw PlatformException(
code: 'ERROR_ABORTED_BY_USER', message: 'Sign in aborted by user');
}
}
#override
Future<void> signOut() async {
final googleSignin = GoogleSignIn();
await googleSignin.signOut();
await _firebaseAuth.signOut();
}
}
Here are the dependencies I'm using:
dependencies:
flutter:
sdk: flutter
font_awesome_flutter: ^8.8.1
image_picker: ^0.6.7+6
provider: ^4.3.2+1
path_provider: ^1.6.14
path: ^1.7.0
firebase_core: ^0.5.0
cloud_firestore: ^0.14.1+2
google_sign_in: ^4.5.3
firebase_auth: ^0.18.1+1
firebase_storage: ^4.0.1
image: ^2.1.18
animator: ^2.0.1
geolocator: ^5.3.2+2
uuid: ^2.2.2
cached_network_image: ^2.3.2+1
bubble: ^1.1.9+1
flutter_cupertino_date_picker: ^1.0.26+2
In the new library version, authStateChanges is a method, so you need to put () after it.
return _firebaseAuth.authStateChanges().map(_userFromFirebase);
Related
I have the following auth provider, and I can sign the user in and the app state changes. But when I do a sign in I notice that nothing is stored in the local storage and when I refresh the page the authStateChanges gives null for the user. I also just tried tho get the current user as a Future which also returns null. What am I doing wrong?
const String oneTimePasswordFunctionName = "requestOneTimePassword";
const String signInWithOneTimePasswordFunctionName = "signInWithOneTimePassword";
class FirebaseAuthProvider extends AuthProvider {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final FirebaseFunctions _firebaseFunctions = FirebaseFunctions.instance;
Stream<AuthUser> get user {
return _firebaseAuth.authStateChanges().asyncMap((firebaseUser) {
//firebaseUser is always null on refresh
return firebaseUser == null ? AuthUser.empty : firebaseUser.toUser();
});
}
Future<void> requestOneTimePassword({required String email}) async {
final data = {"email": email};
final cloudFunction = _firebaseFunctions.httpsCallable(oneTimePasswordFunctionName);
await cloudFunction.call(data);
}
Future<void> signInWithOneTimePassword({required String email, required String oneTimePassword}) async {
final data = {"email": email, "oneTimePassword": oneTimePassword};
final cloudFunction = _firebaseFunctions.httpsCallable(signInWithOneTimePasswordFunctionName);
final result = await cloudFunction.call(data);
final jwt = result.data["data"]["jwt"] as String;
if (jwt.isEmpty) return;
await FirebaseAuth.instance.setPersistence(Persistence.LOCAL);
await _firebaseAuth.signInWithCustomToken(jwt);
}
Future<void> signOut() async {
try {
await _firebaseAuth.signOut();
} on Exception {
throw SignOutException();
}
}
}
extension on User {
FutureOr<AuthUser> toUser() async {
final tokenResult = await this.getIdTokenResult(true);
final claims = tokenResult.claims?.map<String, String>((key, value) => MapEntry(key, value.toString()));
return AuthUser(
id: uid,
email: Email.dirty(email ?? ''),
name: displayName ?? '',
photoURL: Uri.parse(photoURL ?? ''),
claims: claims ?? const {},
);
}
}
I really need it to work with the authStateChanges stream, because I want it also to work when the user does a sign out.
I am using the firebase auth emulator. This is my main
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FirebaseAuth.instance.useAuthEmulator("localhost", 9099);
FirebaseFirestore.instance.settings = Settings(
host: "localhost:8080",
sslEnabled: false,
persistenceEnabled: false,
);
FirebaseFunctions.instance.useFunctionsEmulator("localhost", 5001);
Future<dynamic> Function() initializeFirebase = () async {
if (Firebase.apps.length == 0) await Firebase.initializeApp();
};
await Future.wait([
initializeFirebase(),
EasyLocalization.ensureInitialized(),
]);
runApp(_buildAppWithDependencies());
}
I am testing in the latest version of google chrome
Versions
flutter: 2.5.3 (stable)
firebase_core: ^1.10.0
firebase_auth: ^3.2.0
I am trying to set up with apple sign in with the following code. When tapping the button nothing happens.
I get the following error:
Tried calling: authorizationCode
flutter: NoSuchMethodError: The getter 'authorizationCode' was called on null.
Receiver: null
How would I fix this?
Future<bool> get appleSignInAvailable => AppleSignIn.isAvailable();
Future<User> appleSignIn() async {
try {
final AuthorizationResult appleResult =
await AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);
if (appleResult.error != null) {
// handle errors from Apple
}
final AuthCredential credential =
OAuthProvider('apple.com').credential(
accessToken:
String.fromCharCodes(appleResult.credential.authorizationCode),
idToken: String.fromCharCodes(appleResult.credential.identityToken),
);
UserCredential result =
await Global.fbAuth.signInWithCredential(credential);
User user = result.user;
updateUserData(user);
return user;
} catch (error) {
print(error);
return null;
}
}
If you are using iOS 14 simulator, this may be due to the issue reported here. The workaround would be to use a real device for debugging or use the iOS 13 simulator
Also, see this thread for reference
I have faced same kind of issue in one of my projects.You have to add your sha key in firebase and facebook to resolve the issue.
Also you can try the below code,
import 'package:apple_sign_in/apple_sign_in.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/services.dart';
class AuthService {
final _firebaseAuth = FirebaseAuth.instance;
Future<User> signInWithApple({List<Scope> scopes = const []}) async {
// 1. perform the sign-in request
final result = await AppleSignIn.performRequests(
[AppleIdRequest(requestedScopes: scopes)]);
// 2. check the result
switch (result.status) {
case AuthorizationStatus.authorized:
final appleIdCredential = result.credential;
final oAuthProvider = OAuthProvider('apple.com');
final credential = oAuthProvider.credential(
idToken: String.fromCharCodes(appleIdCredential.identityToken),
accessToken:
String.fromCharCodes(appleIdCredential.authorizationCode),
);
final authResult = await _firebaseAuth.signInWithCredential(credential);
final firebaseUser = authResult.user;
if (scopes.contains(Scope.fullName)) {
final displayName =
'${appleIdCredential.fullName.givenName} ${appleIdCredential.fullName.familyName}';
await firebaseUser.updateProfile(displayName: displayName);
}
return firebaseUser;
case AuthorizationStatus.error:
throw PlatformException(
code: 'ERROR_AUTHORIZATION_DENIED',
message: result.error.toString(),
);
case AuthorizationStatus.cancelled:
throw PlatformException(
code: 'ERROR_ABORTED_BY_USER',
message: 'Sign in aborted by user',
);
default:
throw UnimplementedError();
}
}
}
I have created an app with Google login with firestore support and recently I have updated all the dependencies to a newer version. Here There are some problem with the old code I don't know what's the problem.
Future<String> getCurrentUser() async {
var user = await _auth.currentUser();
if (user == null) {
return null;
} else {
return user.uid;
}
}
It shows error near _auth.currentUser(); and the error is The expression doesn't evaluate to a function, so it can't be invoked. I have searched for it but nothing worked. This is the First problem.
The Second problem arises with rxdart package. Due to new packages Observable is not supported and Searched it for internet and tried using Stream But they are not working.
The Source Code is here for rxdart problem.
class AuthService {
final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseFirestore _db = FirebaseFirestore.instance;
Stream<User> user;
Stream<Map<String, dynamic>> profile;
String uuid;
AuthService() {
Stream<User> user = Observable(_auth.authStateChanges);
profile = user.switchMap((User u) {
if (u != null) {
return _db
.collection('users')
.doc(u.uid)
.snapshots()
.map((snap) => snap.data);
} else {
return Observable.just({});
}
});
}
}
It shows error near return Observable.just({}); and next problem arises with this line Stream<User> user = Observable(_auth.authStateChanges);
Help me sort this out and Help me understand my issues.
currentUser is no longer a method, and no longer asynchronous. So the correct invocation now is:
var user = _auth.currentUser;
I recommend keeping the migration guide handy while upgrading your code to this latest version, as there are quite a few of these changes.
In newer versions of the Firebase Auth SDK for Flutter, if you want a stream of auth state events, you should set up an auth state stream using authStateChanges, as shown in the documentation.
FirebaseAuth.instance
.authStateChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
I was following a tutorial to create an authentication system in flutter using firebase. Registration works as intended and the user is posted to my firebase database, however, when I try to login with the correct credentials, I get:
I/flutter (26424): user A a#a.com added
I/InputMethodManager(26424): showSoftInput
I/InputMethodManager(26424): mServedView =com.waifuhub.app;view =com.waifuhub.app;flags =0
I/HwSecImmHelper(26424): mSecurityInputMethodService is null
W/InputMethodManager(26424): startInputReason = 3
W/IInputConnectionWrapper(26424): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper(26424): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper(26424): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper(26424): requestCursorAnchorInfo on inactive InputConnection
I/InputMethodManager(26424): showSoftInput
I/InputMethodManager(26424): mServedView =com.waifuhub.app;view =com.waifuhub.app;flags =0
I/HwSecImmHelper(26424): mSecurityInputMethodService is null
W/InputMethodManager(26424): startInputReason = 3
V/AudioManager(26424): playSoundEffect effectType: 0
V/AudioManager(26424): querySoundEffectsEnabled...
I/HwSecImmHelper(26424): mSecurityInputMethodService is null
I/ViewRootImpl(26424): jank_removeInvalidNode all the node in jank list is out of time
I/flutter (26424): Sign In Error: NoSuchMethodError: The getter 'data' was called on null.
I/flutter (26424): Receiver: null
I/flutter (26424): Tried calling: data
Application finished.
Exited (sigterm)
The code responsible for signing in is as follows:
void _emailLogin(
{String email, String password, BuildContext context}) async {
if (_formKey.currentState.validate()) {
try {
SystemChannels.textInput.invokeMethod('TextInput.hide');
await _changeLoadingVisible();
//need await so it has chance to go through error if found.
await StateWidget.of(context).logInUser(email, password);
await Navigator.pushNamed(context, '/');
} catch (e) {
_changeLoadingVisible();
print("Sign In Error: $e");
String exception = Auth.getExceptionText(e);
Flushbar(
title: "Sign In Error",
message: exception,
duration: Duration(seconds: 5),
)..show(context);
}
} else {
setState(() => _autoValidate = true);
}
}
class StateWidget extends StatefulWidget {
final StateModel state;
final Widget child;
StateWidget({
#required this.child,
this.state,
});
// Returns data of the nearest widget _StateDataWidget
// in the widget tree.
static _StateWidgetState of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<_StateDataWidget>().data;
}
#override
_StateWidgetState createState() => new _StateWidgetState();
}
class _StateWidgetState extends State<StateWidget> {
StateModel state;
//GoogleSignInAccount googleAccount;
//final GoogleSignIn googleSignIn = new GoogleSignIn();
#override
void initState() {
super.initState();
if (widget.state != null) {
state = widget.state;
} else {
state = new StateModel(isLoading: true);
initUser();
}
}
Future<Null> initUser() async {
//print('...initUser...');
FirebaseUser firebaseUserAuth = await Auth.getCurrentFirebaseUser();
User user = await Auth.getUserLocal();
Settings settings = await Auth.getSettingsLocal();
setState(() {
state.isLoading = false;
state.firebaseUserAuth = firebaseUserAuth;
state.user = user;
state.settings = settings;
});
}
Future<void> logOutUser() async {
await Auth.signOut();
FirebaseUser firebaseUserAuth = await Auth.getCurrentFirebaseUser();
setState(() {
state.user = null;
state.settings = null;
state.firebaseUserAuth = firebaseUserAuth;
});
}
Future<void> logInUser(email, password) async {
String userId = await Auth.signIn(email, password);
User user = await Auth.getUserFirestore(userId);
await Auth.storeUserLocal(user);
Settings settings = await Auth.getSettingsFirestore(userId);
await Auth.storeSettingsLocal(settings);
await initUser();
}
#override
Widget build(BuildContext context) {
return new _StateDataWidget(
data: this,
child: widget.child,
);
}
}
class _StateDataWidget extends InheritedWidget {
final _StateWidgetState data;
_StateDataWidget({
Key key,
#required Widget child,
#required this.data,
}) : super(key: key, child: child);
// Rebuild the widgets that inherit from this widget
// on every rebuild of _StateDataWidget:
#override
bool updateShouldNotify(_StateDataWidget old) => true;
}
static Future<String> signIn(String email, String password) async {
FirebaseUser user = (await FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password))
.user;
return user.uid;
}
class Validator {
static String validateEmail(String value) {
Pattern pattern = r'^[a-zA-Z0-9.]+#[a-zA-Z0-9]+\.[a-zA-Z]+';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value))
return 'Please enter a valid email address.';
else
return null;
}
static String validatePassword(String value) {
Pattern pattern = r'^.{6,}$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value))
return 'Password must be at least 6 characters.';
else
return null;
}
static String validateName(String value) {
Pattern pattern = r"^[a-zA-Z]+(([',. -][a-zA-Z ])?[a-zA-Z]*)*$";
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value))
return 'Please enter a name.';
else
return null;
}
static String validateNumber(String value) {
Pattern pattern = r'^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value))
return 'Please enter a number.';
else
return null;
}
}
And my dependencies in pubsec.yaml:
dependencies:
flutter:
sdk: flutter
flutter_launcher_icons: ^0.7.2
cupertino_icons: ^0.1.2
firebase_auth: ^0.15.5+3
cloud_firestore: ^0.13.4+2
flushbar: 1.9.1
shared_preferences: ^0.5.6+3
dev_dependencies:
flutter_test:
sdk: flutter
Upon further debugging, I think the error is due to the fact that null context is being passed to
_StateWidgetState, however, I am not sure if this is so, or how to solve this. Any help would be highly appreciated!
Not sure, but it seems you're missing calling
_formKey.currentState.save();
after calling _formKey.currentState.validate().
Otherwise this line is causing the error:
static _StateWidgetState of(BuildContext context) {
return (context.dependOnInheritedWidgetOfExactType() as _StateDataWidget)
.data;
}
This (context.dependOnInheritedWidgetOfExactType() as _StateDataWidget) is returning null
change it to:
return (context.inheritFromWidgetOfExactType(_StateDataWidget) as _StateDataWidget).data;
or
return context.dependOnInheritedWidgetOfExactType<_StateDataWidget>().data;
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.