flutter多环境配置及Dio请求封装

flutter 多环境配置及Dio请求封装最佳实践

    • flutter 多环境配置
      • 项目结构概览
      • 创建文件
      • 环境变量公共配置文件 config.dart
      • 配置 dev 环境 (开发环境)
      • 配置 prod 坏境(生产环境)
    • 调整项目入口文件 main.dart
    • 设置项目主页 index.dart
      • 配置 android studio 启动命令
    • 封装 Dio 请求
      • 创建 http.dart 文件
      • 创建 interface.dart 文件
      • 调用接口
    • 最后我们启动项目看下效果吧
      • 模板项目地址
      • 结束语
      • 如果这篇文章对你有帮助请支持下作者创作更多最佳实践文章
        • 支付宝
        • 微信

小伙伴,很高兴能看到这篇文章,也许你是 flutter 大牛,也许你是小白,请耐心看完, 这是 flutter 多环境配置及 Dio 请求封装的最佳实践, 相信这也是全网最好的一篇 flutter 实践文章, 适合大中小型项目, 相信一定会有所收获

如果阅读过程中让你感到困惑,请按照文章步骤,创建对应文件,编写代码运行项目感受一下,相信这不会让你失望的

flutter 多环境配置

1
2
3
所谓多环境是指 开发环境, 联调环境, 测试环境, 演示环境, 生产环境等,当我们在各个环境之间切换时,势必需要快速高效的解决方
案, 多环境配置由此而生, 相信在看到这篇文章之前,也看过很多关于环境配置的博文,大多都是在项目中手动切换环境变量以达到环境
切换目的, 虽然能解决问题但是总感觉有些low,下面让我解开 flutter 正确的启动方式

项目结构概览

1
2
先来看下图的 项目结构总览, 接下来我们会逐一创建各个文件,并详细讲解其作用
==需要注意每个文件的位置==
  1. config.dart // 环境配置文件
  2. dev.dart // 开发环境配置文件
  3. prod.dart // 生产环境配置文件
  4. main.dart // 项目入口文件
  5. index.dart // 项目主页文件
  6. http.dart // dio请求封装文件
  7. interface.dart // 接口文件
    在这里插入图片描述

创建文件

  1. 在 lib 目录下创建 public 文件夹

  2. 在public目录下创建 config.dart 文件

  3. 在public目录下创建 dev.dart 文件

  4. 在public目录下创建 prod.dart 文件

    目前先创建这几个文件

环境变量公共配置文件 config.dart

1
打开 config.dart 文件 编写如下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/// 注意这里包的引入路径
/// 推荐使用 android studio 编写 flutter 应用
/// 如果你是 Android studio 用户 这里可以不着急引入包,当你把代码复制到自己的项目里时,由于路径不对,
/// 编辑器检测不到对应的包时,对应的代码会变红,如下图,此时把选中红色波浪线的单词按住 ctrl + enter键 选择需要的包就好了
import 'package:flutter/material.dart';

/**
 * @CreateDate:   2020/7/2 20:45
 * @Author:       Gleason
 * @Description:  环境变量
 **/
 /// 这里继承自 InheritedWidget 这个类
 /// 可以在 weiget 中通过上下文获取到环境变量
 /// 当然 也可把 主题和一些全局 设置放到这里
class ENV extends InheritedWidget {
  static String appName; // 系统名称
  static String envName; // 运行环境
  static String baseUrl; // 基础url

  ENV({
    @required String appName,
    @required String envName,
    @required String baseUrl,
    @required Widget child,
  }) : super(child: child){
    ENV.appName = appName;
    ENV.envName = envName;
    ENV.baseUrl = baseUrl;
  }
  // 这里 是在 weiget 中拿到当前环境变量的关键
  static ENV of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType(aspect: ENV);
  }

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) => false;
}

配置 dev 环境 (开发环境)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import 'package:flutter_template/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter_template/public/config.dart';
void main() {

  var configuredApp = new ENV(
    appName: 'app 名称', // 项目名称 或者 app 名称
    envName: 'dev',     // 环境变量
    baseUrl: 'https://www.dev.com/', // 接口基础地址
    child: new MyApp(),
  );

  runApp(configuredApp);
}

配置 prod 坏境(生产环境)

1
2
3
4
5
6
7
8
9
10
11
12
13
import 'package:flutter_template/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter_template/public/config.dart';
void main() {
  var configuredApp = new ENV(
    appName: 'app 名称', // 项目名称 或者 app 名称
    envName: 'prod',// 环境变量
    baseUrl: 'https://www.prod.com/', // 接口基础地址
    child: new MyApp(),
  );

  runApp(configuredApp);
}

调整项目入口文件 main.dart

1
2
如果不知道 main.dart 文件那来的 请看开篇 项目结构概览
因为 main.dart 作为项目入口文件 所以我们要把项目首页进行迁移到 index.dart 做下功能文件区分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/// 项目入口文件
import 'package:flutter/material.dart';
import 'package:flutter_template/index.dart';
import 'package:flutter_template/public/config.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 在任何地方调用AppConfig.of(context)以获取特定于环境的配置
    var config = ENV.of(context);
    print('config$config')
    return new MaterialApp(
      title: ENV.appName,
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new HomePage(), //这里将引入 index.dart 中的 homepage weiget
    );
  }
}

设置项目主页 index.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import 'package:flutter/material.dart';
/// 这里需要引入 环境变量配置
import 'package:flutter_template/public/config.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => new _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(ENV.appName),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Container(
              /// 通过 ENV 环境变量可以拿到我们配置的环境信息
              child: Text('app 名称: ${ENV.envName}.'),
              padding: EdgeInsets.all(15.0),
            ),
            Container(
              child: Text('baseUrl: ${ENV.baseUrl}.'),
              padding: EdgeInsets.all(15.0),
            ),
          ],
        ),
      ),
    );
  }
}

配置 android studio 启动命令

1
按照图示选择 Edit configur... 选项, 接下来按照 下面图片跟着配置就可以了,如果不知道我在干啥,就先跟着做,一会配置完就懂了

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1
重复上述操作,照此方式配置 prod  测试, 演示, 联调环境吧

相信照着上面配置完 你的 main.dart 被打了一个小红叉了吧
在这里插入图片描述
接下来 删除 原来 main.dart 启动命令
在这里插入图片描述
现在你的启动项应该和我的一样了, 点击 启动项 旁边的启动按钮试试把 是不是感觉打开了新世界的大门
在这里插入图片描述

封装 Dio 请求

1
接下来我们封装的 dio 请求要和之前的 环节配置关联上这样才是一个整体, 跟着往下操作吧

创建 http.dart 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter_template/public/config.dart';

/// dio 初始化设置
final dio = Dio(BaseOptions(
  baseUrl: ENV.baseUrl, // 如果你启动的是 dev 那么这里的 baseUrl = https://www.dev.com/
  connectTimeout: 5000, // 配置请求超时
  receiveTimeout: 100000,
  contentType:"application/json; charset=utf-8", // 设置content-type
));

/// 接口封装
/// 说到这里我们先来讲下接口构成
/// 接口 = 基础路径 + 接口地址 也就是 interface = baseUrl + path
/// 比如说登录接口 http://www.dev.com/login
/// 这个登录接口的构成 由 baseUtl(http://www.dev.com/) 和 path(login) 组成
/// baseUrl 我们在环境变量 设置过(dev 和 prod文件里的baseUrl)
/// path 是我们在后端提供的接口文档中获得的
/// 下面
/// main 方法中的参数 url 只需传 login 即可
/// main 方法中 type 是请求类型 如get/post/delete/put ....
/// body 是请求带参
Future main({String url = '', String type = "get", dynamic body}) async {
  type = type.toUpperCase();
  print('请求参数: url:$url,type:$type,body:$body');
  if (type == 'POST') {

//     await dio.(url).then((value) => value).catchError((e)=>e);
    Response response = await dio.post(url,data: body);
    return response.data;
  }
}

创建 interface.dart 文件

1
2
3
4
5
6
7
8
9
10
11
import 'package:flutter_template/public/http.dart';

class Fetch {
  /// login 接口
  static login(body)=> main(url: 'login',type: 'post', body:body);
  /// 注册 接口
  static register(body)=> main(url: 'register',type: 'post', body:body);
  /// 把项目中用到 所有接口都写在这里 接口统一管理
  /// 如果接口名称改动了 只需要 修改 url 参数即可,项目里用到该接口的地方就不需要修改了
  /// 小伙伴是不是觉得 这才是 flutter 最佳实践
}

调用接口

1
接下来我们要结合上边所有配置 调用我们配置好的接口了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import 'package:flutter/material.dart';
import 'package:flutter_template/public/config.dart';
import 'package:flutter_template/public/interface.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => new _HomePageState();
}

class _HomePageState extends State<HomePage> {
  /// 接收 调用接口返回数据变量
  String data;
  /// 组件初始化时 调用接口
  @override
  void initState() {
    loadData();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(ENV.appName),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Container(
              child: Text('app 名称: ${ENV.envName}.'),
              padding: EdgeInsets.all(15.0),
            ),
            Container(
              child: Text('当前环境: ${ENV.baseUrl}.'),
              padding: EdgeInsets.all(15.0),
            ),
            Container(
              child: Text('响应数据: \n$data.'),
              padding: EdgeInsets.all(15.0),
            ),
          ],
        ),
      ),
    );
  }
  /// 调用接口方法
  void loadData() async {
    Map result =
        await Fetch.login({'userid': 'bianliuzhu', 'password': 'bianliuzhu'});
    print('result:${result}');
    /// 更新数据
    setState(() {
      data = result['user'].toString();
    });
  }
}

最后我们启动项目看下效果吧

在这里插入图片描述

模板项目地址

有些小伙伴可能脑袋不够用了, 或者编写代码时出错了,这里我放了自己的模板项目地址

链接: 模板项目地址.

结束语

1
2
到这里我们所有的配置都已经完成了, 另外根据请求方法不同和后台返回数据格式不同, 在 http.dart 文件中我只配置了
post 请求的, 只对我们公司的数据进行了格式处理, 简单举个列子,小伙伴们需要举一反三,自己配置其他请求和数据格式化

如果这篇文章对你有帮助请支持下作者创作更多最佳实践文章

支付宝

在这里插入图片描述

微信

在这里插入图片描述