# #firebase #flutter #dart #flutter-web
Вопрос:
В Flutter Web поток изменений пользователей из экземпляра FirebaseAuth никогда не выдает пользователя, вошедшего в систему, после перезагрузки страницы. Вместо этого он выдает только значение null. В приведенном ниже примере приложение застревает на странице загрузки.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/loading',
onGenerateRoute: (settings) {
switch (settings.name) {
case '/error':
return MaterialPageRoute(builder: (_) => ErrorScreen());
case '/loading':
return MaterialPageRoute(builder: (_) => LoadingScreen());
case '/signin':
return MaterialPageRoute(builder: (_) => SignInScreen());
case '/welcome':
return MaterialPageRoute(builder: (_) => WelcomeScreen());
default:
return MaterialPageRoute(
builder: (_) => Center(child: Text('Unknown route')));
}
},
);
}
}
class ErrorScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: Text('An error occurred.'),
),
);
}
}
class LoadingScreen extends StatefulWidget {
@override
_LoadingScreenState createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
@override
void initState() {
init();
super.initState();
}
init() async {
try {
await Firebase.initializeApp();
if (kDebugMode) {
await FirebaseAuth.instance.useEmulator('http://localhost:1001');
}
final preferences = await SharedPreferences.getInstance();
bool signedIn = preferences.getBool('IS_SIGNED_IN') ?? false;
String landingPath = '/signin';
if (signedIn) {
landingPath = '/welcome';
// Wait for the userChanges to emit a non-null element.
await FirebaseAuth.instance
.userChanges()
.firstWhere((user) => user != null);
}
Navigator.of(context).pushReplacementNamed(landingPath);
} catch (error) {
print(error);
Navigator.of(context).pushReplacementNamed('/error');
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: Text('Loading...'),
),
);
}
}
class SignInScreen extends StatelessWidget {
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
TextField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email address'),
),
TextField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
),
ElevatedButton(
onPressed: () => _submit(context),
child: Text('SIGN IN'),
),
],
),
),
);
}
void _submit(BuildContext context) async {
final email = _emailController.text;
final password = _passwordController.text;
FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password)
.then((credential) async {
final preferences = await SharedPreferences.getInstance();
await preferences.setBool('IS_SIGNED_IN', true);
Navigator.of(context).pushReplacementNamed('/welcome');
});
}
}
class WelcomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Text('Welcome!'),
ElevatedButton(
onPressed: () => _signOut(context),
child: Text('SIGN OUT'),
)
],
),
),
);
}
void _signOut(BuildContext context) {
FirebaseAuth.instance.signOut().then((_) async {
final preferences = await SharedPreferences.getInstance();
await preferences.setBool('IS_SIGNED_IN', false);
Navigator.of(context).pushReplacementNamed('/signin');
});
}
}
Если это поможет, я использую версию 8.3.0 библиотек Javascript Firebase в своем index.html файл.
Я что-то здесь упускаю?
Ответ №1:
Оказывается, приведенный выше код в порядке. Проблема в эмуляторе. Комментируя эти строки кода, приложение ведет себя так, как ожидалось:
if (kDebugMode) {
FirebaseAuth.instance.useEmulator('http://localhost:1001');
}
Я подал сообщение об ошибке в репо FlutterFire по поводу этой проблемы с эмулятором.