基础库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

185 lines
6.3 KiB

  1. import 'dart:io';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_update_dialog/flutter_update_dialog.dart';
  5. import 'package:flutter_xupdate/flutter_xupdate.dart';
  6. import 'package:package_info/package_info.dart';
  7. import 'package:url_launcher/url_launcher.dart';
  8. import 'package:zhiying_comm/util/shared_prefe_util.dart';
  9. import 'package:zhiying_comm/util/update/app_update_model.dart';
  10. import 'package:zhiying_comm/zhiying_comm.dart';
  11. import 'package:fluttertoast/fluttertoast.dart';
  12. import '../log/let_log.dart';
  13. ///
  14. /// App更新工具类
  15. ///
  16. class AppUpdateUtil {
  17. static final String _IGNORE_VERSION = "xupdate_ignore_version";
  18. ///
  19. /// 初始化更新插件
  20. ///
  21. static void initXUpdate() {
  22. if (Platform.isAndroid) {
  23. FlutterXUpdate.init(
  24. ///是否输出日志
  25. debug: true,
  26. ///是否使用post请求
  27. isPost: false,
  28. ///post请求是否是上传json
  29. isPostJson: false,
  30. ///是否开启自动模式
  31. isWifiOnly: false,
  32. ///是否开启自动模式
  33. isAutoMode: false,
  34. ///需要设置的公共参数
  35. supportSilentInstall: false,
  36. ///在下载过程中,如果点击了取消的话,是否弹出切换下载方式的重试提示弹窗
  37. enableRetry: false)
  38. .then((value) {
  39. Logger.log('初始化成功: $value');
  40. }).catchError((error) {
  41. print(error);
  42. });
  43. FlutterXUpdate.setErrorHandler(onUpdateError: (Map<String, dynamic> message) async {
  44. Logger.warn(message);
  45. });
  46. FlutterXUpdate.setErrorHandler(onUpdateError: (Map<String, dynamic> message) async {
  47. Logger.warn(message);
  48. });
  49. } else {
  50. Logger.log('ios暂不支持XUpdate更新');
  51. }
  52. }
  53. ///
  54. /// 检查并且更新app
  55. ///
  56. /// @context 上下文
  57. /// @needToast 是否需要提示最新版本
  58. /// @mustShowDialog 是否必须弹窗(检查更新页面要弹窗)
  59. ///
  60. static void updateApp(BuildContext context, {bool needToast = false, bool mustShowDialog = false}) async {
  61. UpdateEntity updateEntity = await _checkAppUpdate();
  62. // 有新版本,进行更新
  63. if (!EmptyUtil.isEmpty(updateEntity) && updateEntity.hasUpdate) {
  64. if (Platform.isAndroid) {
  65. FlutterXUpdate.updateByInfo(
  66. updateEntity: updateEntity,
  67. supportBackgroundUpdate: true,
  68. enableIgnore: mustShowDialog || updateEntity.isForce,
  69. retryContent: '更新下载速度太慢了,是否考虑切换下载方式?',
  70. enableRetry: updateEntity.thirdParty,
  71. overrideGlobalRetryStrategy: true,
  72. retryUrl: updateEntity.thirdUrl,
  73. );
  74. } else if (Platform.isIOS) {
  75. bool ignore = await isIgnoreVersion(updateEntity?.versionCode?.toString());
  76. if ((!ignore || mustShowDialog) || updateEntity.isForce || !updateEntity.isIgnorable) {
  77. String updateUrl = updateEntity.downloadUrl;
  78. customStyle(context, updateEntity, onUpdate: () {
  79. // 打开第三方sdk
  80. launch(updateUrl, forceSafariVC: true, enableJavaScript: true, forceWebView: true);
  81. Navigator.pop(context);
  82. });
  83. }
  84. }
  85. } else {
  86. if (needToast) Fluttertoast.showToast(msg: '已经是最新版本了~');
  87. }
  88. }
  89. /// 检查是否有新版本
  90. static Future<UpdateEntity> _checkAppUpdate() async {
  91. try {
  92. // var result = {
  93. // "code": 1,
  94. // "data": {
  95. // "app_download_thirdparty_url": "https://android.myapp.com/myapp/detail.htm?apkName=com.hairuyi.www&ADTAG=mobile",
  96. // "app_download_url": "http://fir.osant.cn/zhiyi",
  97. // "app_version": "1",
  98. // "app_version_name": "1.0.0",
  99. // "content": "更新接口\n完善app页面\n更新站长后台",
  100. // "dialog": "1",
  101. // "is_force": "0",
  102. // "is_ignore": "0",
  103. // "is_thirdparty": "1",
  104. // "tip": "有新版下载"
  105. // },
  106. // "msg": "ok"
  107. // };
  108. var result = await NetUtil.post('/api/v1/appcheck', method: NetMethod.GET);
  109. AppUpdateModel model = AppUpdateModel.fromJson(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]);
  110. if (!EmptyUtil.isEmpty(model)) {
  111. return UpdateEntity(
  112. hasUpdate: model?.dialog == '1',
  113. isIgnorable: model?.isIgnore == '1' && model?.isForce != '1',
  114. isForce: model?.isForce == '1',
  115. versionCode: int.parse(model?.appVersion ?? '1'),
  116. versionName: model?.appVersionName,
  117. downloadUrl: model?.appDownloadUrl,
  118. updateContent: model?.content,
  119. tip: model?.tip,
  120. thirdUrl: model?.appDownloadThirdpartyUrl,
  121. thirdParty: model?.isThirdparty == '1',
  122. );
  123. }
  124. } catch (e, s) {
  125. Logger.error(e, s);
  126. }
  127. return null;
  128. }
  129. // IOS 样式
  130. static void customStyle(BuildContext context, UpdateEntity updateEntity, {@required VoidCallback onUpdate}) {
  131. UpdateDialog.showUpdate(context,
  132. width: 250,
  133. title: "是否升级到${updateEntity?.versionName ?? '1.0.0'}版本?",
  134. updateContent: updateEntity?.updateContent ?? '',
  135. titleTextSize: 14,
  136. contentTextSize: 12,
  137. buttonTextSize: 12,
  138. // topImage: Image.asset('assets/bg_update_top.png'),
  139. extraHeight: 5,
  140. radius: 8,
  141. themeColor: Colors.redAccent,
  142. progressBackgroundColor: Color(0x5AFFAC5D),
  143. isForce: updateEntity?.isForce ?? false,
  144. updateButtonText: '升级',
  145. ignoreButtonText: '忽略此版本',
  146. enableIgnore: updateEntity?.isIgnorable ?? false, onIgnore: () {
  147. saveIgnoreVersion(updateEntity?.versionCode?.toString());
  148. Navigator.pop(context);
  149. }, onUpdate: onUpdate);
  150. }
  151. // 保存忽略的版本号码
  152. static void saveIgnoreVersion(String newVersion) async {
  153. if (!EmptyUtil.isEmpty(newVersion)) {
  154. await SharedPreferencesUtil.setStringValue(_IGNORE_VERSION, newVersion);
  155. }
  156. }
  157. // 是否是忽略版本
  158. static Future<bool> isIgnoreVersion(String newVersion) async {
  159. String oldVersion = await SharedPreferencesUtil.getStringValue(_IGNORE_VERSION);
  160. if (!EmptyUtil.isEmpty(oldVersion) && !EmptyUtil.isEmpty(newVersion)) {
  161. return oldVersion == newVersion;
  162. }
  163. return false;
  164. }
  165. }