thl 7 yıl önce
ebeveyn
işleme
a458f68766

+ 4 - 0
CHANGELOG.md

@@ -1,3 +1,7 @@
+## 0.1.6
+
+* TODO: Dio Util, print http log, singleton mode.
+
 ## 0.1.5
 
 * TODO: Screen adaptation,屏幕适配.

+ 88 - 19
README.md

@@ -3,21 +3,53 @@
 
 ## [flustars] Flutter常用工具类库。主要对第三方库封装,以便于使用。如果你有好的工具类欢迎PR.  
 
-## 更新说明  
+## 更新说明
+v0.1.6(2018.12.20)  
+新增网络请求工具DioUtil, 单例模式,可输出请求日志。详细请求+解析请参考[flutter_wanandroid][flutter_wanandroid_github]项目。
+```
+// 打开debug模式.
+DioUtil.openDebug(); 
+  
+// 两种单例请求方式.
+DioUtil().request<List>(Method.get, "banner/json");
+DioUtil.getInstance().request(Method.get, "banner/json");
+  
+//示例
+LoginReq req = new LoginReq('username', 'password');
+DioUtil().request(Method.post, "user/login",data: req.toJson());
+  
+//示例
+FormData formData = new FormData.from({
+      "username": "username",
+      "password": "password",
+    });
+DioUtil().requestR(Method.post, "user/login",data: rformData);
+  
+// 网络请求日志  
+I/flutter ( 5922): ----------------Http Log----------------
+I/flutter ( 5922): [statusCode]:   200
+I/flutter ( 5922): [request   ]:   method: GET  baseUrl: http://www.wanandroid.com/  path: lg/collect/list/0/json
+I/flutter ( 5922): [reqdata   ]:   null
+I/flutter ( 5922): [response  ]:   {data: {curPage: 1, datas: [], offset: 0, over: true, pageCount: 0, size: 20, total: 0}, errorCode: 0, errorMsg: }
+```
+
 v0.1.5(2018.12.14)  
-ScreenUtil新增屏幕适配。
+ScreenUtil 新增屏幕适配。
 ```
-//配置设计稿尺寸 默认 360.0 / 640.0 / 3.0
+//如果设计稿尺寸默认配置一致,无需该设置。  配置设计稿尺寸 默认 360.0 / 640.0 / 3.0
 setDesignWHD(_designW,_designH,_designD);
 
 //返回根据屏幕宽适配后尺寸(单位 dp or pt)
 ScreenUtil.getInstance().getWidth(100.0);  
+ScreenUtil().getWidth(100.0); 
 
 //返回根据屏幕高适配后尺寸(单位 dp or pt)
-ScreenUtil.getInstance().getHeight(100.0);  
+ScreenUtil.getInstance().getHeight(100.0); 
+ScreenUtil().getHeight(100.0);  
 
 //返回根据屏幕宽适配后字体尺寸
-ScreenUtil.getInstance().getSp(12.0);  
+ScreenUtil.getInstance().getSp(12.0); 
+ScreenUtil().getSp(100.0);   
 ```
 v0.1.4(2018.11.22)  
 ScreenUtil不依赖context获取屏幕数据。  
@@ -25,16 +57,17 @@ ScreenUtil不依赖context获取屏幕数据。
 新增MyAppBar,不需要GlobalKey就能openDrawer。  
 
 ## 关于示例
-本项目中不包含示例,所有示例均在[flutter_demos](https://github.com/Sky24n/flutter_demos)项目中。  
+本项目中不包含示例,所有示例均在[flutter_demos][flutter_demos_github]项目中。  
 
-完整项目[flutter_wanandroid](https://github.com/Sky24n/flutter_wanandroid),包含启动页,引导页,主题色切换,应用国际化多语言,版本更新等功能。欢迎体验!  
+完整项目[flutter_wanandroid][flutter_wanandroid_github],包含启动页,引导页,主题色切换,应用国际化多语言,版本更新等功能。欢迎体验!  
 
-### [flustars](https://github.com/Sky24n/flustars)  
- 1、SpUtil       : SharedPreferences 工具类.  
- 2、ScreenUtil   : 屏幕适配,获取屏幕宽、高、密度,AppBar高,状态栏高度,屏幕方向.  
- 3、WidgetUtil   : 获取Widget宽高,在屏幕上的坐标.  
+### [Flutter工具类库 flustars][flustars_github]   
+ 1、DioUtil      : Dio 工具类.   
+ 2、SpUtil       : 单例"同步" SharedPreferences 工具类.  
+ 3、ScreenUtil   : 屏幕适配,获取屏幕宽、高、密度,AppBar高,状态栏高度,屏幕方向.  
+ 4、WidgetUtil   : 获取Widget宽高,在屏幕上的坐标.  
 
-### [common_utils](https://github.com/Sky24n/common_utils)  
+### [Dart常用工具类库 common_utils][common_utils_github]  
  1、TimelineUtil : 时间轴.(新)  
  2、TimerUtil    : 倒计时,定时任务.(新)  
  3、MoneyUtil    : 精确转换,元转分,分转元,支持格式输出.(新)  
@@ -44,15 +77,17 @@ ScreenUtil不依赖context获取屏幕数据。
  7、NumUtil      : 保留x位小数, 精确加、减、乘、除, 防止精度丢失.  
  8、ObjectUtil   : 判断对象是否为空(String List Map),判断两个List是否相等. 
 
-## Demo: [flutter_demos](https://github.com/Sky24n/flutter_demos).
-## APK: [点击下载v1.0.4](https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppStore/flutter_demos.apk)
-## Android扫码下载APK
-  ![](https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/qrcode.png)
+## Demo Github :  
+ [flutter_wanandroid][flutter_wanandroid_github] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [flutter_demos][flutter_demos_github]
+## 点击下载APK :  
+ [v0.1.2][flutter_wanandroid_apk] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [v1.0.4][flutter_demos_apk]
+## 扫码下载APK :
+  ![flutter_wanandroid][flutter_wanandroid_qr] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ![flutter_demos][flutter_demos_qr]
 
 ### Screenshot
-<img src="https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/Screenshot_20181003-234414.jpg" width="200">   <img src="https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/Screenshot_20181003-211011.jpg" width="200">   <img src="https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/Screenshot_20180930-012302.jpg" width="200">  
-<img src="https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/Screenshot_20180930-012431.jpg" width="200">  <img src="https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/Screenshot_20180919-231618.jpg" width="200">   <img src="https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/Screenshot_20180926-144840.png" width="200">  
-<img src="https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/Screenshot_20180919-224204.jpg" width="200">   <img src="https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/Screenshot_20180919-224146.jpg" width="200">   <img src="https://github.com/Sky24n/LDocuments/blob/master/AppImgs/flutter_demos/Screenshot_20180919-224231.jpg" width="200">   
+<img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/Screenshot_20181003-234414.jpg" width="200">   <img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/Screenshot_20181003-211011.jpg" width="200">   <img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/Screenshot_20180930-012302.jpg" width="200">  
+<img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/Screenshot_20180930-012431.jpg" width="200">  <img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/Screenshot_20180919-231618.jpg" width="200">   <img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/Screenshot_20180926-144840.png" width="200">  
+<img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/Screenshot_20180919-224204.jpg" width="200">   <img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/Screenshot_20180919-224146.jpg" width="200">   <img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/Screenshot_20180919-224231.jpg" width="200">   
 
 ### APIs
 
@@ -60,6 +95,18 @@ ScreenUtil不依赖context获取屏幕数据。
 dependencies:
   flustars: x.x.x  #latest version
 ```
+* #### DioUtil
+```
+openDebug()
+setConfig(config)
+request<T>(method, path, {data, options, cancelToken})
+requestR<T>(method, path, {data, options, cancelToken})
+download(urlPath,savePath, {...})
+getDio()
+getDefOptions()
+createNewDio()
+```
+
 * #### SpUtil
 ```
 getString
@@ -148,5 +195,27 @@ double dx = offset.dy
 
 ```
 
+## 作者简书,欢迎关注~
+ [![jianshu][jianshuSvg]][jianshu]
+
+## Donations
+ 如果您觉得该库不错的话,欢迎随意打赏,请作者喝杯咖啡~   
+ <img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/alipay.png" width="240">  <img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/wechat.png" width="240">    
+ <img src="https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/alipay_reward.png" width="240">
+
+
+[flutter_wanandroid_github]: https://github.com/Sky24n/flutter_wanandroid
+[flutter_wanandroid_apk]: https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppStore/flutter_wanandroid.apk
+[flutter_wanandroid_qr]: https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_wanandroid/qrcode.png
+
+[flutter_demos_github]: https://github.com/Sky24n/flutter_demos
+[flutter_demos_apk]: https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppStore/flutter_demos.apk
+[flutter_demos_qr]: https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_demos/qrcode.png
+
+[common_utils_github]: https://github.com/Sky24n/common_utils
+
+[flustars_github]: https://github.com/Sky24n/flustars
 
+[jianshuSvg]: https://img.shields.io/badge/简书-@Sky24n-34a48e.svg
+[jianshu]: https://www.jianshu.com/u/cbf2ad25d33a
 

+ 3 - 3
analysis_options.yaml

@@ -2,9 +2,9 @@
 # Source of linter options:
 # http://dart-lang.github.io/linter/lints/options/options.html
 analyzer:
-  strong-mode:
-    implicit-casts: false
-    implicit-dynamic: false
+  strong-mode: true
+#    implicit-casts: false
+#    implicit-dynamic: false
   errors:
     todo: ignore
   exclude:

+ 28 - 3
example/lib/main.dart

@@ -1,3 +1,4 @@
+import 'package:dio/dio.dart';
 import 'package:flustars/flustars.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
@@ -62,13 +63,37 @@ class MainPage extends StatefulWidget {
 }
 
 class MainPageState extends State<MainPage> {
+  WidgetUtil widgetUtil = new WidgetUtil();
+
+  @override
+  void initState() {
+    super.initState();
+
+    DioUtil.openDebug(); //打开debug模式
+
+    Options options = DioUtil.getDefOptions();
+    options.baseUrl = "http://www.wanandroid.com/";
+    HttpConfig config = new HttpConfig(options: options);
+    DioUtil().setConfig(config);
+
+    DioUtil()
+        .request<List>(Method.get, "banner/json")
+        .then((BaseResp<List> resp) {
+      print("BaseResp: " + resp.toString());
+    });
+
+    widgetUtil.asyncPrepares(true, (_) {
+      print("Widget 渲染完成...");
+    });
+  }
+
   @override
   Widget build(BuildContext context) {
-    double width = ScreenUtil.getInstance().screenWidth;
-    double height = ScreenUtil.getInstance().screenHeight;
+    double width = ScreenUtil().screenWidth;
+    double height = ScreenUtil().screenHeight;
     double density = ScreenUtil.getInstance().screenDensity;
     double tempW = ScreenUtil.getInstance().getWidth(360.0);
-    double tempH = ScreenUtil.getInstance().getHeight(360.0);
+    double tempH = ScreenUtil().getHeight(360.0);
 
     print(
         "width: $width, height: $height, density: $density, tempW: $tempW, tempH: $tempH");

+ 1 - 0
lib/flustars.dart

@@ -5,3 +5,4 @@ export 'src/ui/my_app_bar.dart';
 export 'src/screen_util.dart';
 export 'src/widget_util.dart';
 export 'src/sp_util.dart';
+export 'src/dio_util.dart';

+ 423 - 0
lib/src/dio_util.dart

@@ -0,0 +1,423 @@
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:dio/dio.dart';
+
+/**
+ * @Author: thl
+ * @GitHub: https://github.com/Sky24n
+ * @JianShu: https://www.jianshu.com/u/cbf2ad25d33a
+ * @Email: 863764940@qq.com
+ * @Description: Dio Util.
+ * @Date: 2018/12/19
+ */
+
+/// <BaseResp<T> 返回 status code msg data.
+class BaseResp<T> {
+  String status;
+  int code;
+  String msg;
+  T data;
+
+  BaseResp(this.status, this.code, this.msg, this.data);
+
+  @override
+  String toString() {
+    StringBuffer sb = new StringBuffer('{');
+    sb.write("\"status\":\"$status\"");
+    sb.write(",\"code\":$code");
+    sb.write(",\"msg\":\"$msg\"");
+    sb.write(",\"data\":\"$data\"");
+    sb.write('}');
+    return sb.toString();
+  }
+}
+
+/// <BaseRespR<T> 返回 status code msg data Response.
+class BaseRespR<T> {
+  String status;
+  int code;
+  String msg;
+  T data;
+  Response response;
+
+  BaseRespR(this.status, this.code, this.msg, this.data, this.response);
+
+  @override
+  String toString() {
+    StringBuffer sb = new StringBuffer('{');
+    sb.write("\"status\":\"$status\"");
+    sb.write(",\"code\":$code");
+    sb.write(",\"msg\":\"$msg\"");
+    sb.write(",\"data\":\"$data\"");
+    sb.write('}');
+    return sb.toString();
+  }
+}
+
+/// 请求方法.
+class Method {
+  static final String get = "GET";
+  static final String post = "POST";
+  static final String put = "PUT";
+  static final String head = "HEAD";
+  static final String delete = "DELETE";
+  static final String patch = "PATCH";
+}
+
+///Http配置.
+class HttpConfig {
+  /// constructor.
+  HttpConfig({
+    this.status,
+    this.code,
+    this.msg,
+    this.data,
+    this.options,
+    this.pem,
+    this.pKCSPath,
+    this.pKCSPwd,
+  });
+
+  /// BaseResp [String status]字段 key, 默认:status.
+  String status;
+
+  /// BaseResp [int code]字段 key, 默认:errorCode.
+  String code;
+
+  /// BaseResp [String msg]字段 key, 默认:errorMsg.
+  String msg;
+
+  /// BaseResp [T data]字段 key, 默认:data.
+  String data;
+
+  /// Options.
+  Options options;
+
+  /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验.
+  /// PEM证书内容.
+  String pem;
+
+  /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验.
+  /// PKCS12 证书路径.
+  String pKCSPath;
+
+  /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验.
+  /// PKCS12 证书密码.
+  String pKCSPwd;
+}
+
+/// 单例 DioUtil.
+/// debug模式下可以打印请求日志. DioUtil.openDebug().
+/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio).
+class DioUtil {
+  static final DioUtil _singleton = DioUtil._init();
+  static Dio _dio;
+
+  /// BaseResp [String status]字段 key, 默认:status.
+  String _statusKey = "status";
+
+  /// BaseResp [int code]字段 key, 默认:errorCode.
+  String _codeKey = "errorCode";
+
+  /// BaseResp [String msg]字段 key, 默认:errorMsg.
+  String _msgKey = "errorMsg";
+
+  /// BaseResp [T data]字段 key, 默认:data.
+  String _dataKey = "data";
+
+  /// Options.
+  Options _options = getDefOptions();
+
+  /// PEM证书内容.
+  String _pem;
+
+  /// PKCS12 证书路径.
+  String _pKCSPath;
+
+  /// PKCS12 证书密码.
+  String _pKCSPwd;
+
+  /// 是否是debug模式.
+  static bool _isDebug = false;
+
+  static DioUtil getInstance() {
+    return _singleton;
+  }
+
+  factory DioUtil() {
+    return _singleton;
+  }
+
+  DioUtil._init() {
+    _dio = new Dio(_options);
+  }
+
+  /// 打开debug模式.
+  static void openDebug() {
+    _isDebug = true;
+  }
+
+  /// set Config.
+  void setConfig(HttpConfig config) {
+    _statusKey = config.status ?? _statusKey;
+    _codeKey = config.code ?? _codeKey;
+    _msgKey = config.msg ?? _msgKey;
+    _dataKey = config.data ?? _dataKey;
+    _mergeOption(config.options);
+    _pem = config.pem ?? _pem;
+    if (_dio != null) {
+      _dio.options = _options;
+      if (_pem != null) {
+        _dio.onHttpClientCreate = (HttpClient client) {
+          client.badCertificateCallback =
+              (X509Certificate cert, String host, int port) {
+            if (cert.pem == _pem) {
+              // 证书一致,则放行
+              return true;
+            }
+            return false;
+          };
+        };
+      }
+      if (_pKCSPath != null) {
+        _dio.onHttpClientCreate = (HttpClient client) {
+          SecurityContext sc = new SecurityContext();
+          //file为证书路径
+          sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd);
+          HttpClient httpClient = new HttpClient(context: sc);
+          return httpClient;
+        };
+      }
+    }
+  }
+
+  /// Make http request with options.
+  /// [method] The request method.
+  /// [path] The url path.
+  /// [data] The request data
+  /// [options] The request options.
+  /// <BaseResp<T> 返回 status code msg data .
+  Future<BaseResp<T>> request<T>(String method, String path,
+      {data, Options options, CancelToken cancelToken}) async {
+    Response response = await _dio.request(path,
+        data: data,
+        options: _checkOptions(method, options),
+        cancelToken: cancelToken);
+    _printHttpLog(response);
+    String _status;
+    int _code;
+    String _msg;
+    T _data;
+    if (response.statusCode == HttpStatus.ok ||
+        response.statusCode == HttpStatus.created) {
+      try {
+        if (response.data is Map) {
+          _status = (response.data[_statusKey] is int)
+              ? response.data[_statusKey].toString()
+              : response.data[_statusKey];
+          _code = (response.data[_codeKey] is String)
+              ? int.tryParse(response.data[_codeKey])
+              : response.data[_codeKey];
+          _msg = response.data[_msgKey];
+          _data = response.data[_dataKey];
+        } else {
+          Map<String, dynamic> _dataMap = _decodeData(response);
+          _status = (_dataMap[_statusKey] is int)
+              ? _dataMap[_statusKey].toString()
+              : _dataMap[_statusKey];
+          _code = (_dataMap[_codeKey] is String)
+              ? int.tryParse(_dataMap[_codeKey])
+              : _dataMap[_codeKey];
+          _msg = _dataMap[_msgKey];
+          _data = _dataMap[_dataKey];
+        }
+        return new BaseResp(_status, _code, _msg, _data);
+      } catch (e) {
+        return new Future.error(new DioError(
+          response: response,
+          message: "data parsing exception...",
+          type: DioErrorType.RESPONSE,
+        ));
+      }
+    }
+    return new Future.error(new DioError(
+      response: response,
+      message: "statusCode: $response.statusCode, service error",
+      type: DioErrorType.RESPONSE,
+    ));
+  }
+
+  /// Make http request with options.
+  /// [method] The request method.
+  /// [path] The url path.
+  /// [data] The request data
+  /// [options] The request options.
+  /// <BaseRespR<T> 返回 status code msg data  Response.
+  Future<BaseRespR<T>> requestR<T>(String method, String path,
+      {data, Options options, CancelToken cancelToken}) async {
+    Response response = await _dio.request(path,
+        data: data,
+        options: _checkOptions(method, options),
+        cancelToken: cancelToken);
+    _printHttpLog(response);
+    String _status;
+    int _code;
+    String _msg;
+    T _data;
+    if (response.statusCode == HttpStatus.ok ||
+        response.statusCode == HttpStatus.created) {
+      try {
+        if (response.data is Map) {
+          _status = (response.data[_statusKey] is int)
+              ? response.data[_statusKey].toString()
+              : response.data[_statusKey];
+          _code = (response.data[_codeKey] is String)
+              ? int.tryParse(response.data[_codeKey])
+              : response.data[_codeKey];
+          _msg = response.data[_msgKey];
+          _data = response.data[_dataKey];
+        } else {
+          Map<String, dynamic> _dataMap = _decodeData(response);
+          _status = (_dataMap[_statusKey] is int)
+              ? _dataMap[_statusKey].toString()
+              : _dataMap[_statusKey];
+          _code = (_dataMap[_codeKey] is String)
+              ? int.tryParse(_dataMap[_codeKey])
+              : _dataMap[_codeKey];
+          _msg = _dataMap[_msgKey];
+          _data = _dataMap[_dataKey];
+        }
+        return new BaseRespR(_status, _code, _msg, _data, response);
+      } catch (e) {
+        return new Future.error(new DioError(
+          response: response,
+          message: "data parsing exception...",
+          type: DioErrorType.RESPONSE,
+        ));
+      }
+    }
+    return new Future.error(new DioError(
+      response: response,
+      message: "statusCode: $response.statusCode, service error",
+      type: DioErrorType.RESPONSE,
+    ));
+  }
+
+  /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method].
+  /// [urlPath]: The file url.
+  /// [savePath]: The path to save the downloading file later.
+  /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress].
+  Future<Response> download(
+    String urlPath,
+    savePath, {
+    OnDownloadProgress onProgress,
+    CancelToken cancelToken,
+    data,
+    Options options,
+  }) {
+    return _dio.download(urlPath, savePath,
+        onProgress: onProgress,
+        cancelToken: cancelToken,
+        data: data,
+        options: options);
+  }
+
+  /// decode response data.
+  Map<String, dynamic> _decodeData(Response response) {
+    if (response == null ||
+        response.data == null ||
+        response.data.toString().isEmpty) {
+      return new Map();
+    }
+    return json.decode(response.data.toString());
+  }
+
+  /// check Options.
+  Options _checkOptions(method, options) {
+    if (options == null) {
+      options = new Options();
+    }
+    options.method = method;
+    return options;
+  }
+
+  /// merge Option.
+  void _mergeOption(Options opt) {
+    _options.method = opt.method ?? _options.method;
+    _options.headers = (new Map.from(_options.headers))..addAll(opt.headers);
+    _options.baseUrl = opt.baseUrl ?? _options.baseUrl;
+    _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout;
+    _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout;
+    _options.responseType = opt.responseType ?? _options.responseType;
+    _options.data = opt.data ?? _options.data;
+    _options.extra = (new Map.from(_options.extra))..addAll(opt.extra);
+    _options.contentType = opt.contentType ?? _options.contentType;
+    _options.validateStatus = opt.validateStatus ?? _options.validateStatus;
+    _options.followRedirects = opt.followRedirects ?? _options.followRedirects;
+  }
+
+  /// print Http Log.
+  void _printHttpLog(Response response) {
+    if (!_isDebug) {
+      return;
+    }
+    try {
+      print("----------------Http Log----------------" +
+          "\n[statusCode]:   " +
+          response.statusCode.toString() +
+          "\n[request   ]:   " +
+          _getOptionsStr(response.request));
+      _printDataStr("reqdata ", response.request.data);
+      _printDataStr("response", response.data);
+    } catch (ex) {
+      print("Http Log" + " error......");
+    }
+  }
+
+  /// get Options Str.
+  String _getOptionsStr(Options request) {
+    return "method: " +
+        request.method +
+        "  baseUrl: " +
+        request.baseUrl +
+        "  path: " +
+        request.path;
+  }
+
+  /// print Data Str.
+  void _printDataStr(String tag, Object value) {
+    String da = value.toString();
+    while (da.isNotEmpty) {
+      if (da.length > 512) {
+        print("[$tag  ]:   " + da.substring(0, 512));
+        da = da.substring(512, da.length);
+      } else {
+        print("[$tag  ]:   " + da);
+        da = "";
+      }
+    }
+  }
+
+  /// get dio.
+  Dio getDio() {
+    return _dio;
+  }
+
+  /// create new dio.
+  static Dio createNewDio([Options options]) {
+    options = options ?? getDefOptions();
+    Dio dio = new Dio(options);
+    return dio;
+  }
+
+  /// get Def Options.
+  static Options getDefOptions() {
+    Options options = new Options();
+    options.contentType =
+        ContentType.parse("application/x-www-form-urlencoded");
+    options.connectTimeout = 1000 * 10;
+    options.receiveTimeout = 1000 * 20;
+    return options;
+  }
+}

+ 2 - 1
lib/src/screen_util.dart

@@ -4,6 +4,7 @@ import 'dart:ui' as ui show window;
 /**
  * @Author: thl
  * @GitHub: https://github.com/Sky24n
+ * @JianShu: https://www.jianshu.com/u/cbf2ad25d33a
  * @Email: 863764940@qq.com
  * @Description: Screen Util.
  * @Date: 2018/9/8
@@ -26,7 +27,7 @@ void setDesignWHD(double w, double h, {double density: 3.0}) {
   _designD = density;
 }
 
-///
+/// Screen Util.
 class ScreenUtil {
   double _screenWidth;
   double _screenHeight;

+ 1 - 0
lib/src/sp_util.dart

@@ -6,6 +6,7 @@ import 'package:synchronized/synchronized.dart';
 /**
  * @Author: thl
  * @GitHub: https://github.com/Sky24n
+ * @JianShu: https://www.jianshu.com/u/cbf2ad25d33a
  * @Email: 863764940@qq.com
  * @Description: Sp Util.
  * @Date: 2018/9/8

+ 14 - 4
lib/src/widget_util.dart

@@ -3,22 +3,23 @@ import 'package:flutter/widgets.dart';
 /**
  * @Author: thl
  * @GitHub: https://github.com/Sky24n
+ * @JianShu: https://www.jianshu.com/u/cbf2ad25d33a
  * @Email: 863764940@qq.com
  * @Description: Widget Util.
  * @Date: 2018/9/10
  */
 
-///
+/// Widget Util.
 class WidgetUtil {
   bool _hasMeasured = false;
   double _width;
   double _height;
 
   /// Widget rendering listener.
-  /// Widget渲染监听
-  /// context: Widget context
+  /// Widget渲染监听.
+  /// context: Widget context.
   /// isOnce: true,Continuous monitoring  false,Listen only once.
-  /// onCallBack: Widget Rect CallBack
+  /// onCallBack: Widget Rect CallBack.
   void asyncPrepare(
       BuildContext context, bool isOnce, ValueChanged<Rect> onCallBack) {
     if (_hasMeasured) return;
@@ -37,6 +38,15 @@ class WidgetUtil {
     });
   }
 
+  /// Widget渲染监听.
+  void asyncPrepares(bool isOnce, ValueChanged<Rect> onCallBack) {
+    if (_hasMeasured) return;
+    WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) {
+      if (isOnce) _hasMeasured = true;
+      if (onCallBack != null) onCallBack(null);
+    });
+  }
+
   ///get Widget Bounds (width, height, left, top, right, bottom and so on).Widgets must be rendered completely.
   ///获取widget Rect
   static Rect getWidgetBounds(BuildContext context) {

+ 6 - 2
pubspec.yaml

@@ -1,6 +1,6 @@
 name: flustars
-description: Flutter common utils library. SpUtil, ScreenUtil, WidgetUtil.
-version: 0.1.5
+description: Flutter common utils library. DioUtil, SpUtil, ScreenUtil, WidgetUtil.
+version: 0.1.6
 author: thl <863764940@qq.com>
 homepage: https://github.com/Sky24n/flustars
 
@@ -11,8 +11,12 @@ dependencies:
   flutter:
     sdk: flutter
 
+  # https://github.com/tekartik/synchronized.dart
   synchronized: ^1.5.3
+  # https://github.com/flutter/plugins/tree/master/packages/shared_preferences
   shared_preferences: ^0.4.3
+  # https://github.com/flutterchina/dio
+  dio: ^1.0.11
 
 
 # For information on the generic Dart part of this file, see the