Flutter32.Opensource China主界面My的网络请求校验和数据封装处理(04)

    科技2026-04-16  16

    profile_page.dart主界面跳转逻辑触发,登录以后会通过EventBus跳转到登录的处理eventBus.fire(LoginEvent());

    import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutterapp2/common/event_bus.dart'; import 'package:flutterapp2/constants/Constants.dart'; import 'package:flutterapp2/utils/data_utils.dart'; import 'login_web_page.dart'; /** * 主界面My */ class ProfilePage extends StatefulWidget { @override _ProfilePageState createState() => _ProfilePageState(); } class _ProfilePageState extends State<ProfilePage> { List menuTitles = [ '我的消息', '阅读记录', '我的博客', '我的问答', '我的活动', '我的团队', '邀请好友', ]; List menuIcons = [ Icons.message, Icons.print, Icons.error, Icons.phone, Icons.send, Icons.people, Icons.person, ]; String userAvatar; String userName; @override void initState() { // TODO: implement initState super.initState(); //尝试显示用户信息 _showUerInfo(); eventBus.on<LoginEvent>().listen((event) { //TODO //获取用户信息并显示 }); eventBus.on<LogoutEvent>().listen((event) { //TODO }); } _showUerInfo() { } @override Widget build(BuildContext context) { return ListView.separated( itemBuilder: (context, index) { //My界面的头部 if(index == 0){ //头像用Container装起来 return _buildHeader(); } index -= 1; return ListTile( leading: Icon(menuIcons[index]), title: Text(menuTitles[index]), trailing: Icon(Icons.arrow_forward_ios),//尾巴 onTap: () { _login(); }, ); }, //分割线 separatorBuilder: (context, index) { return Divider(); }, itemCount: menuTitles.length + 1 ); } _login() async { final result = await Navigator.of(context) .push(MaterialPageRoute(builder: (context) => LoginWebPage())); if (result != null && result == 'refresh') { print('Debug profile page LoginEvent'); //登录成功 eventBus.fire(LoginEvent()); } } Container _buildHeader() { return Container( height: 150.0, color: Color(AppColors.APP_THEME), //头像的布局填充 child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ GestureDetector( child: Container( width: 60.0, height: 60.0, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: Color(0xffffffff), width: 2.0, ), image: DecorationImage( //加载网路图片 image: AssetImage('assets/images/ic_avatar_default.png'), fit: BoxFit.cover, ), ), ), onTap: () { //执行登录 _login(); }, ), SizedBox( ), Text( '点击头像登录', style: TextStyle(color: Color(0xffffffff)), ), ], ), ), ); } }

    login_web_page.dart登录页面跳转逻辑,数据拼接组装校验,数据保存完成以后会调用Navigator.pop(context, 'refresh');通过路由跳转到My的界面

    import 'dart:convert'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; import 'package:flutterapp2/constants/Constants.dart'; import 'package:flutterapp2/utils/data_utils.dart'; import 'package:flutterapp2/utils/net_utils.dart'; class LoginWebPage extends StatefulWidget { @override _LoginWebPageState createState() => _LoginWebPageState(); } class _LoginWebPageState extends State<LoginWebPage> { FlutterWebviewPlugin _flutterWebviewPlugin = FlutterWebviewPlugin(); bool isLoading = true; @override void initState() { // TODO: implement initState super.initState(); //监听url的变化 _flutterWebviewPlugin.onUrlChanged.listen((url) { //https://www.oschina.net/action/oauth2/authorize?response_type=code&client_id=6i4Yu6IUqXnR64em0rsJ&redirect_uri=https://www.dongnaoedu.com/ print('Debug LoginWebPage onUrlChanged: $url'); if (mounted) { setState(() { isLoading = true; }); } if (url != null && url.length > 0 && url.contains('?code=')) { //登录成功了 //提取授权码code String code = url.split('?')[1].split('&')[0].split('=')[1]; Map<String, dynamic> params = Map<String, dynamic>(); params['client_id'] = AppInfos.CLIENT_ID; params['client_secret'] = AppInfos.CLIENT_SECRET; params['grant_type'] = 'authorization_code'; params['redirect_uri'] = AppInfos.REDIRECT_URI; params['code'] = '$code'; params['dataType'] = 'json'; NetUtils.get(AppUrls.OAUTH2_TOKEN, params).then((data) { //{"access_token":"aa105aaf-ca4f-4458-822d-1ae6a1fa33f9","refresh_token":"daae8b80-3ca6-4514-a8ae-acb3a82c951c","uid":2006874,"token_type":"bearer","expires_in":510070} //this is login_web_page: {"access_token":"d0e00aa3-4d43-4a05-ab76-546d351ce5d5","refresh_token":"555f4e8a-bccc-4976-9d7e-1d5183ef5798","uid":4571926,"token_type":"bearer","expires_in":604295} print('Debug this is login_web_page: $data'); if (data != null) { Map<String, dynamic> map = json.decode(data); if (map != null && map.isNotEmpty) { //保存token等信息 DataUtils.saveLoginInfo(map); //弹出当前路由,并返回refresh通知我的界面刷新数据 Navigator.pop(context, 'refresh'); } } }); } }); } @override void dispose() { // TODO: implement dispose super.dispose(); _flutterWebviewPlugin.close(); } @override Widget build(BuildContext context) { //authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https List<Widget> _appBarTitle = [ Text( '登录开源中国', style: TextStyle( color: Color(AppColors.APPBAR), ), ), ]; if(isLoading) { _appBarTitle.add(SizedBox( width: 10.0, )); _appBarTitle.add(CupertinoActivityIndicator()); } return WebviewScaffold( url: AppUrls.OAUTH2_AUTHORIZE + '?response_type=code&client_id=' + AppInfos.CLIENT_ID + '&redirect_uri=' + AppInfos.REDIRECT_URI, appBar: AppBar( title: Row( children: _appBarTitle, ), ), withJavascript: true,//允许执行js withLocalStorage: true,//允许本地存储 withZoom: true,//允许网页缩放 ); } }

    net_utils.dart网络数据的请求处理

    import 'package:http/http.dart' as http; class NetUtils{ //返回类型是String,是一个JSON ///authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri static Future<String> get(String url, Map<String, dynamic> params) async{ if(url != null && params != null && params.isNotEmpty) { //拼装参数 StringBuffer sb = StringBuffer('?'); params.forEach((key, value) { sb.write('$key=$value&'); }); //去掉最后一个& String paramStr = sb.toString().substring(0, sb.length - 1); url += paramStr; } //NetUtils : https://www.oschina.net/action/openapi/token?client_id=6ZmjMJ4ZCW7YRhQ4sm42&client_secret=sXWCxyV1KegoF2gethYuBZhI8WQI9fjk&grant_type=authorization_code&redirect_uri=https://www.dongnaoedu.com/&code=1s8xBT&dataType=json print('Debug NetUtils : $url'); http.Response response = await http.get(url); return response.body; } }

    data_utils.dart数据的封装和拼接

    import 'package:shared_preferences/shared_preferences.dart'; class DataUtils{ static const String SP_ACCESS_TOKEN = 'access_token'; static const String SP_REFRESH_TOKEN = 'refresh_token'; static const String SP_UID = 'uid'; static const String SP_TOKEN_TYPE = 'token_type'; static const String SP_EXPIRES_IN = 'expires_in'; static const String SP_IS_LOGIN = 'is_login'; //存储数据 // {"access_token":"aa105aaf-ca4f-4458-822d-1ae6a1fa33f9","refresh_token":"daae8b80-3ca6-4514-a8ae-acb3a82c951c","uid":2006874,"token_type":"bearer","expires_in":510070} static Future<void> saveLoginInfo(Map<String, dynamic> map) async { if (map != null && map.isNotEmpty) { SharedPreferences sp = await SharedPreferences.getInstance(); sp ..setString(SP_ACCESS_TOKEN, map[SP_ACCESS_TOKEN]) ..setString(SP_REFRESH_TOKEN, map[SP_REFRESH_TOKEN]) ..setInt(SP_UID, map[SP_UID]) ..setString(SP_TOKEN_TYPE, map[SP_TOKEN_TYPE]) ..setInt(SP_EXPIRES_IN, map[SP_EXPIRES_IN]) ..setBool(SP_IS_LOGIN, true); } } //清楚登陆数据 static Future<void> clearLoginInfo() async { SharedPreferences sp = await SharedPreferences.getInstance(); sp ..setString(SP_ACCESS_TOKEN, '') ..setString(SP_REFRESH_TOKEN, '') ..setInt(SP_UID, -1) ..setString(SP_TOKEN_TYPE, '') ..setInt(SP_EXPIRES_IN, -1) ..setBool(SP_IS_LOGIN, false); } //是否登录 static Future<bool> isLogin() async { SharedPreferences sp = await SharedPreferences.getInstance(); bool isLogin = sp.getBool(SP_IS_LOGIN); return isLogin != null && isLogin; } //获取token static Future<String> getAccessToken() async { SharedPreferences sp = await SharedPreferences.getInstance(); return sp.getString(SP_ACCESS_TOKEN); } }

    使用EventBus和SharedPreferences需要在yaml文件中

    name: flutterapp2 description: A new Flutter application. publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: sdk: ">=2.7.0 <3.0.0" dependencies: flutter: sdk: flutter cupertino_icons: ^0.1.3 http: ^0.12.2 flutter_webview_plugin: ^0.3.11 shared_preferences: ^0.5.7+3 event_bus: ^1.1.1 dev_dependencies: flutter_test: sdk: flutter flutter: uses-material-design: true assets: #导航栏背景 - assets/images/ic_nav_news_normal.png - assets/images/ic_nav_news_actived.png - assets/images/ic_nav_tweet_normal.png - assets/images/ic_nav_tweet_actived.png - assets/images/ic_nav_discover_normal.png - assets/images/ic_nav_discover_actived.png - assets/images/ic_nav_my_normal.png - assets/images/ic_nav_my_pressed.png #抽屉背景 - assets/images/cover_img.jpg #用户默认头像 - assets/images/ic_avatar_default.png

    打印如下:

    2020-10-08 23:58:40.324 17019-17246/com.example.flutterapp2 I/flutter: Debug LoginWebPage onUrlChanged: https://www.oschina.net/action/oauth2/authorize?response_type=code&client_id=6ZmjMJ4ZCW7YRhQ4sm42&redirect_uri=https://www.dongnaoedu.com/ 2020-10-08 23:58:54.658 17019-17246/com.example.flutterapp2 I/flutter: Debug LoginWebPage onUrlChanged: https://www.dongnaoedu.com/?code=Jsl6Yh&state=# 2020-10-08 23:58:54.668 17019-17246/com.example.flutterapp2 I/flutter: Debug NetUtils : https://www.oschina.net/action/openapi/token?client_id=6ZmjMJ4ZCW7YRhQ4sm42&client_secret=sXWCxyV1KegoF2gethYuBZhI8WQI9fjk&grant_type=authorization_code&redirect_uri=https://www.dongnaoedu.com/&code=Jsl6Yh&dataType=json 2020-10-08 23:58:55.241 17019-17246/com.example.flutterapp2 I/flutter: Debug this is login_web_page: {"access_token":"21b8d7d0-6bef-469f-ba64-033d47387d50","refresh_token":"45545f98-d72c-4b3e-b6bd-f2f037f0a661","uid":4571926,"token_type":"bearer","expires_in":603334} 2020-10-08 23:58:55.252 17019-17246/com.example.flutterapp2 I/flutter: Debug profile page LoginEvent

    效果如下:

     

    Processed: 0.014, SQL: 9