App一般都会遇到这样的需求:没有登录则跳转登录页面,登录了则跳转至指定页面。
思路:
1.登录之后存储token。
2.路由拦截,没有登录则跳转至登录页面,登录了则跳转至指定页面。
步骤:
一:首先在pubspec.yaml中添加shared_preferences依赖库
shared_preferences: ^2.0.17
整个pubspec.yaml如下所示:
name: flutter_doctor_app
description: A new Flutter application.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.19.2 <3.0.0"
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
shared_preferences: ^2.0.17
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- images/info_image_portrait.png
- images/nav_icon_back.png
- images/logo.png
- images/passwordinvisible.png
- images/passwordvisible.png
- images/weixin_icon.png
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
二.在lib目录下创建common文件夹,创建LoginPrefs.dart文件
LoginPrefs.dart内容如下:
import 'package:flutter/cupertino.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LoginPrefs{
static const String USER_NAME="USER_NAME";//用户名
static const String TOKEN="TOKEN";//token
static late SharedPreferences _prefs;//延迟初始化
static Future<String> init() async {
WidgetsFlutterBinding.ensureInitialized();
_prefs = await SharedPreferences.getInstance();
return 'ok';
}
static void saveUserName(String userName) {
_prefs.setString(USER_NAME, userName);
}
static String? getUserName() {
return _prefs.getString(USER_NAME);
}
static void saveToken(String token){
_prefs.setString(TOKEN, token);
}
static String? getToken() {
return _prefs.getString(TOKEN);
}
static void removeUserName() {
_prefs.remove(USER_NAME);
}
static void removeToken() {
_prefs.remove(TOKEN);
}
static void clearLogin(){
_prefs.clear();
}
}
三.在lib目录的common文件夹下创建MyRoutes.dart文件
MyRoutes.dart内容如下:
//配置路由
import 'package:flutter/material.dart';
import 'package:flutter_doctor_app/common/LoginPrefs.dart';
import '../login.dart';
import '../main.dart';
/*
* 这个方法是固定写法,功能就像是一个拦截器。
*/
Route<dynamic>? onGenerateRoute(RouteSettings settings) {
Map<String, Widget> routes = {
'home': MyHomePage(), //定义app路径
'login': LoginPage(), //定义login路径
};
String routerName = routeBeforeHook(settings);
bool mathMap = false;
Route<dynamic>? mathWidget;
routes.forEach((key, v) {
if (key == routerName) {
mathMap = true;
mathWidget = MaterialPageRoute(builder: (BuildContext context) => v);
}
});
if (mathMap) {
return mathWidget;
}
return MaterialPageRoute(
builder: (BuildContext context) => Container(
child: Text('404'),
));
}
String routeBeforeHook(RouteSettings settings) {
if(checkToken()==false){
return 'login';
}else{
return settings.name!;
}
}
bool checkToken() {
String token = LoginPrefs.getToken()??'';
if ('' != token) return true;
return false;
}
四.在main.dart中修改main方法如下所示:
void main() async{
String value= await LoginPrefs.init();// await 关键字必须用在异步方法中 await等待异步方法执行完毕 异步方法必须用变量接收
if('ok'==value){
runApp(MyApp());
}
}
shared_preferences的初始化过程是个耗时的操作,所以要放在异步方法中,LoginPrefs.dart的init()方法
static Future<String> init() async {
WidgetsFlutterBinding.ensureInitialized();
_prefs = await SharedPreferences.getInstance();
return 'ok';
}
我们需要的是必须要等待初始化完成,我们才可以进行其它操作,所以前面需要await修饰,等待异步初始化完成,而若使用await关键字则必须在异步方法中,所以,修改main方法由async修饰。
void main() async{
String value= await LoginPrefs.init();// await 关键字必须用在异步方法中 await等待异步方法执行完毕 异步方法必须用变量接收
if('ok'==value){
runApp(MyApp());
}
}
五.main.dart添加路由拦截
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
//去除右上角的Debug标签
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: createMaterialColor(Color(0xFF009999)),
// This makes the visual density adapt to the platform that you run
// the app on. For desktop platforms, the controls will be smaller and
// closer together (more dense) than on mobile platforms.
visualDensity: VisualDensity.adaptivePlatformDensity,
),
initialRoute: "home",
onGenerateRoute: onGenerateRoute,
//注册路由表
);
}
}
onGenerateRoute: onGenerateRoute
路由拦截
六.login.dart中点击登录按钮执行的方法:
void onLoginClick() async {
print("登录");
setState(() {
// 当所有编辑框都失去焦点时键盘就会收起
_uNameFocusNode.unfocus();
_uPassFocusNode.unfocus();
LoginPrefs.saveToken(_uNameController.text);//保存token (我这里保存的输入框中输入的值)
Navigator.of(context).pop();//登录页消失
Navigator.pushNamed(context, 'home');//跳转至首页
});
}
至此,就完成了路由拦截功能,没有登录则跳转登录页面,登录了则跳转至指定页面。