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+1environment: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.2dev_dependencies:flutter_test:sdk: fluttershared_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";//tokenstatic late SharedPreferences _prefs;//延迟初始化static Future 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? onGenerateRoute(RouteSettings settings) {Map routes = {'home': MyHomePage(), //定义app路径'login': LoginPage(), //定义login路径};String routerName = routeBeforeHook(settings);bool mathMap = false;Route? 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
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.@overrideWidget 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');//跳转至首页});}至此,就完成了路由拦截功能,没有登录则跳转登录页面,登录了则跳转至指定页面。