首页 > 解决方案 > 在保留 StreamProvider 的同时,无法将 Flutter Firebase_Auth 从版本 0.15 更新到 0.18

问题描述

我有一个Flutter运行良好的大型应用程序......

现在,我正在努力如何更新firebase_auth: ^0.15.5+3具有重大更改的 Firebase 插件(自 2020 年夏季起)。

StreamProvider当我检查MyUser应用程序的多个位置时,我绝对需要保留我的。

我重新创建了一个最小的工作应用程序来专注于我的具体问题。

你能建议我应该如何调整这些:

1- getCurrentUserin AuthService:看来我需要使用authStateChanges但不知道如何使用。

2- StreamProviderin MyApp:如何调整它,以便我可以在我的应用程序中继续使用它而无需更改任何内容。

3-使用这种方式:final currentUser = Provider.of<MyUser>(context)然后currentUser.uid获取uid字符串。

请具体举例。

这是我的 puspec.yaml

name: myApp
environment:
  sdk: ">=2.7.0 <3.0.0"
dependencies:
  flutter:
    sdk: flutter

  # **** FIREBASE ****
  firebase_auth: ^0.15.5+3
  provider: ^4.0.5
  #firebase_core: "^0.5.2"
  #firebase_auth: "^0.18.3"

dev_dependencies:
  flutter_test:
    sdk: flutter
flutter:
  uses-material-design: true
  assets:
    - assets/

这是以前Firebase版本 0.15的所有(工作)代码

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:firebase_auth/firebase_auth.dart';

void main() {
  runApp(MyApp());
}
//******************************************
class MyApp extends StatelessWidget  {
  @override Widget build(BuildContext context) {
    //The following StreamProvider is what I am trying to recreate with new Firebase version.
    return StreamProvider<MyUser>.value(
      value: AuthService().getCurrentUser,
      child: MaterialApp( title: 'MyApp',
        home: Wrapper(),),);}
}
//******************************************
class Wrapper extends StatelessWidget {
  @override  Widget build(BuildContext context) {
    final currentUser = Provider.of<MyUser>(context);

    // return either the Home or Authenticate widget
    if (currentUser == null) {return SignIn();}
    else {return HomePage();}}
}
//******************************************
class MyUser {
  String uid;
  MyUser({this.uid ,});
}
//******************************************
class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  //This method will need to be updated I guess
  Stream<MyUser> get getCurrentUser {
    return _auth.onAuthStateChanged.map((FirebaseUser user) => _refereeFromFirebaseUser(user));
  }
  MyUser _refereeFromFirebaseUser(FirebaseUser _authUser) {
    return (_authUser != null) ? MyUser(uid: _authUser.uid) : null;
  }

  Future signInWithEmailAndPassword(String email, String password) async {
    try {
      AuthResult result = await _auth.signInWithEmailAndPassword(email: email, password: password);
      FirebaseUser user = result.user;
      return user;
    } catch (error) {
      print(error.toString());
      return null;}
  }

  Future signOut() async {
    try {return await _auth.signOut();}
    catch (error) {print(error.toString());return null;}
  }
}
//******************************************
class HomePage extends StatelessWidget {
  final AuthService _auth = AuthService();

  @override  Widget build(BuildContext context) {
    final currentUser = Provider.of<MyUser>(context);
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('MyApp2'),
          actions: <Widget>[FlatButton.icon(icon: Icon(Icons.person), label: Text('logout'), onPressed: () async {await _auth.signOut();},),  ],),
        //Following line is very important: this is what I'd like to replicate with new Firebase version
        body: Text("My ID is ${currentUser.uid}"),
      ),);
  }
}
//******************************************
class SignIn extends StatefulWidget {
  @override _SignInState createState() => _SignInState();
}

class _SignInState extends State<SignIn> {

  final AuthService _auth = AuthService();
  final _formKey = GlobalKey<FormState>();
  String error = '';
  String email ;
  String password ;

  @override Widget build(BuildContext context) {
    return Scaffold(
      body:  Form(key: _formKey,
        child: ListView(shrinkWrap: true, children: <Widget>[ SizedBox(height: 60.0),
          emailField(),     SizedBox(height: 8.0),
          passwordField(),  SizedBox(height: 24.0),
          signInButton(),
          Text(error, style: TextStyle(color: Colors.red, fontSize: 16.0),),
        ],),),);}

  RaisedButton signInButton()  {
    return RaisedButton( child: Text('Sign In'),
        onPressed: () async {
          if(_formKey.currentState.validate()) {
            dynamic result = await _auth.signInWithEmailAndPassword(email, password);
            //If successful SignIn, the Provider listening in the Wrapper will automatically load the Home page.
            if(result == null) {setState(() {error = 'Could not sign in with those credentials';});}}});
  }
  TextFormField passwordField() {
    return TextFormField(
      validator: (val) => val.length < 6 ? 'Enter a password 6+ chars long' : null,
      onChanged: (val) {setState(() => password = val);},);
  }
  TextFormField emailField() {
    return TextFormField(
      validator: (val) => val.isEmpty ? 'Enter an email' : null,
      onChanged: (val) {setState(() => email = val);},);
  }
}

标签: firebaseflutterfirebase-authenticationflutter-provider

解决方案


  1. 第一点:当前用户不再是异步的。如果您检查文档,您会发现它不会返回未来,而是返回用户。如果您想检查身份验证状态更新,只需调用 FirebaseAuth.instance.authStateChanges()。需要注意的另一件事是,现在包含用户数据的类不再称为 FirebaseUser,而只是称为 User。

  2. StreamProvider 在提供程序包中仍然可用。在您的问题中,尚不清楚这门课向您提出的问题是什么。

  3. Provider.of<>(context) 仍然可以使用。但是,现在您也可以使用以下 2 种替代方法:

  • context.watch(),让小部件监听 T 上的变化
  • context.read(),不听就返回 T

推荐阅读