Flutter32.Opensource China主介面My的網路請求校驗和資料封裝處理(04)

augfun發表於2020-10-09

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

效果如下:

 

相關文章