firebase - 是否可以根据用户角色从启动屏幕导航或推送到管理屏幕或用户屏幕?
问题描述
我正在使用 Flutter 和 firebase 创建一个 Web 应用程序。以下是依赖项:
firebase_core: ^1.7.0
firebase_auth: ^3.1.3
cloud_firestore: ^2.5.3
以下是 web/index.html 上的脚本版本:
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-firestore.js"></script>
我正在尝试使用电子邮件和密码方法登录后导航用户。用户应该导航到admin page
或user page
依赖于user role
on cloud Firestore
。登录后用户从登录页面将导航到splash screen
应该决定用户导航到下一页的位置,具体取决于用户角色。它正在启动启动屏幕,但我无法做我想做的事情,页面不会被导航。请让我知道这是正确的方法,请给我一个解决方案。以下是我在启动画面上的测试代码:
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:webfire/admin_screen.dart';
import 'package:webfire/home_screen.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
String role = 'user';
@override
void initState() {
super.initState();
_checkRole();
}
final FirebaseAuth auth = FirebaseAuth.instance;
void _checkRole() async {
User? user = FirebaseAuth.instance.currentUser;
//User user = auth.currentUser;
final DocumentSnapshot snap = await FirebaseFirestore.instance
.collection('users')
.doc(user!.uid)
.get();
setState(() {
role = snap['role'];
});
if (role == 'user') {
navigateNext(const HomeScreen());
} else if (role == 'admin') {
navigateNext(const AdminScreen());
}
}
void navigateNext(Widget route) {
Timer(const Duration(milliseconds: 500), () {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => route));
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('Welcome'),
],
),
));
}
}
错误:打开 utils.dart 并显示:return util.promiseToFuture(thenable);
以下是根据第一个答案编辑的代码:
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:webfire/admin_screen.dart';
import 'package:webfire/home_screen.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
String role = 'user';
@override
void initState() {
super.initState();
_checkRole();
}
final FirebaseAuth auth = FirebaseAuth.instance;
void _checkRole() async {
User? user = FirebaseAuth.instance.currentUser;
//User user = auth.currentUser;
final DocumentSnapshot snap = await FirebaseFirestore.instance
.collection('users')
.doc(user!.uid)
.get();
setState(() {
role = snap['role'];
});
// if (role == 'user') {
// navigateNext(const HomeScreen());
// } else if (role == 'admin') {
// navigateNext(const AdminScreen());
// }
}
void navigateNext(Widget route) {
Timer(const Duration(milliseconds: 500), () {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => route));
});
}
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// body: Center(
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: const [
// Text('Welcome to my project'),
// ],
// ),
// ));
// }
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (role == 'user') const HomeScreen(),
if (role == 'admin') const AdminScreen(),
],
),
));
}
}
以下是异常错误:
Exception has occurred.
"Error: Cannot hit test a render box that has never been laid out.
The hitTest() method was called on this RenderBox: RenderStack#197ec NEEDS-LAYOUT NEEDS-PAINT:
creator: Stack ← _FloatingActionButtonTransition ← MediaQuery ← LayoutId-[<_ScaffoldSlot.floatingActionButton>] ← CustomMultiChildLayout ← AnimatedBuilder ← DefaultTextStyle ← AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#c955e ink renderer] ← NotificationListener<LayoutChangedNotification> ← PhysicalModel ← AnimatedPhysicalModel ← ⋯
parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.floatingActionButton
constraints: MISSING
size: MISSING
alignment: Alignment.centerRight
textDirection: ltr
fit: loose
Unfortunately, this object's geometry is not known at this time, probably because it has never been laid out. This means it cannot be accurately hit-tested.
If you are trying to perform a hit test during the layout phase itself, make sure you only hit test nodes that have completed layout (e.g. the node's children, after their layout() method has been called).
at Object.throw_ [as throw] (http://localhost:61527/dart_sdk.js:5061:11)
下面是调试错误:
Launching lib\main.dart on Chrome in debug mode...
This app is linked to the debug service: ws://127.0.0.1:51157/0tP91b-9bJU%3D/ws
Debug service listening on ws://127.0.0.1:51157/0tP91b-9bJU=/ws
Running with sound null safety
Connecting to VM Service at ws://127.0.0.1:51157/0tP91b-9bJU=/ws
════════ Exception caught by rendering library ═════════════════════════════════
The following assertion was thrown during performLayout():
RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size.
The nearest ancestor providing an unbounded height constraint is: RenderFlex#5be33 relayoutBoundary=up2 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
The constraints that applied to the RenderCustomMultiChildLayoutBox were: BoxConstraints(0.0<=w<=681.0, 0.0<=h<=Infinity)
The exact size it was given was: Size(681.0, Infinity)
See https://flutter.dev/docs/development/ui/layout/box-constraints for more information.
The relevant error-causing widget was
Scaffold
When the exception was thrown, this was the stack
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 251:49 throw_
packages/flutter/src/rendering/box.dart 2205:9 <fn>
packages/flutter/src/rendering/box.dart 2298:14 debugAssertDoesMeetConstraints
packages/flutter/src/rendering/box.dart 1991:7 <fn>
packages/flutter/src/rendering/box.dart 1992:14 set size
packages/flutter/src/rendering/custom_layout.dart 403:5 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/proxy_box.dart 1388:11 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/layout_helper.dart 56:10 layoutChild
packages/flutter/src/rendering/flex.dart 829:43 [_computeSizes]
packages/flutter/src/rendering/flex.dart 931:32 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/shifted_box.dart 437:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/custom_layout.dart 171:10 layoutChild
packages/flutter/src/material/scaffold.dart 1097:7 performLayout
packages/flutter/src/rendering/custom_layout.dart 240:7 [_callPerformLayout]
packages/flutter/src/rendering/custom_layout.dart 404:14 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/proxy_box.dart 1388:11 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 3420:14 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/rendering/proxy_box.dart 116:7 performLayout
packages/flutter/src/rendering/object.dart 1858:7 layout
packages/flutter/src/widgets/overlay.dart 745:14 performLayout
packages/flutter/src/rendering/object.dart 1713:7 [_layoutWithoutResize]
packages/flutter/src/rendering/object.dart 885:17 flushLayout
packages/flutter/src/rendering/binding.dart 453:19 drawFrame
packages/flutter/src/widgets/binding.dart 883:13 drawFrame
packages/flutter/src/rendering/binding.dart 319:5 [_handlePersistentFrameCallback]
packages/flutter/src/scheduler/binding.dart 1143:15 [_invokeFrameCallback]
packages/flutter/src/scheduler/binding.dart 1080:9 handleDrawFrame
packages/flutter/src/scheduler/binding.dart 996:5 [_handleDrawFrame]
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/platform_dispatcher.dart 1003:13 invoke
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/platform_dispatcher.dart 157:5 invokeOnDrawFrame
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine.dart 440:45 <fn>
The following RenderObject was being processed when the exception was fired: RenderCustomMultiChildLayoutBox#95e25 relayoutBoundary=up5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
RenderObject: RenderCustomMultiChildLayoutBox#95e25 relayoutBoundary=up5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
parentData: <none> (can use size)
constraints: BoxConstraints(0.0<=w<=681.0, 0.0<=h<=Infinity)
size: Size(681.0, Infinity)
child 1: RenderPositionedBox#0a91e NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.body
constraints: MISSING
size: MISSING
alignment: Alignment.center
textDirection: ltr
widthFactor: expand
heightFactor: expand
child: RenderFlex#1cdfb NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
parentData: offset=Offset(0.0, 0.0)
constraints: MISSING
size: MISSING
direction: vertical
mainAxisAlignment: center
mainAxisSize: max
crossAxisAlignment: center
verticalDirection: down
child 1: RenderParagraph#768de NEEDS-LAYOUT NEEDS-PAINT
parentData: offset=Offset(0.0, 0.0); flex=null; fit=null
constraints: MISSING
size: MISSING
textAlign: start
textDirection: ltr
softWrap: wrapping at box width
overflow: clip
locale: en_US
maxLines: unlimited
text: TextSpan
debugLabel: (englishLike body1 2014).merge(blackRedmond bodyText2)
inherit: false
color: Color(0xdd000000)
family: Segoe UI
size: 14.0
weight: 400
baseline: alphabetic
decoration: TextDecoration.none
"You have logged in Successfuly"
child 2: RenderConstrainedBox#f5889 NEEDS-LAYOUT NEEDS-PAINT
parentData: offset=Offset(0.0, 0.0); flex=null; fit=null
constraints: MISSING
size: MISSING
additionalConstraints: BoxConstraints(0.0<=w<=Infinity, h=50.0)
child 3: RenderConstrainedBox#6f662 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
parentData: offset=Offset(0.0, 0.0); flex=null; fit=null
constraints: MISSING
size: MISSING
additionalConstraints: BoxConstraints(w=150.0, h=60.0)
child: RenderSemanticsAnnotations#68b39 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
parentData: <none>
constraints: MISSING
semantic boundary
size: MISSING
child 2: RenderStack#197ec NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.floatingActionButton
constraints: MISSING
size: MISSING
alignment: Alignment.centerRight
textDirection: ltr
fit: loose
child 1: RenderTransform#402cb NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
parentData: not positioned; offset=Offset(0.0, 0.0)
constraints: MISSING
size: MISSING
transform matrix: [0] 0.0,0.0,0.0,0.0
[1] 0.0,0.0,0.0,0.0
[2] 0.0,0.0,1.0,0.0
[3] 0.0,0.0,0.0,1.0
origin: null
alignment: Alignment.center
textDirection: ltr
transformHitTests: true
child: RenderTransform#03a78 NEEDS-LAYOUT NEEDS-PAINT
parentData: <none>
constraints: MISSING
size: MISSING
transform matrix: [0] 0.7,0.7,0.0,0.0
[1] -0.7,0.7,0.0,0.0
[2] 0.0,0.0,1.0,0.0
[3] 0.0,0.0,0.0,1.0
origin: null
alignment: Alignment.center
textDirection: ltr
transformHitTests: true
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by rendering library ═════════════════════════════════
_RenderInkFeatures object was given an infinite size during layout.
The relevant error-causing widget was
Scaffold
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by rendering library ═════════════════════════════════
RenderPhysicalModel object was given an infinite size during layout.
The relevant error-causing widget was
Scaffold
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by rendering library ═════════════════════════════════
A RenderFlex overflowed by Infinity pixels on the bottom.
The relevant error-causing widget was
Column
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by scheduler library ═════════════════════════════════
Cannot hit test a render box that has never been laid out.
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by scheduler library ═════════════════════════════════
Assertion failed:
!_debugDuringDeviceUpdate
is not true
════════════════════════════════════════════════════════════════════════════════
解决方案
也许您可能已经修复,但让我分享我的解决方案,您可以在此升级。
SplashScreen 页面和模型类
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dynamic_links/admin_page.dart';
import 'package:flutter_dynamic_links/user_page.dart';
class SplashScreen extends StatefulWidget {
final SplashScreenModel model;
const SplashScreen({
Key? key,
required this.model,
}) : super(key: key);
@override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
super.initState();
checkRoleAndNavigate();
}
@override
Widget build(BuildContext context) {
return Container(
child: Text('You can show loading indicator or App logo'),
);
}
Future<void> checkRoleAndNavigate() async {
final Role role = await widget.model.init();
if (role == Role.admin) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (_) => AdminPage()));
} else if (role == Role.user) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (_) => UserPage()));
}
}
}
class SplashScreenModel {
//as it takes little time to check no need timer
Future<Role> init() async {
final user = FirebaseAuth.instance.currentUser;
final snap = await FirebaseFirestore.instance
.collection('users')
.doc(user!.uid)
.get();
final role = snap['role'];
if (role == 'user') {
return Role.user;
} else {
return Role.admin;
}
}
}
enum Role { user, admin }
用户页面
import 'package:flutter/material.dart';
class UserPage extends StatelessWidget {
const UserPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Text('User Page'),
);
}
}
管理页面
import 'package:flutter/material.dart';
class AdminPage extends StatelessWidget {
const AdminPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Text('Admin Page'),
);
}
}
==================================================== ====
显示 5 秒或其他东西的飞溅
checkRoleAndNavigate() {
Future.delayed(Duration(seconds: 5)).then((value) async {
final Role role = await widget.model.init();
if (role == Role.admin) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (_) => AdminPage()));
} else if (role == Role.user) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (_) => UserPage()));
}
});
}