import 'package:dio/dio.dart'; import 'package:dio/adapter.dart'; import 'dart:io'; import 'dart:ui'; import 'dart:convert'; import 'package:convert/convert.dart'; import 'package:crypto/crypto.dart'; import 'package:zhiying_comm/zhiying_comm.dart'; import 'package:package_info/package_info.dart'; import 'package:device_info/device_info.dart'; import 'package:fluttertoast/fluttertoast.dart'; typedef OnSuccess = dynamic Function(dynamic data); typedef OnError = dynamic Function(String e); class NetUtil { static final String APPKEY = "123"; Dio _dio; static String _apiVersion; NetUtil._() {} static NetUtil _instance; static NetUtil getInstance() { if (_instance == null) { _instance = NetUtil._(); } return _instance; } get dio async { if (_dio == null) { var setting = await NativeUtil.getSetting(); String domain = setting['domain']; //'http://www.hairuyi.com/'; String version = setting['version']; //'42'; _config(domain, apiVersion: _apiVersion); } return _dio; } // 配置网络请求,基础地址,代理地址,如:192.168.0.123:8888(代理地址生产环境无效) // apiVersion 接口版本 void _config(String baseUrl, {String proxyUrl, String apiVersion}) { _dio = Dio(BaseOptions( method: "post", baseUrl: baseUrl, connectTimeout: 15000, receiveTimeout: 15000, contentType: Headers.formUrlEncodedContentType, followRedirects: true)); _dio.interceptors.add(_NetInterceptors()); _apiVersion = apiVersion; const bool inProduction = const bool.fromEnvironment("dart.vm.product"); if (proxyUrl != null && proxyUrl != '' && !inProduction) { _setProxy(proxyUrl); } } void _setProxy(String proxyUrl) { (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) { client.findProxy = (uri) { return "PROXY $proxyUrl"; }; client.badCertificateCallback = (X509Certificate cert, String host, int port) => true; }; } /// 统一添加必要的参数 static Future> signParams( Map params) async { if (_apiVersion != null) { params["version"] = _apiVersion; } if (Platform.isIOS) { params["platform"] = "iOS"; DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); IosDeviceInfo iosInfo = await deviceInfo.iosInfo; params["systemVersion"] = iosInfo.systemVersion; } else if (Platform.isAndroid) { params["platform"] = "Android"; DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; String androidVersion = androidInfo.version.release; params["systemVersion"] = "Android $androidVersion"; } PackageInfo packageInfo = await PackageInfo.fromPlatform(); String version = packageInfo.version; //版本号 params["appVersion"] = version; int width = window.physicalSize.width.floor(); int height = window.physicalSize.height.floor(); params["resolutionRatio"] = "$width*$height"; String token = await NativeUtil.getToken(); if (token != null && token != '' && (!params.containsKey('token') || params['token'] == '')) { params['token'] = token; } params["time"] = getNowTime(); // 过滤空字段,过滤首尾空格 Map filters = Map(); params.forEach((key, value) { if (key != '' && value != '') { filters[key] = (value is String) ? value.trim() : value; } }); params = filters; List list = List(); params.forEach((key, value) { list.add(key.toString() + value.toString()); }); params["sign"] = signWithArray(list); return params; } /// 签名 static String signWithArray(List params) { params.sort(); String result = ""; result += APPKEY; params.forEach((param) { result += param; }); result += APPKEY; return generateMd5(result); } // md5 加密 static String generateMd5(String data) { var content = new Utf8Encoder().convert(data); var digest = md5.convert(content); // 这里其实就是 digest.toString() return hex.encode(digest.bytes); } /// 获取时间戳,单位:秒 static String getNowTime() { int timestamp = (DateTime.now().millisecondsSinceEpoch / 1000).floor(); return "$timestamp"; } @Deprecated('方法弃用,建议使用 NetUtil.requet') static Future post(String path, {Map params}) async { if (params == null) { params = {}; } Map sign = await signParams(params); Response response; try { Dio dio = await NetUtil.getInstance().dio; response = await dio.post(path, data: sign); } on DioError catch (e) { _formatError(e); } if (response == null) { return {}; } if (response.statusCode != 200) { const bool inProduction = const bool.fromEnvironment("dart.vm.product"); if (!inProduction) { Fluttertoast.showToast(msg: response.statusMessage); } // log.e(response.statusMessage); return {}; } var result = jsonDecode(response.data); if (result['success'] == 0 || result['success'] == '0') { print('error: ' + result['msg']); Fluttertoast.showToast( msg: result['msg'], toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, ); return {}; } return result['data']; } static Future post2(String path, {Map params}) async { // if (params == null) { // params = {}; // } // Map sign = await signParams(params); // Response response; // try { // Dio dio = await NetUtil.getInstance().dio; // response = await dio.post(path, data: sign); // } on DioError catch (e) { // _formatError(e); // } // if (response == null) { // return {}; // } // if (response.statusCode != 200) { // const bool inProduction = const bool.fromEnvironment("dart.vm.product"); // if (!inProduction) { // Fluttertoast.showToast(msg: response.statusMessage); // } // log.e(response.statusMessage); // return {}; // } // var result = jsonDecode(response.data); // if (result['success'] == 0 || result['success'] == '0') { // print('error: ' + result['msg']); // Fluttertoast.showToast( // msg: result['msg'], // toastLength: Toast.LENGTH_SHORT, // gravity: ToastGravity.BOTTOM, // ); // return result; // } // return result['data']; } /* * error统一处理 */ static void _formatError(DioError e) { // if (e.type == DioErrorType.CONNECT_TIMEOUT) { // log.d('连接超时: ${e.toString()}'); // } else if (e.type == DioErrorType.SEND_TIMEOUT) { // log.d('请求超时: ${e.toString()}'); // } else if (e.type == DioErrorType.RECEIVE_TIMEOUT) { // log.d('响应超时: ${e.toString()}'); // } else if (e.type == DioErrorType.RESPONSE) { // log.d('出现异常: ${e.toString()}'); // } else if (e.type == DioErrorType.CANCEL) { // log.d('请求取消: ${e.toString()}'); // } else { // log.d('未知错误: ${e.toString()}'); // } } static void request(String path, {String method = 'POST', Map params, Map multiFiles, OnSuccess onSuccess, OnError onError}) async { if (params == null) { params = {}; } signParams(params).then((sign) async { print('params => ${sign.toString()}'); Dio dio = await NetUtil.getInstance().dio; if (multiFiles != null && multiFiles.length > 0) { for (String key in multiFiles.keys) { var file = await MultipartFile.fromFile(multiFiles[key].path); sign[key] = file; } } FormData formdata = FormData.fromMap(sign); return dio.request(path, data: formdata, options: Options(method: method)); }).then((response) { var result = jsonDecode(response.data); if (result['success'] == 0 || result['success'] == '0') { print('error: ' + result['msg']); Fluttertoast.showToast( msg: result['msg'], toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, ); if (onError != null) { onError(result['msg'] ?? '未知错误'); } return; } if (onSuccess != null) { onSuccess(result['data']); } }).catchError((error) { onError(error.toString()); }); } } /** * @description: 网络请求拦截器 * @param {type} * @return: */ class _NetInterceptors extends InterceptorsWrapper { @override Future onRequest(RequestOptions options) { print("${options?.method} => ${options?.path}"); return super.onRequest(options); } @override Future onResponse(Response response) { print("response[${response?.statusCode}] => ${response?.data}"); return super.onResponse(response); // String data = response?.data; // Map map = json.decode(data); // var success = map['success']; // if (success != null && '$success' == '1') { // return super.onResponse(response); // } else { // response.data = response?.data['msg'] ?? '未知错误'; // return NetUtil._dio.reject(Response(data: response)); // } } @override Future onError(DioError err) { print("ERROR[${err?.response?.statusCode}] => PATH: ${err?.request?.path}"); return super.onError(err); } }