flutter-web - 当应用程序通过浏览器的地址栏以不同的路由启动时,避免 initialRoute 启动?

Posted

技术标签:

【中文标题】flutter-web - 当应用程序通过浏览器的地址栏以不同的路由启动时,避免 initialRoute 启动?【英文标题】:flutter-web - Avoid initialRoute from initiating when the app launched with a different route via the browser's address bar? 【发布时间】:2020-12-09 23:12:35 【问题描述】:

Flutter 新手。

我正在制作一个具有初始屏幕的应用,该屏幕最初会在用户打开应用时显示。 3 秒后,应用将显示登录或仪表板屏幕,具体取决于身份验证状态。

这是我的代码。

ma​​in.dart

void main()  
  runApp(myApp);


MaterialApp myApp = MaterialApp(
  initialRoute: "/",
  routes: 
    "/": (context) => SplashScreen(),
    "/signin": (context) => SignInScreen(),
    "/notes": (context) => NotesScreen(),
  ,
);

splash_screen.dart

class SplashScreen extends StatefulWidget 
  @override
  _SplashScreenState createState() => _SplashScreenState();


class _SplashScreenState extends State<SplashScreen> 
  @override
  void initState() 
    super.initState();
    _goToNextScreen();
  

  void _goToNextScreen() 
    Future.delayed(
      Duration(seconds:3),
      () async 
        AuthState authState = await Auth.getAuthState();
        String route = authState == AuthState.SIGNED_IN ? "/notes" : "/signin";
        Navigator.pushReplacementNamed(context, route);
      
    );
   

  // build() override goes here...

我一直在使用网络服务器调试应用程序。当应用程序使用 url localhost:8000/ 启动时,一切似乎都很好。但是,如果应用程序以 url localhost:8000/notes 开头,我认为启动画面仍然会启动。发生的情况是应用程序将显示笔记屏幕,然后在 3 秒后,应用程序将打开另一个笔记屏幕。

有什么想法吗?

【问题讨论】:

你找到解决办法了吗? 如果您没有使用 Navigator 2.0,那么接受的答案应该可以解决上述问题。 【参考方案1】:

请参阅,因为主要逻辑是我们不能在初始化状态下等待,因此无论您提供的任何逻辑如何,页面都会构建。我对此有一个解决方案,可能也有一些先进的或其他好的解决方案,所以这就是我要使用的。

我会使用未来建设者的概念。它会做的是等待我的服务器,然后构建整个应用程序。

所以过程是

    在你的 main.dart 使用

     Future<void> main() async 
       try 
         WidgetsFlutterBinding.ensureInitialized();
    
     //await for my server code and according to the variable I get I will take action
     //I would have a global parameter lets say int InternetOff
         await checkServer();
         runApp(MyApp());
        catch (error) 
         print(error);
         print('Locator setup has failed');
     //I can handle the error here
       
     
    

Now MyApp 无状态小部件,将帮助我们选择路径

class MyApp extends Stateless Widget
Widget build(BuildContext context) 
//Using this FutureBuilder 
    return FutureBuilder<String>(
      builder: (BuildContext context, AsyncSnapshot<String> snapshot) 
        // AsyncSnapshot<Your object type>

// Now if InternetOff is equal to one I would make it go to home 
if(InternetOff==1) return MaterialApp(
              theme: ThemeData.light(),
              home: CheckInternet(),
              debugShowCheckedModeBanner: false,
            );
//else go to Home similarly with these if and else you can add more conditions
else 
             
              return MaterialApp(
                theme: ThemeData.dark(),
                home: UserHome(),
                debugShowCheckedModeBanner: false,
              );
            
          
        
      ,
    );
  

【讨论】:

【参考方案2】:

因为第一次渲染总是从根“/”开始,所以最好使用自己的初始屏幕路径,例如

initialRoute: '/splash'.

要在地址栏中隐藏此路径,请将 routes 地图替换为路由生成器:

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      onGenerateRoute: (RouteSettings settings) 

        // print current route for clarity.
        print('>>> $settings.name <<<');

        switch (settings.name) 
          case '/splash':
            return MaterialPageRoute(
              builder: (context) => SplashScreen(),
              // settings omitted to hide route name
            );
          case '/signin':
            return MaterialPageRoute(
              builder: (context) => SignInScreen(),
              settings: settings,
            );
          case '/notes':
            return MaterialPageRoute(
              builder: (context) => NotesScreen(),
              settings: settings,
            );
          case '/':
            // don't generate route on start-up
            return null;
          default:
            return MaterialPageRoute(
              builder: (context) => FallbackScreen(),
            );
        
      ,
      initialRoute: '/splash',
    );
  



【讨论】:

但是对于我的网站website.com/,它将返回null,我将始终不得不使用website.com/splash【参考方案3】:

首先,flutter-web 与任何其他单页应用程序一样支持基于哈希的路由。因此,如果您想访问

localhost:8000/notes

您必须以身份访问它

localhost:8000/#/notes

更简洁的身份验证状态处理方式

在 runApp() 之前调用 getAuthState 函数,以确保在应用初始化之前设置了身份验证状态。并将 authState 作为参数传递给 SplashScreen 小部件。

void main() 
  WidgetsFlutterBinding.ensureInitialized();
  AuthState authState = await Auth.getAuthState();
  runApp(MaterialApp myApp = MaterialApp(
    initialRoute: "/",
    routes: 
      "/": (context) => SplashScreen(authState: authState),
      "/signin": (context) => SignInScreen(),
      "/notes": (context) => NotesScreen(),
    ,
  ));

splash_screen.dart

class SplashScreen extends StatefulWidget 
  final AuthState authState;
  SplashScreen(Key key, this.authState) : super(key: key);
  @override
  _SplashScreenState createState() => _SplashScreenState();


class _SplashScreenState extends State<SplashScreen> 
  @override
  void initState() 
    super.initState();
    _goToNextScreen();
  

  void _goToNextScreen() 
    Future.delayed(
      Duration(seconds:3),
      () async 
        String route = widget.authState == AuthState.SIGNED_IN ? "/notes" : "/signin";
        Navigator.pushReplacementNamed(context, route);
      
    );
   

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: Center(
        child: CircularProgressIndicator(),
      ),
    );
  

如果您想要更简洁的方式来处理身份验证状态,则必须使用像 Provider 这样的状态管理解决方案。

【讨论】:

手机版和网页版都可以用吗? 是的,它适用于移动设备和网络。虽然对于 web,如果您想要更好的路由解决方案,您可以查看 Navigator 2.0

以上是关于flutter-web - 当应用程序通过浏览器的地址栏以不同的路由启动时,避免 initialRoute 启动?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter-web:浏览器刷新时提供者状态丢失

flutter-web:通过 Location 插件获取 web 上的位置

如何在小部件的容器内显示 pdf [flutter-web]

如何防止platformViewRegistry出错[flutter-web]

如何将 http url 链接到 flutter-web

flutter-web: build_runner getter 'typeArguments' 没有为类 'Annotation' 错误定义