From d17a6a5037fbe0237ea7b23151a8bd5069ae9553 Mon Sep 17 00:00:00 2001 From: PH2 <1293456824@qq.com> Date: Tue, 10 Nov 2020 14:06:08 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E7=BD=91=E7=BB=9C=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E7=9A=84=E5=A4=B4=E9=83=A8=E7=BB=9F=E4=B8=80=E5=8F=82=E6=95=B0?= =?UTF-8?q?=202=E3=80=81=E6=B7=98=E5=AE=9D=E6=8E=88=E6=9D=83=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=203=E3=80=81app=E6=9B=B4=E6=96=B0=E7=9A=84=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/user/user_info_model.dart | 4 +- lib/models/user/user_info_model_notifier.dart | 20 +- lib/util/net_util.dart | 217 +++++++++------- lib/util/taobao/taobao_auth.dart | 53 ++-- lib/util/update/app_update_model.dart | 26 ++ lib/util/update/app_update_util.dart | 239 ++++++++++-------- pubspec.yaml | 5 +- 7 files changed, 345 insertions(+), 219 deletions(-) diff --git a/lib/models/user/user_info_model.dart b/lib/models/user/user_info_model.dart index 2c28e09..60b4414 100644 --- a/lib/models/user/user_info_model.dart +++ b/lib/models/user/user_info_model.dart @@ -10,12 +10,12 @@ class UserInfoModel { String username; List perms; String registerInviteCodeEnable; - bool isTBAuth; + bool isTBAuth; // 是否淘宝授权 // 获取模糊手机号码 get blurMobile => !EmptyUtil.isEmpty(mobile) ? mobile.length == 11 ? '${mobile.substring(0, 3)}****${mobile.substring(7, mobile.length)}' : mobile : mobile; - UserInfoModel({this.token, this.userId, this.username, this.perms, this.registerInviteCodeEnable}); + UserInfoModel({this.token, this.userId, this.username, this.perms, this.registerInviteCodeEnable, this.isTBAuth = false}); UserInfoModel.fromJson(Map json) { token = json['token']; diff --git a/lib/models/user/user_info_model_notifier.dart b/lib/models/user/user_info_model_notifier.dart index 9fb5b46..fd8b799 100644 --- a/lib/models/user/user_info_model_notifier.dart +++ b/lib/models/user/user_info_model_notifier.dart @@ -28,15 +28,25 @@ class UserInfoNotifier with ChangeNotifier { } return _userInfo; } - + /// 更新淘宝授权 - void updateUserAuth(bool isAuth){ - if(_userInfo != null){ + void updateUserAuth(bool isAuth) { + if (null == _userInfo) { + getUserInfoModel().then((user) { + if (user != null) { + _userInfo = user; + _userInfo.isTBAuth = isAuth; + Logger.log('upate data TBAuth'); + notifyListeners(); + } + }); + } else { _userInfo.isTBAuth = isAuth; + Logger.log('upate data TBAuth'); notifyListeners(); } } - + /// 更新用户数据 void setUserInfo(UserInfoModel loginUser) async { print('${loginUser.toString()}'); @@ -73,7 +83,7 @@ class UserInfoNotifier with ChangeNotifier { String userInfoJson = await SharedPreferencesUtil.getStringValue( GlobalConfig.SHARED_KEY_USER_INFO); if (userInfoJson == null || userInfoJson == '') { - _userInfo = UserInfoModel(); + _userInfo = UserInfoModel(); } else { _userInfo = UserInfoModel.fromJson(jsonDecode(userInfoJson)); } diff --git a/lib/util/net_util.dart b/lib/util/net_util.dart index 4969129..362c76c 100644 --- a/lib/util/net_util.dart +++ b/lib/util/net_util.dart @@ -1,3 +1,4 @@ +import 'dart:collection'; import 'dart:convert'; import 'dart:io'; import 'dart:ui'; @@ -77,53 +78,46 @@ class NetUtil { /// 设置代理 void _setProxy(String proxyUrl) { - (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = - (HttpClient client) { + (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) { client.findProxy = (uri) { return "PROXY $proxyUrl"; }; - client.badCertificateCallback = - (X509Certificate cert, String host, int port) => true; + client.badCertificateCallback = (X509Certificate cert, String host, int port) => true; }; } /// 同步请求 - static Future post(String path, - {Map params, - NetMethod method = NetMethod.POST, - bool cache = false}) async { + static Future post(String path, {Map params, NetMethod method = NetMethod.POST, bool cache = false}) async { if (params == null) { params = {}; } // 根据请求参数,获取缓存的Key String cacheKey = getRequestParamsCachedKey(params, path); // 参数签名 TODO 加密? - Map sign = await signParams(params); + // post请求的参数 + Map bodyParams = params; + // 请求头参数 + Map headParam = await _getMustHeadParams(); Response response; try { - String token = await SharedPreferencesUtil.getStringValue( - GlobalConfig.SHARED_KEY_TOKEN) ?? - ''; Dio dio = await NetUtil.getInstance().dio; - response = await dio.request(path, - data: sign, - options: Options(method: enumToString(method), headers: {'token': token, 'app_version': sign['app_version']}), - // options: Options(method: enumToString(method), headers: sign), + response = await dio.request( + path, + data: !EmptyUtil.isEmpty(bodyParams) ? bodyParams : null, + options: Options(method: enumToString(method), headers: headParam), ); } on DioError catch (e) { _formatError(e); } try { - var result = - response.data is Map ? response.data : jsonDecode(response.data); + 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); + _setCallBackCacheData(cacheKey, response.data is Map ? jsonEncode(response.data) : response.data); } return result; // 缓存返回的数据 @@ -145,12 +139,7 @@ class NetUtil { } /// 异步请求 - static void request(String path, - {NetMethod method = NetMethod.GET, - Map params, - OnSuccess onSuccess, - OnError onError, - OnCache onCache}) async { + static void request(String path, {NetMethod method = NetMethod.GET, Map params, OnSuccess onSuccess, OnError onError, OnCache onCache}) async { if (params == null) { params = {}; } @@ -173,11 +162,7 @@ class NetUtil { } if (onError != null) { - onError(!EmptyUtil.isEmpty(result) - ? !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_MSG]) - ? result[GlobalConfig.HTTP_RESPONSE_KEY_MSG] - : '未知错误' - : '未知错误'); + 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()); @@ -190,8 +175,85 @@ class NetUtil { } /// 统一添加必要的参数 - static Future> signParams( - Map params) async { + // static Future> signParams(Map 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 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 Future> _getMustHeadParams() async { + Map params = new HashMap(); // 应用信息 PackageInfo packageInfo = await PackageInfo.fromPlatform(); // 原生传的信息 @@ -202,56 +264,47 @@ class NetUtil { // 设备 params["platform"] = "ios"; // 设备系统版本 - params["system_version"] = iosInfo?.systemVersion; + params["os_version"] = iosInfo?.systemVersion?.toString(); // 设备型号 如:iPhone 11pro - params['device_model'] = iosInfo?.name; - // 设备型号,如:MLMF2LL/A - // params['device_number'] = iosInfo?.model; + params['device_model'] = iosInfo?.name?.toString(); // 设备ID - params['device_id'] = iosInfo?.identifierForVendor; + params['device_id'] = iosInfo?.identifierForVendor?.toString(); } else if (Platform.isAndroid) { AndroidDeviceInfo androidInfo = await DeviceInfoPlugin().androidInfo; // 设备 params["platform"] = "android"; // 设备系统版本 - params["system_version"] = "Android ${androidInfo?.version?.release}"; + params["os_version"] = "Android ${androidInfo?.version?.release}"; // 设备型号 如:iPhone 11pro - params['device_model'] = androidInfo?.model; - // 设备型号,如:MLMF2LL/A - // params['device_number'] = androidInfo?.id; + params['device_model'] = androidInfo?.model?.toString(); // 设备Id - params['device_id'] = androidInfo?.androidId; + params['device_id'] = androidInfo?.androidId?.toString(); } // 应用版本号 - params["app_version_name"] = packageInfo.version; - params["app_version"] = packageInfo.buildNumber; + params["app_version_name"] = packageInfo.version?.toString(); + params["app_version"] = packageInfo.buildNumber?.toString(); // 分辨率 - params["solution"] = - "${window.physicalSize.width.floor()}*${window.physicalSize.height.floor()}"; + 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; + if (null != masterId && masterId != '' && (!params.containsKey('master_id') || params['master_id'] == '')) { + params['master_id'] = masterId ?? 'template_database'; } - // secret_key - params['secret_key'] = setting['secret_key']; - // token 读取SP缓存中的用户token - String token = await SharedPreferencesUtil.getStringValue( - GlobalConfig.SHARED_KEY_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 filters = Map(); + Map filters = Map(); params.forEach((key, value) { if (key != '' && value != '') { filters[key] = (value is String) ? value.trim() : value; @@ -261,25 +314,23 @@ class NetUtil { List list = List(); params.forEach((key, value) { - list.add(key.toString() + value.toString()); + list.add(key.toString() + '=' + value.toString() + '&'); }); + params["sign"] = signWithArray(list); + params.remove('secret_key'); return params; } /// 获取请求缓存成功的数据 - static Future _onCallBackCacheData( - OnCache onCache, String cacheKey) async { + static Future _onCallBackCacheData(OnCache onCache, String cacheKey) async { // 读取缓存 - Map cacheMap = - await SharedPreferencesUtil.getNetCacheResult(cacheKey); + Map 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}') && + (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; @@ -293,17 +344,12 @@ class NetUtil { } /// 根据请求参数,获取缓存的数据 - static Future getRequestCachedData(String url, - {Map params}) async { - Map cacheMap = - await SharedPreferencesUtil.getNetCacheResult( - getRequestParamsCachedKey(params, url)); + static Future getRequestCachedData(String url, {Map params}) async { + Map 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}') && + (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]; } @@ -314,10 +360,8 @@ class NetUtil { static bool isSuccess(Map 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}')) { + (data[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == GlobalConfig.RESPONSE_SUCCESS_CODE || + data[GlobalConfig.HTTP_RESPONSE_KEY_CODE] == '${GlobalConfig.RESPONSE_SUCCESS_CODE}')) { return true; } } catch (e) { @@ -327,8 +371,7 @@ class NetUtil { } /// 根据请求参数,获取缓存的Key - static String getRequestParamsCachedKey( - Map map, String path) { + static String getRequestParamsCachedKey(Map map, String path) { if (EmptyUtil.isEmpty(map)) { return EncodeUtil.generateMd5(path); } @@ -336,11 +379,7 @@ class NetUtil { } // 七牛云文件上传 - static Future uploadFile(String url, File file, - {String method = 'POST', - Map params, - OnSuccess onSuccess, - OnError onError}) async { + static Future uploadFile(String url, File file, {String method = 'POST', Map params, OnSuccess onSuccess, OnError onError}) async { if (params == null) { params = {}; } @@ -362,11 +401,10 @@ class NetUtil { // 字母升序 params.sort(); String result = ""; -// result += secret_key; params.forEach((param) { result += param; }); -// result += secret_key; + result = result.substring(0, result.length - 1); return EncodeUtil.generateMd5(result); } @@ -405,8 +443,7 @@ class _NetInterceptors extends InterceptorsWrapper { @override Future onResponse(Response response) { - Logger.endNet(response?.request?.uri?.toString(), - data: response?.data?.toString() ?? ''); + Logger.endNet(response?.request?.uri?.toString(), data: response?.data?.toString() ?? ''); // TODO 解密? return super.onResponse(response); } diff --git a/lib/util/taobao/taobao_auth.dart b/lib/util/taobao/taobao_auth.dart index 0bfef60..e27eb97 100644 --- a/lib/util/taobao/taobao_auth.dart +++ b/lib/util/taobao/taobao_auth.dart @@ -10,13 +10,14 @@ import 'package:zhiying_comm/zhiying_comm.dart'; import 'package:provider/provider.dart'; class TaobaoAuth { - static ProfileModel _profile; + // static ProfileModel _profile; // 淘宝授权 static auth(BuildContext context) async { bool isAuth = await TaobaoAuth.isAuth(); if (isAuth) { Fluttertoast.showToast(msg: '你已经授权过了'); + Provider.of(context, listen: false).updateUserAuth(true); return; } @@ -26,8 +27,7 @@ class TaobaoAuth { return TaobaoAuthAlert(); }); if (isConfirm != null && isConfirm == true) { - Map data = Map.from( - await NetUtil.post('/api/v1/taobao/auth', method: NetMethod.GET)); + Map data = Map.from(await NetUtil.post('/api/v1/taobao/auth', method: NetMethod.GET)); Logger.debug(data); if (data['code'] != 1) { return; @@ -36,20 +36,15 @@ class TaobaoAuth { print("授权链接" + url); TradeResult result; if (Platform.isAndroid) { - result = await FlutterAlibc.openByUrl( - url: url, backUrl: "alisdk://", isAuth: true); - // TradeResult result = await FlutterAlibc.openByUrl(url: ''); - Logger.debug('${result.errorCode} ${result.errorMessage} '); + result = await FlutterAlibc.openByUrl(url: url, backUrl: "alisdk://", isAuth: true); } else if (Platform.isIOS) { result = await FlutterAlibc.openByUrl(url: url); - // TradeResult result = await FlutterAlibc.openByUrl(url: ''); - Logger.debug('${result.errorCode} ${result.errorMessage} '); } - - if(null !=result && result.errorCode == '0'){ - Provider.of(context).updateUserAuth(true); - } - + Logger.log('${result.errorCode} ${result.errorMessage} '); + // if(null != result && result.errorCode == '0'){ + // Provider.of(context, listen: false).updateUserAuth(true); + // } + await initAuth(context); } } @@ -58,12 +53,32 @@ class TaobaoAuth { // if (_profile != null) { // return _profile.isAuth; // } - Map data = Map.from( - await NetUtil.post('/api/v1/user/profile', method: NetMethod.GET)); - if (data['code'] == 1) { - _profile = ProfileModel.fromJson(Map.from(data['data'])); - return _profile.isAuth; + try { + Map data = Map.from(await NetUtil.post('/api/v1/user/profile', method: NetMethod.GET)); + if (data['code'] == 1) { + ProfileModel _profile = ProfileModel.fromJson(Map.from(data['data'])); + return _profile.isAuth; + } + }catch(e, s){ + Logger.error(e, s); } return false; } + + // 返回是否授权 + static void initAuth(BuildContext context) async { + try { + Map data = Map.from(await NetUtil.post('/api/v1/user/profile', method: NetMethod.GET)); + if (data['code'] == 1) { + ProfileModel model = ProfileModel.fromJson(Map.from(data['data'])); + if(null != model && model.isAuth){ + Provider.of(context, listen: false).updateUserAuth(true); + } + } + }catch(e, s){ + Logger.error(e, s); + } + + } + } diff --git a/lib/util/update/app_update_model.dart b/lib/util/update/app_update_model.dart index 67402e8..47ff9f9 100644 --- a/lib/util/update/app_update_model.dart +++ b/lib/util/update/app_update_model.dart @@ -1,11 +1,32 @@ class AppUpdateModel { + /// Android的第三方URL更新链接 例如:应用宝 String appDownloadThirdpartyUrl; + + /// 更新的下载链接(Android为应用内的下载链接,IOS为商店链接) String appDownloadUrl; + + /// 新版本号码 String appVersion; + + /// 新版本昵称 String appVersionName; + + /// 更新内容 + String content; + + /// 是否显示提示更新弹窗 String dialog; + + /// 是否强制更新 String isForce; + + /// 是否可以忽略此版本 + String isIgnore; + + /// 是否优先使用第三方更新 String isThirdparty; + + /// 提示 String tip; AppUpdateModel({ @@ -17,6 +38,7 @@ class AppUpdateModel { this.isForce, this.isThirdparty, this.tip, + this.content, }); AppUpdateModel.fromJson(Map json) { @@ -26,8 +48,10 @@ class AppUpdateModel { appVersionName = json['app_version_name']; dialog = json['dialog']; isForce = json['is_force']; + isIgnore = json['is_ignore']; isThirdparty = json['is_thirdparty']; tip = json['tip']; + content = json['content']; } Map toJson() { @@ -38,8 +62,10 @@ class AppUpdateModel { data['app_version_name'] = this.appVersionName; data['dialog'] = this.dialog; data['is_force'] = this.isForce; + data['is_ignore'] = this.isIgnore; data['is_thirdparty'] = this.isThirdparty; data['tip'] = this.tip; + data['content'] = this.content; return data; } } diff --git a/lib/util/update/app_update_util.dart b/lib/util/update/app_update_util.dart index afb71ac..550800b 100644 --- a/lib/util/update/app_update_util.dart +++ b/lib/util/update/app_update_util.dart @@ -3,8 +3,10 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_update_dialog/flutter_update_dialog.dart'; -// import 'package:flutter_xupdate/flutter_xupdate.dart'; +import 'package:flutter_xupdate/flutter_xupdate.dart'; import 'package:package_info/package_info.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:zhiying_comm/util/shared_prefe_util.dart'; import 'package:zhiying_comm/util/update/app_update_model.dart'; import 'package:zhiying_comm/zhiying_comm.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -15,48 +17,49 @@ import '../log/let_log.dart'; /// App更新工具类 /// class AppUpdateUtil { + static final String _IGNORE_VERSION = "xupdate_ignore_version"; + /// /// 初始化更新插件 /// static void initXUpdate() { if (Platform.isAndroid) { - // FlutterXUpdate.init( - // - // ///是否输出日志 - // debug: true, - // - // ///是否使用post请求 - // isPost: false, - // - // ///post请求是否是上传json - // isPostJson: false, - // - // ///是否开启自动模式 - // isWifiOnly: false, - // - // ///是否开启自动模式 - // isAutoMode: false, - // - // ///需要设置的公共参数 - // supportSilentInstall: false, - // - // ///在下载过程中,如果点击了取消的话,是否弹出切换下载方式的重试提示弹窗 - // enableRetry: false) - // .then((value) { - // // updateMessage("初始化成功: $value"); - // Logger.log('初始化成功: $value'); - // }).catchError((error) { - // print(error); - // }); - - // FlutterXUpdate.setErrorHandler(onUpdateError: (Map message) async { - // Logger.warn(message); - // // setState(() { - // // _message = "$message"; - // // }); - // }); + FlutterXUpdate.init( + + ///是否输出日志 + debug: true, + + ///是否使用post请求 + isPost: false, + + ///post请求是否是上传json + isPostJson: false, + + ///是否开启自动模式 + isWifiOnly: false, + + ///是否开启自动模式 + isAutoMode: false, + + ///需要设置的公共参数 + supportSilentInstall: false, + + ///在下载过程中,如果点击了取消的话,是否弹出切换下载方式的重试提示弹窗 + enableRetry: false) + .then((value) { + Logger.log('初始化成功: $value'); + }).catchError((error) { + print(error); + }); + + FlutterXUpdate.setErrorHandler(onUpdateError: (Map message) async { + Logger.warn(message); + }); + + FlutterXUpdate.setErrorHandler(onUpdateError: (Map message) async { + Logger.warn(message); + }); } else { - // updateMessage("ios暂不支持XUpdate更新"); Logger.log('ios暂不支持XUpdate更新'); } } @@ -64,74 +67,89 @@ class AppUpdateUtil { /// /// 检查并且更新app /// - static void updateApp(BuildContext context) async { - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - Logger.log('version = ${packageInfo.version}, buildNum = ${packageInfo.buildNumber}'); - var result = await NetUtil.post('/api/v1/appcheck', params: {'app_version': packageInfo.buildNumber}, method: NetMethod.GET); - customStyle(context, onUpdate: (){ - Navigator.pop(context); - }); - // UpdateEntity updateEntity = await _checkAppUpdate(); - // // 有新版本,进行更新 - // if (!EmptyUtil.isEmpty(updateEntity) && updateEntity.hasUpdate) { - // if (Platform.isAndroid) { - // FlutterXUpdate.updateByInfo( - // updateEntity: updateEntity, - // supportBackgroundUpdate: true, - // ); - // } else if (Platform.isIOS) { - // // TODO 完成IOS更新 - // String updateUrl = updateEntity.downloadUrl; - // customStyle(context, onUpdate: (){ - // - // - // - // Navigator.pop(context); - // }); - // } - // } else { - // Fluttertoast.showToast(msg: '已经是最新版本了~'); - // } + /// @context 上下文 + /// @needToast 是否需要提示最新版本 + /// @mustShowDialog 是否必须弹窗(检查更新页面要弹窗) + /// + static void updateApp(BuildContext context, {bool needToast = false, bool mustShowDialog = false}) async { + UpdateEntity updateEntity = await _checkAppUpdate(); + // 有新版本,进行更新 + if (!EmptyUtil.isEmpty(updateEntity) && updateEntity.hasUpdate) { + if (Platform.isAndroid) { + FlutterXUpdate.updateByInfo( + updateEntity: updateEntity, + supportBackgroundUpdate: true, + enableIgnore: mustShowDialog || updateEntity.isForce, + retryContent: '更新下载速度太慢了,是否考虑切换下载方式?', + enableRetry: updateEntity.thirdParty, + overrideGlobalRetryStrategy: true, + retryUrl: updateEntity.thirdUrl, + ); + } else if (Platform.isIOS) { + bool ignore = await isIgnoreVersion(updateEntity?.versionCode?.toString()); + if ((!ignore || mustShowDialog) || updateEntity.isForce || !updateEntity.isIgnorable) { + String updateUrl = updateEntity.downloadUrl; + customStyle(context, updateEntity, onUpdate: () { + // 打开第三方sdk + launch(updateUrl, forceSafariVC: true, enableJavaScript: true, forceWebView: true); + Navigator.pop(context); + }); + } + } + } else { + if (needToast) Fluttertoast.showToast(msg: '已经是最新版本了~'); + } } /// 检查是否有新版本 - // static Future _checkAppUpdate() async { - // try { - // PackageInfo packageInfo = await PackageInfo.fromPlatform(); - // // var result = await NetUtil.post('/api/v1/appcheck', params: {'app_version': packageInfo.version}, method: NetMethod.GET); - // - // var result = { - // 'dialog': '1', - // 'is_force': '0', - // 'app_version': '5', - // 'app_version_name': '5.0.0', - // 'tip': '\n1、优化api接口。\n2、添加使用demo演示。\n3、新增自定义更新服务API接口。\n4、优化更新提示界面。', - // 'app_download_url': 'http://imtt.dd.qq.com/16891/apk/FAD58DEFE56A938D86B123DEA4E298EB.apk?fsname=com.hairuyi.www_5.8.8_469.apk&hsr=4d5s', - // }; - // AppUpdateModel model = AppUpdateModel.fromJson(result); - // if (!EmptyUtil.isEmpty(model)) { - // // ⚠️ isIgnorable 目前只有两种状态,为强制更新和不强制更新(每次进来都会提示更新UI弹窗) - // return UpdateEntity( - // hasUpdate: model?.dialog == '1', - // isIgnorable: false, - // isForce: model?.isForce == '1', - // versionCode: int.parse(model?.appVersion ?? '1'), - // versionName: model?.appVersionName, - // downloadUrl: model?.appDownLoadUrl, - // updateContent: model?.tip, - // ); - // } - // } catch (e, s) { - // Logger.error(e, s); - // } - // return null; - // } - - static void customStyle(BuildContext context, {@required VoidCallback onUpdate }) { + static Future _checkAppUpdate() async { + try { + + // var result = { + // "code": 1, + // "data": { + // "app_download_thirdparty_url": "https://android.myapp.com/myapp/detail.htm?apkName=com.hairuyi.www&ADTAG=mobile", + // "app_download_url": "http://fir.osant.cn/zhiyi", + // "app_version": "1", + // "app_version_name": "1.0.0", + // "content": "更新接口\n完善app页面\n更新站长后台", + // "dialog": "1", + // "is_force": "0", + // "is_ignore": "0", + // "is_thirdparty": "1", + // "tip": "有新版下载" + // }, + // "msg": "ok" + // }; + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + var result = await NetUtil.post('/api/v1/appcheck', method: NetMethod.GET); + AppUpdateModel model = AppUpdateModel.fromJson(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); + if (!EmptyUtil.isEmpty(model)) { + return UpdateEntity( + hasUpdate: model?.dialog == '1' || model?.isForce == '1', + isIgnorable: model?.isIgnore == '1' && model?.isForce != '1', + isForce: model?.isForce == '1', + versionCode: int.parse(model?.appVersion ?? '1'), + versionName: model?.appVersionName, + downloadUrl: model?.appDownloadUrl, + updateContent: model?.content, + tip: model?.tip, + thirdUrl: model?.appDownloadThirdpartyUrl, + thirdParty: model?.isThirdparty == '1', + ); + } + } catch (e, s) { + Logger.error(e, s); + } + return null; + } + + // IOS 样式 + static void customStyle(BuildContext context, UpdateEntity updateEntity, {@required VoidCallback onUpdate}) { UpdateDialog.showUpdate(context, width: 250, - title: "是否升级到4.1.4版本?", - updateContent: "新版本大小:2.0M\n1.xxxxxxx\n2.xxxxxxx\n3.xxxxxxx", + title: "是否升级到${updateEntity?.versionName ?? '1.0.0'}版本?", + updateContent: updateEntity?.updateContent ?? '', titleTextSize: 14, contentTextSize: 12, buttonTextSize: 12, @@ -140,11 +158,28 @@ class AppUpdateUtil { radius: 8, themeColor: Colors.redAccent, progressBackgroundColor: Color(0x5AFFAC5D), - isForce: false, + isForce: updateEntity?.isForce ?? false, updateButtonText: '升级', ignoreButtonText: '忽略此版本', - enableIgnore: true, onIgnore: () { + enableIgnore: updateEntity?.isIgnorable ?? false, onIgnore: () { + saveIgnoreVersion(updateEntity?.versionCode?.toString()); Navigator.pop(context); }, onUpdate: onUpdate); } + + // 保存忽略的版本号码 + static void saveIgnoreVersion(String newVersion) async { + if (!EmptyUtil.isEmpty(newVersion)) { + await SharedPreferencesUtil.setStringValue(_IGNORE_VERSION, newVersion); + } + } + + // 是否是忽略版本 + static Future isIgnoreVersion(String newVersion) async { + String oldVersion = await SharedPreferencesUtil.getStringValue(_IGNORE_VERSION); + if (!EmptyUtil.isEmpty(oldVersion) && !EmptyUtil.isEmpty(newVersion)) { + return oldVersion == newVersion; + } + return false; + } } diff --git a/pubspec.yaml b/pubspec.yaml index cfcb100..3484781 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,7 +33,10 @@ dependencies: # 京东sdk jdsdk: ^0.0.1 # Android app更新 -# flutter_xupdate: ^1.0.0 + flutter_xupdate: + git: + ref: 1.0.1 + url: http://192.168.0.138:3000/FnuoOS_ZhiYing/flutter_xupdate.git # app更新dialogUI(用于IOS,以便统一样式) flutter_update_dialog: 1.0.0 flutter_alibc: