Проблема: мое приложение всегда отображает экран входа в систему, независимо от того, какой тип навигации я выполняю (например, установка исходного местоположения на другую страницу, context.push, context.go и т. д.). Я реализовал функцию перенаправления в системе аутентификации, которая перенаправляет пользователя обратно на страницу входа в систему, если он не прошел аутентификацию, но, похоже, это не является виновником (два оператора печати: «authState Changes» и «Redirect!» не были вызваны). когда я нажимал кнопку навигации).
Мой файл main.dart:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:sneaker_app/models/cart.dart';
import 'package:sneaker_app/routes/app_route_config.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:sneaker_app/services/auth_service.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// Referesh GoRouter configuration every time authState changes (Authentication guaranteed)
FirebaseAuth.instance.authStateChanges().listen((User? user) {
print("authState changes");
MyAppRouter.router.refresh();
});
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<Cart>(create: (context) => Cart()),
ChangeNotifierProvider<AuthService>(
create: (context) => AuthService())
],
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.grey)),
routerConfig: MyAppRouter.router,
));
}
}
Конфигурации маршрутизатора моего приложения:
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:sneaker_app/models/shopee_tile.dart';
import 'package:sneaker_app/pages/home_page.dart';
import 'package:sneaker_app/pages/item_page.dart';
import 'package:sneaker_app/pages/login_page.dart';
import 'package:sneaker_app/pages/signup_page.dart';
import 'package:sneaker_app/routes/app_route_constants.dart';
import 'package:sneaker_app/services/auth_service.dart';
class MyAppRouter {
static final GoRouter router = GoRouter(
initialLocation: "/login",
routes: [
GoRoute(
name: MyAppRouteConstants.homeRouteName,
path: "/",
builder: (context, state) => HomePage()),
GoRoute(
name: MyAppRouteConstants.itemRouteName,
path: "/item/:id",
builder: (context, state) {
ShopeeTile item = state.extra as ShopeeTile;
return ItemPage(
id: int.parse(state.pathParameters["id"]!),
item: item,
);
}),
GoRoute(
name: MyAppRouteConstants.loginRouteName,
path: "/login",
builder: (context, state) => LoginPage()),
GoRoute(
name: MyAppRouteConstants.signupRouteName,
path: "/signup",
builder: (context, state) => SignupPage()),
],
redirect: (BuildContext context, GoRouterState state) async {
final bool loggedIn =
Provider.of<AuthService>(context, listen: false).user != null;
final bool loggingIn = state.matchedLocation == "/login";
print("Redirect!");
if (!loggedIn) return "/login";
if (loggingIn) return "/";
// no need to redirect at all
return null;
},
);
}
Я могу гарантировать, что константы в MyAppRouteConstants соответствуют их пути.
Вот виджет кнопки на странице входа
TextButton(
child: Text('Sign up'),
onPressed: () {
context.pushNamed(MyAppRouteConstants.signupRouteName);
},
),
Я попытался отладить проблему, вставив операторы печати, но не смог понять, почему приложение застряло только на странице входа и вообще не перемещалось.
Учитывая предоставленные вами фрагменты кода, я могу предположить, что проблема заключается в следующей строке:
routerConfig: MyAppRouter.router,
Поскольку у вас, очевидно, есть встроенная аутентификация, позволяющая решить, куда попадает пользователь, метод сборки MyApp вызывается снова. Однако из-за этой строки создается новый объект GoRouter, поскольку вы назначаете новый объект маршрутизатору в MyAppRouter. И эта конфигурация затем принимает LoginPage (/login) в качестве начального местоположения.
В качестве теста попробуйте сохранить объект GoRouter в файле main.dart как глобальную переменную:
GoRouter myRouter = GoRouter(...)
Теперь передайте эту переменную как routerConfig. Возможно, это уже решение.
Я предполагаю, что перенаправление вызывается каждый раз, когда вы переходите на страницу, даже если это ваша начальная страница. Итак, если вы запускаете свое приложение, вы переходите к /login. Эта навигация должна вызывать вашу логику внутри вашего перенаправления.
Кроме того, у меня есть вопрос. Я помечаю GoRouter myRouter в классе appRouterConfigs как статический и читал в Интернете, что если переменная помечена как статическая, то существует только один «экземпляр» этой переменной, доступный каждому экземпляру. Так почему же, когда метод сборки вызывается несколько раз, а также создается множество новых экземпляров MyAppRouterConfigs, назначаются разные экземпляры «myRouter»? Разве они все не ссылаются на одну и ту же статическую переменную маршрутизатора в этом классе?
Это только один экземпляр. Но каждый раз, когда вы вызываете build, он переходит в строку MyAppRouter.router. Это проверяет, что находится за маршрутизатором. И в вашем случае вы всегда создаете новый экземпляр GoRouter и записываете его в свое статическое поле. Таким образом, каждый раз, когда вы вызываете сборку, вы создаете новый GoRouter, который можно использовать в любом месте вашего проекта. Вы не хотите создавать экземпляр каждый раз, когда вызываете сборку, вам не нужно создавать его только один раз. И этот экземпляр следует использовать в вашем коде, если он вам нужен.
Теперь у меня есть «Перенаправление!» напечатано на консоли: O, хотя мой статус аутентификации никогда не менялся