|
- import 'dart:collection';
- import 'dart:convert';
- import 'dart:io';
- import 'dart:ui';
-
- import 'package:device_info/device_info.dart';
- import 'package:dio/adapter.dart';
- import 'package:dio/dio.dart';
- import 'package:flutter/material.dart';
- import 'package:fluttertoast/fluttertoast.dart';
- import 'package:imei_plugin/imei_plugin.dart';
- import 'package:package_info/package_info.dart';
- import 'package:zhiying_comm/util/empty_util.dart';
- import 'package:zhiying_comm/zhiying_comm.dart';
-
- import 'encode_util.dart';
- import 'global_config.dart';
- import 'shared_prefe_util.dart';
- import 'time_util.dart';
-
- import 'package:provider/provider.dart';
-
- typedef OnSuccess = dynamic Function(dynamic data);
- typedef OnError = dynamic Function(String e);
- typedef OnCache = dynamic Function(dynamic data);
-
- final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
-
- enum NetMethod {
- GET,
- POST,
- PUT,
- DELETE,
- OPTIONS,
- PATCH,
- UPDATE,
- HEAD,
- }
-
- class NetUtil {
- Dio _dio;
-
- 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/';
- _config(domain, proxyUrl: '192.168.0.66:8866');
- }
- return _dio;
- }
-
- /// 配置网络请求,基础地址,代理地址,如:192.168.0.123:8888(代理地址生产环境无效)
- /// apiVersion 接口版本
- void _config(String baseUrl, {String proxyUrl}) {
- _dio = Dio(BaseOptions(
- method: "post",
- baseUrl: baseUrl,
- connectTimeout: 15000,
- receiveTimeout: 15000,
- contentType: Headers.jsonContentType,
- followRedirects: true,
- headers: {'device': 'wx_applet', 'Platform': 'wx_applet'},
- validateStatus: (_) {
- return true;
- }));
- _dio.interceptors.add(_NetInterceptors());
- // _dio.interceptors.add(LogInterceptor());
-
- 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<dynamic> post(String path, {Map<String, dynamic> params, Map<String, dynamic> queryParameters, NetMethod method = NetMethod.POST, bool cache = false, bool showToast = true}) async {
- if (params == null) {
- params = {};
- }
- // 根据请求参数,获取缓存的Key
- String cacheKey = getRequestParamsCachedKey(params, path);
- // 参数签名 TODO 加密?
- // post请求的参数
- Map<String, dynamic> bodyParams = params;
- // 请求头参数
- Map<String, dynamic> headParam = await _getMustHeadParams();
-
- Response response;
- try {
- Dio dio = await NetUtil.getInstance().dio;
- response = await dio.request(
- path,
- data: !EmptyUtil.isEmpty(bodyParams) ? bodyParams : null,
- options: Options(method: enumToString(method), headers: headParam),
- queryParameters: !EmptyUtil.isEmpty(queryParameters) ? queryParameters : null,
- );
- } on DioError catch (e) {
- _formatError(e);
- }
-
- try {
- var result = response.data is Map ? response.data : jsonDecode(response.data);
- // TODO 解密?
- if (isSuccess(result)) {
- // 缓存成功的数据
- if (cache) {
- _setCallBackCacheData(cacheKey, response.data is Map ? jsonEncode(response.data) : response.data);
- }
- return result;
- // 缓存返回的数据
- } else {
- Logger.error('error: ' + result[GlobalConfig.HTTP_RESPONSE_KEY_MSG]);
- ///
- /// 401000 验证用户失败(不提示Toast)
- /// 404004 没有找到对应模块(跳空页面,不提示toast)
- ///
- if (result[GlobalConfig.HTTP_RESPONSE_KEY_CODE] != 401000 && result[GlobalConfig.HTTP_RESPONSE_KEY_CODE] != 404004) {
- if(showToast) {
- Fluttertoast.showToast(
- msg: result[GlobalConfig.HTTP_RESPONSE_KEY_MSG],
- toastLength: Toast.LENGTH_SHORT,
- gravity: ToastGravity.BOTTOM,
- );
- }
- }
-
- // 退出登陆
- if (result[GlobalConfig.HTTP_RESPONSE_KEY_CODE]?.toString() == '401003') {
- try {
- Future.delayed(Duration(seconds: 0)).then((onValue) {
- BuildContext context = navigatorKey.currentState.overlay.context;
- Provider.of<UserInfoNotifier>(context, listen: false).unLogin();
- });
- } catch (e, s) {
- Logger.error(e, s);
- }
- }
-
- return result;
- }
- } catch (e) {
- return null;
- }
- }
-
- /// 异步请求
- static void request(String path, {NetMethod method = NetMethod.GET, Map<String, dynamic> params,Map<String, dynamic> queryParameters, OnSuccess onSuccess, OnError onError, OnCache onCache, bool showToast = true}) async {
- if (params == null) {
- params = {};
- }
-
- // 根据请求参数,获取缓存的Key
- String cacheKey = getRequestParamsCachedKey(params, path);
- // // 读取缓存回调
- if (onCache != null) {
- await _onCallBackCacheData(onCache, cacheKey);
- }
-
- try {
- Map result = await NetUtil.post(path, method: method, params: params, queryParameters: queryParameters, showToast: showToast);
- // TODO 解密?
- if (isSuccess(result)) {
- if (onSuccess != null) {
- onSuccess(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]);
- }
- return;
- }
-
- if (onError != null) {
- onError(!EmptyUtil.isEmpty(result) ? !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_MSG]) ? result[GlobalConfig.HTTP_RESPONSE_KEY_MSG] : '未知错误' : '未知错误');
- }
- } catch (e) {
- Logger.error('error: ' + e.toString());
- if (onError != null) {
- onError(e?.toString() ?? '未知错误');
- }
- }
-
- return;
- }
-
- /// 统一添加必要的参数
- // static Future<Map<String, dynamic>> signParams(Map<String, dynamic> params) async {
- // // 应用信息
- // PackageInfo packageInfo = await PackageInfo.fromPlatform();
- // // 原生传的信息
- // Map setting = await NativeUtil.getSetting();
- //
- // if (Platform.isIOS) {
- // IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo;
- // // 设备
- // params["platform"] = "ios";
- // // 设备系统版本
- // params["system_version"] = iosInfo?.systemVersion;
- // // 设备型号 如:iPhone 11pro
- // params['device_model'] = iosInfo?.name;
- // // 设备型号,如:MLMF2LL/A
- // // params['device_number'] = iosInfo?.model;
- // // 设备ID
- // params['device_id'] = iosInfo?.identifierForVendor;
- // } else if (Platform.isAndroid) {
- // AndroidDeviceInfo androidInfo = await DeviceInfoPlugin().androidInfo;
- // // 设备
- // params["platform"] = "android";
- // // 设备系统版本
- // params["system_version"] = "Android ${androidInfo?.version?.release}";
- // // 设备型号 如:iPhone 11pro
- // params['device_model'] = androidInfo?.model;
- // // 设备型号,如:MLMF2LL/A
- // // params['device_number'] = androidInfo?.id;
- // // 设备Id
- // params['device_id'] = androidInfo?.androidId;
- // }
- // // 应用版本号
- // params["app_version_name"] = packageInfo.version;
- // params["app_version"] = -1 ;// packageInfo.buildNumber;
- // // 分辨率
- // params["solution"] =
- // "${window.physicalSize.width.floor()}*${window.physicalSize.height.floor()}";
- //
- // // 站长ID
- // String masterId = setting['master_id'];
- // if (null != masterId &&
- // masterId != '' &&
- // (!params.containsKey('master_id') || params['master_id'] == '')) {
- // params['master_id'] = masterId;
- // }
- //
- // // secret_key
- // params['secret_key'] = setting['secret_key'];
- //
- // // token 读取SP缓存中的用户token
- // String token = await SharedPreferencesUtil.getStringValue(
- // GlobalConfig.SHARED_KEY_TOKEN);
- // if (!EmptyUtil.isEmpty(token)) {
- // params['token'] = token;
- // }
- //
- // // 当前时间戳:秒
- // params["time"] = TimeUtil.getNowTime();
- //
- // // 过滤空字段,过滤首尾空格
- // Map<String, dynamic> filters = Map<String, dynamic>();
- // params.forEach((key, value) {
- // if (key != '' && value != '') {
- // filters[key] = (value is String) ? value.trim() : value;
- // }
- // });
- // params = filters;
- //
- // List<String> list = List<String>();
- // params.forEach((key, value) {
- // list.add(key.toString() + value.toString());
- // });
- // params["sign"] = signWithArray(list);
- // return params;
- // }
-
- /// 获取必须的请求参数(用于请求头部)
- static Future<Map<String, String>> _getMustHeadParams() async {
- Map<String, String> params = new HashMap<String, String>();
- // 应用信息
- PackageInfo packageInfo = await PackageInfo.fromPlatform();
- // 原生传的信息
- Map setting = await NativeUtil.getSetting();
-
- if (Platform.isIOS) {
- IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo;
- // 设备
- params["platform"] = "ios";
- // 设备系统版本
- params["os_version"] = iosInfo?.systemVersion?.toString();
- // 设备型号 如:iPhone 11pro
-
- params['device_model'] =
- EncodeUtil.encodeBase64(iosInfo?.name?.toString() ?? '');
- // 设备ID
- params['device_id'] = iosInfo?.identifierForVendor?.toString();
-
- // idfa
- params['idfa'] = iosInfo?.identifierForVendor?.toString();
- } else if (Platform.isAndroid) {
- AndroidDeviceInfo androidInfo = await DeviceInfoPlugin().androidInfo;
- // 设备
- params["platform"] = "android";
- // 设备系统版本
- params["os_version"] = "Android ${androidInfo?.version?.release}";
- // 设备型号 如:iPhone 11pro
- params['device_model'] = androidInfo?.model?.toString();
- // 设备Id
- params['device_id'] = androidInfo?.androidId?.toString();
-
- // imei
- params['imei'] = await _getImei();
- }
- // 应用版本号
- params["app_version_name"] = packageInfo.version?.toString();
- params["app_version"] = packageInfo.buildNumber?.toString();
- // 分辨率
- params["solution"] = "${window.physicalSize.width.floor()}*${window.physicalSize.height.floor()}";
-
- // 站长ID
- String masterId = setting['master_id'];
- if (null != masterId && masterId != '' && (!params.containsKey('master_id') || params['master_id'] == '')) {
- params['master_id'] = masterId ?? 'template_database';
- }
-
- // token 读取SP缓存中的用户token
- String token = await SharedPreferencesUtil.getStringValue(GlobalConfig.SHARED_KEY_TOKEN);
- if (!EmptyUtil.isEmpty(token)) {
- params['token'] = token;
- }
- // secret_key
- params['secret_key'] = setting['secret_key'] ?? '';
-
- // 当前时间戳:秒
- params["time"] = TimeUtil.getNowTime();
-
- // 过滤空字段,过滤首尾空格
- Map<String, String> filters = Map<String, String>();
- params.forEach((key, value) {
- if (key != '' && value != '') {
- filters[key] = (value is String) ? value.trim() : value;
- }
- });
- params = filters;
-
- List<String> list = List<String>();
- params.forEach((key, value) {
- list.add(key.toString() + '=' + value.toString() + '&');
- });
-
- params["sign"] = signWithArray(list);
- params.remove('secret_key');
- return params;
- }
-
- /// 获取Android imei
- static Future<String> _getImei() async {
- try {
- return await ImeiPlugin.getImei(shouldShowRequestPermissionRationale: true);
- } catch (e, s) {
- Logger.error(e, s);
- }
- return null;
- }
-
- /// 获取请求缓存成功的数据
- static Future<void> _onCallBackCacheData(OnCache onCache, String cacheKey) async {
- // 读取缓存
- Map<String, dynamic> cacheMap = await SharedPreferencesUtil.getNetCacheResult(cacheKey);
-
- if (!EmptyUtil.isEmpty(cacheMap) &&
- cacheMap.containsKey(GlobalConfig.HTTP_RESPONSE_KEY_CODE) &&
- (cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == GlobalConfig.RESPONSE_SUCCESS_CODE ||
- cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == '${GlobalConfig.RESPONSE_SUCCESS_CODE}') &&
- !EmptyUtil.isEmpty(cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {
- onCache(cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_DATA]);
- return;
- }
- return;
- }
-
- /// 缓存请求成功的数据
- static void _setCallBackCacheData(String cacheKey, String value) async {
- SharedPreferencesUtil.setNetCacheResult(cacheKey, value);
- }
-
- /// 根据请求参数,获取缓存的数据
- static Future<dynamic> getRequestCachedData(String url, {Map<String, dynamic> params}) async {
- Map<String, dynamic> cacheMap = await SharedPreferencesUtil.getNetCacheResult(getRequestParamsCachedKey(params, url));
- if (!EmptyUtil.isEmpty(cacheMap) &&
- cacheMap.containsKey(GlobalConfig.HTTP_RESPONSE_KEY_CODE) &&
- (cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == GlobalConfig.RESPONSE_SUCCESS_CODE ||
- cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == '${GlobalConfig.RESPONSE_SUCCESS_CODE}') &&
- !EmptyUtil.isEmpty(cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {
- return cacheMap[GlobalConfig.HTTP_RESPONSE_KEY_DATA];
- }
- return null;
- }
-
- /// 判断后台返回是否成功
- static bool isSuccess(Map<String, dynamic> data) {
- try {
- if (!EmptyUtil.isEmpty(data) &&
- (data[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == GlobalConfig.RESPONSE_SUCCESS_CODE ||
- data[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == '${GlobalConfig.RESPONSE_SUCCESS_CODE}')) {
- return true;
- }
- } catch (e) {
- return false;
- }
- return false;
- }
-
- /// 根据请求参数,获取缓存的Key
- static String getRequestParamsCachedKey(Map<String, dynamic> map, String path) {
- if (EmptyUtil.isEmpty(map)) {
- return EncodeUtil.generateMd5(path);
- }
- return EncodeUtil.generateMd5(path + map.toString());
- }
-
- // 七牛云文件上传
- static Future uploadFile(String url, File file, {String method = 'POST', Map<String, dynamic> params, OnSuccess onSuccess, OnError onError}) async {
- if (params == null) {
- params = {};
- }
- Dio dio = Dio(BaseOptions(
- method: "post",
- connectTimeout: 15000,
- receiveTimeout: 15000,
- contentType: Headers.jsonContentType,
- followRedirects: true,
- ));
-
- params['file'] = await MultipartFile.fromFile(file.path);
- FormData format = FormData.fromMap(params);
- return dio.request(url, data: format, options: Options(method: method));
- }
-
- /// 签名
- static String signWithArray(List<String> params) {
- // 字母升序
- params.sort();
- String result = "";
- params.forEach((param) {
- result += param;
- });
- result = result.substring(0, result.length - 1);
- return EncodeUtil.generateMd5(result);
- }
-
- /*
- * error统一处理
- */
- static void _formatError(DioError e) {
- if (e.type == DioErrorType.CONNECT_TIMEOUT) {
- Logger.error('连接超时: ${e.toString()}');
- } else if (e.type == DioErrorType.SEND_TIMEOUT) {
- Logger.error('请求超时: ${e.toString()}');
- } else if (e.type == DioErrorType.RECEIVE_TIMEOUT) {
- Logger.error('响应超时: ${e.toString()}');
- } else if (e.type == DioErrorType.RESPONSE) {
- Logger.error('出现异常: ${e.toString()}');
- } else if (e.type == DioErrorType.CANCEL) {
- Logger.error('请求取消: ${e.toString()}');
- } else {
- Logger.error('未知错误: ${e.toString()}');
- }
- }
- }
-
- /**
- * @description: 网络请求拦截器
- * @param {type}
- * @return:
- */
- class _NetInterceptors extends InterceptorsWrapper {
- @override
- Future onRequest(RequestOptions options) {
- Logger.net(options?.uri?.toString(), data: options.data.toString());
- // TODO 加密?
- return super.onRequest(options);
- }
-
- @override
- Future onResponse(Response response) {
- Logger.endNet(response?.request?.uri?.toString(), data: response?.data?.toString() ?? '');
- // TODO 解密?
- return super.onResponse(response);
- }
-
- @override
- Future onError(DioError err) {
- // Logger.error(err);
- return super.onError(err);
- }
- }
|