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

flutter-web - Avoid initialRoute from initiating when the app launched with a different route via the browser's address bar?

Flutter 新手。

我正在制作一个应用程序,它有一个启动画面,当用户打开应用程序时,该画面最初会出现。 3 秒后,应用程序将显示登录或仪表板屏幕,具体取决于身份验证状态。

这是我的代码。

main.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 秒后,应用程序将打开另一个笔记屏幕。

有什么想法吗?

因为主要逻辑是我们不能在初始状态等待,所以无论您提供什么逻辑,页面都会构建。我有办法解决这个问题,可能还有一些先进的或其他好的解决方案,所以这就是我会用的。

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

所以流程是

  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
       }
     }
    

现在 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,
              );
            }
          }
        }
      },
    );
  }
}

因为第一次渲染总是从根目录“/”开始,所以最好使用您自己的启动画面路径,例如

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',
    );
  }
}


首先,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 这样的状态管理解决方案。