#firebase #flutter #dart #firebase-authentication
#firebase #flutter #dart #firebase-аутентификация
Вопрос:
Всякий раз, когда пользователь закрывает приложение, он должен повторно войти в систему. Я посмотрел и попытался реализовать authStateChanges. Но все же мое приложение по-прежнему заставляет пользователей снова входить в систему после закрытия приложения. В классе App вы можете видеть, что я пытался выполнить именно authStateChange, но, к сожалению, ничего не происходит.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(App());
}
// Firebase Auth Instance
FirebaseAuth auth = FirebaseAuth.instance;
class MyApp extends StatelessWidget {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Tanbo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LoginPage(),
);
}
}
// This is the main root screen of the Tanbo app
class App extends StatelessWidget {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
@override
Widget build(BuildContext context) {
return FutureBuilder(
// Initialize FlutterFire
future: _initialization,
builder: (context, snapshot) {
final user = FirebaseAuth.instance.authStateChanges().listen((User user) {
if (user == null) {
print('User signed out');
} else {
print('User signed in');
}
});
// Check for errors
if (snapshot.hasError) {
return ErrorHandler();
}
// Once complete, show your application
if (snapshot.connectionState == ConnectionState.done) {
// If the user isn't logged in, we will be sent to sign up page.
if (user != null) {
return MyApp();
} else {
// If the user is logged in, TabHandler will be shown.
return TabHandler();
}
}
// Otherwise, show something whilst waiting for initialization to complete
return LoadingHandler();
},
);
}
}
Комментарии:
1. Вы должны реагировать на изменения в состоянии пользователя внутри обратного вызова, который вы передаете listen() , а не сразу после настройки прослушивателя. Пользователь снова входит в систему только по истечении некоторого времени после добавления слушателя, и только ваш слушатель будет знать об этом изменении.
Ответ №1:
Проблема в том, что вы явно сделали свою страницу входа в систему своей домашней страницей. Когда приложение откроется, оно автоматически прочитает main.dart
файл и увидит страницу входа в систему в качестве назначенной домашней страницы.
Вот как вы это исправляете. А также создайте систему аутентификации, в которой вы можете получить идентификатор зарегистрированного пользователя в любой точке приложения.
Что вам нужно:
- Зависимость от поставщика в зависимости от версии. Желательно последнюю
- Улыбка — перестаньте хмуриться. Вы собираетесь решить свою проблему
- Зависимость от аутентификации Firebase. В зависимости от версии. Я собираюсь дать вам исправление для новейшей версии и для явно более старых версий.
Шаг 0: добавьте необходимые зависимости и запустите flutter pub get. Это не проблема.
Шаг 1: создайте auth_services
класс: код приведен ниже
Для более старых версий firebase auth
:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
Stream<String> get onAuthStateChanged =>
_firebaseAuth.onAuthStateChanged.map(
(FirebaseUser user) => user?.uid,
);
// GET UID
Future<String> getCurrentUID() async {
return (await _firebaseAuth.currentUser()).uid;
}
}
Для более новых версий зависимости аутентификации firebase:
class AuthService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
Stream<User> get onAuthStateChanged => _firebaseAuth.authStateChanges();
// GET UID
Future<String> getCurrentUID() async {
return _firebaseAuth.currentUser.uid;
}
}
Объяснение: я создал этот класс для обработки всех функций аутентификации. Я создаю функцию с именем onAuthStateChanged, которая возвращает поток типа User (идентификаторы для более старых версий firebase auth), и я собираюсь прослушать этот поток, чтобы узнать, вошел ли пользователь в систему или нет.
Шаг 2: Создайте поставщика аутентификации, который будет охватывать все приложение и позволит получить наш идентификатор пользователя в любом месте приложения.
Создайте файл с именем auth_provider.dart. Код приведен ниже.
import 'package:flutter/material.dart';
import 'auth_service.dart';
class Provider extends InheritedWidget {
final AuthService auth;
Provider({
Key key,
Widget child,
this.auth,
}) : super(key: key, child: child);
@override
bool updateShouldNotify(InheritedWidget oldWiddget) {
return true;
}
static Provider of(BuildContext context) =>
(context.dependOnInheritedWidgetOfExactType<Provider>());
}
Следующий шаг — обернуть все приложение в этот виджет поставщика и установить домашний контроллер в качестве домашней страницы.
Шаг 3: В файле main.dart или в любом другом месте создайте класс с именем HomeController, который будет обрабатывать состояние входа в систему, и установите домашний контроллер в качестве назначенной домашней страницы.
ПРИМЕЧАНИЕ: я установил контейнер черного цвета, который будет отображаться при загрузке приложения, чтобы определить, вошел ли пользователь в систему или нет. Это довольно быстрый процесс, но если вы хотите, вы можете настроить его как контейнер цвета темы вашего приложения. Вы даже можете установить его в качестве заставки. (Пожалуйста, обратите внимание. Этот контейнер отображается не более 1 секунды. Из моего опыта)
Код приведен ниже: импортируйте все необходимые вещи
void main() {
//WidgetsFlutterBinding.ensureInitialized();
// await Firebase.initializeApp();
//only add these if you're on the latest firebase
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provider(
auth: AuthService(),
child: MaterialApp(
title: 'Dreamora',
theme: ThemeData(
// fontFamily: "Montserrat",
brightness: Brightness.light,
inputDecorationTheme: InputDecorationTheme(
contentPadding:
EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
primarySwatch: Colors.purple,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomeController(),
);
},
),
),}
//(I think i have messed up the brackets here, but, you get the
//gist)
class HomeController extends StatelessWidget {
const HomeController({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final AuthService auth = Provider.of(context).auth;
return StreamBuilder(
stream: auth.onAuthStateChanged,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final bool signedIn = snapshot.hasData;
return signedIn ? DashBoard() : FirstView();
}
return Container(
color: Colors.black,
);
},
);
}
}
Объяснение: Домашний контроллер — это просто конструктор steam, который прослушивает множество внесенных нами изменений аутентификации. Если есть какие-либо данные, пользователь входит в систему. Если нет, он вышел из системы. Довольно просто. Между определением состояния пользователя, вошедшего в систему, существует задержка в 1 секунду. Су, за это время я возвращаю черный контейнер. Пользователь увидит, что экран становится черным примерно на секунду после открытия приложения, а затем бум. Домашняя страница
ВАЖНО: вы должны обернуть все свое приложение поставщиком. Это важно. Не забывайте об этом.
КАК ПОЛУЧИТЬ ИДЕНТИФИКАТОР ПОЛЬЗОВАТЕЛЯ В ЛЮБОЙ ТОЧКЕ ПРИЛОЖЕНИЯ
Provider.of(context).auth.getCurrentUID()
Вот так. Наслаждайтесь
[ПРАВИТЬ]Как выразился Л. Гангеми, новая версия Firebase Auth возвращает поток пользователей. Итак, отредактируйте код домашнего контроллера, чтобы
builder: (context, AsyncSnapshot<User> snapshot) {
Комментарии:
1. Ваш ответ был очень полезен. Я просто хотел сказать, что в новейшей версии ваш код возвращает пользователя с потоком, поэтому AsyncSnaphot в StreamBuilder должен быть таким: AsyncSnapshot<Пользователь>
2. Хороший ответ, также используйте
?
для User и других, который показывает нулевую ошибку3. @Simeon Я знаю, что это немного устарело, но я всегда задавался вопросом, зачем использовать StreamBuilder вместо того, чтобы просто использовать FutureBuilder? Разве он не проверяет только один раз, когда отображается экран, а затем показывает соответствующий экран?
4. Хорошо.. Изменения состояния auth пакета auth предоставляют вам доступ к потоку данных, которые символизируют изменения статистики аутентификации пользователя. Например, вход в систему, выход из системы и т.д. Вы не можете использовать поток в сборщике future. По крайней мере, нелегко. Кроме того, конструктор потоков реагирует в режиме реального времени на изменения в потоке. То же самое делает будущий разработчик. Нам нужно что-то, что меняется в тот момент, когда кто-то выходит из системы. Следовательно .., stream builder
Ответ №2:
Я считаю, что это не работает из-за этой проблемы — https://github.com/FirebaseExtended/flutterfire/issues/3356
Решается путем понижения рейтинга firebase-app.js и firebase-auth.js версии до 7.20.0
и замена метода authStateChanges() на userChanges()
FirebaseAuth.instance
.userChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
Ответ №3:
Использовать
FirebaseAuth.instance
.authStateChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
Комментарии:
1. Хотя этот код может дать решение вопроса, лучше добавить контекст относительно того, почему / как это работает. Это может помочь будущим пользователям учиться и применять эти знания к своему собственному коду. Вы также, вероятно, получите положительные отзывы от пользователей в виде положительных голосов, когда будет объяснен код.
2. Где было бы лучшее место для размещения этого кода?