flutter-web - Избегать инициализации initialRoute, когда приложение запускается с другим маршрутом через адресную строку браузера?

Aug 21 2020

Впервые во 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 секунды приложение открывает еще один экран заметок.

Есть идеи?

Ответы

6 Spatz Aug 24 2020 at 21:21

Поскольку первый рендеринг всегда начинается с корня '/', предпочтительно использовать свой собственный путь для экрана-заставки, например

initialRoute: '/splash'.

Чтобы скрыть этот путь в адресной строке, заменить маршруты карты с генератором маршрута:

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


2 KrishBhanushali Aug 20 2020 at 22:58

Смотрите, поскольку основная логика заключается в том, что мы не можем ожидать в состоянии инициализации, поэтому страница будет строиться независимо от любой логики, которую вы предоставляете. У меня есть решение, может быть какое-то продвижение или другие хорошие решения, так что это то, что я бы использовал.

Я бы использовал концепцию будущего строителя. Что он сделает, так это дождется моего сервера, а затем создаст все приложение.

Итак, процесс

  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,
              );
            }
          }
        }
      },
    );
  }
}
tanweeranwar Aug 25 2020 at 17:09

Прежде всего, flutter-web, как и любое другое одностраничное приложение, поддерживает маршрутизацию на основе хэша. В результате, если вы хотите получить доступ

localhost: 8000 / примечания

вы должны получить к нему доступ как

локальный: 8000 / # / примечания

Более чистый способ обработки состояния аутентификации

Вызовите функцию getAuthState перед runApp (), чтобы убедиться, что состояние аутентификации установлено до инициализации приложения. И передайте 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.