CheckUpgrade.dart 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import 'dart:io';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter/widgets.dart';
  4. import 'package:flutter_bugly/flutter_bugly.dart';
  5. import 'package:intl/intl.dart';
  6. import 'package:dio/dio.dart';
  7. import 'package:path_provider/path_provider.dart';
  8. import 'package:open_file/open_file.dart';
  9. import 'package:permission_handler/permission_handler.dart';
  10. Future checkUpgrade(context, key) async {
  11. final upgradeInfo = await FlutterBugly.getUpgradeInfo();
  12. if (upgradeInfo == null) {
  13. return false;
  14. }
  15. return await showUpgradeDailog(context, upgradeInfo, key);
  16. }
  17. Future showUpgradeDailog(context, upgradeInfo, key) async {
  18. return await showGeneralDialog(
  19. context: context,
  20. barrierDismissible: false,
  21. pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) {
  22. return WillPopScope(
  23. onWillPop: () {
  24. return Future.value(false);
  25. },
  26. child: Center(
  27. child: Material(
  28. color: Colors.transparent,
  29. child: UpgradeDialog(upgradeInfo, key: key),
  30. ),
  31. ),
  32. );
  33. },
  34. barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
  35. barrierColor: Colors.black26,
  36. transitionDuration: const Duration(milliseconds: 300),
  37. );
  38. }
  39. Future downloadApk(context, url) async {
  40. return await showGeneralDialog(
  41. context: context,
  42. barrierDismissible: false,
  43. pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) {
  44. return Center(
  45. child: Material(
  46. color: Colors.transparent,
  47. child: DownloadDialog(url),
  48. ),
  49. );
  50. },
  51. barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
  52. barrierColor: Colors.black26,
  53. transitionDuration: const Duration(milliseconds: 300),
  54. );
  55. }
  56. class UpgradeDialog extends StatefulWidget {
  57. final UpgradeInfo upgradeInfo;
  58. UpgradeDialog(this.upgradeInfo, {Key key}) : super(key: key);
  59. @override
  60. State<StatefulWidget> createState() {
  61. return UpgradeDialogState();
  62. }
  63. }
  64. class UpgradeDialogState extends State<UpgradeDialog> {
  65. final Color primaryColor = Color(0xFF1990F8);
  66. final Color bgColor = Color(0xE6293559);
  67. @override
  68. Widget build(BuildContext context) {
  69. return Container(
  70. width: 280,
  71. padding: EdgeInsets.only(left: 20, right: 20),
  72. decoration: BoxDecoration(color: bgColor, border: Border.all(width: 1, color: primaryColor)),
  73. child: Column(
  74. mainAxisAlignment: MainAxisAlignment.start,
  75. crossAxisAlignment: CrossAxisAlignment.stretch,
  76. mainAxisSize: MainAxisSize.min,
  77. children: <Widget>[
  78. Container(
  79. margin: EdgeInsets.only(top: 20),
  80. child: Text(
  81. widget.upgradeInfo.title,
  82. style: TextStyle(color: primaryColor, fontSize: 16, fontWeight: FontWeight.bold),
  83. textAlign: TextAlign.center,
  84. ),
  85. ),
  86. Container(
  87. margin: EdgeInsets.only(top: 15),
  88. child: Text(
  89. '版本:' + widget.upgradeInfo.versionName,
  90. style: TextStyle(color: Colors.white),
  91. ),
  92. ),
  93. Container(
  94. margin: EdgeInsets.only(top: 10),
  95. child: Text(
  96. '包大小:' + (widget.upgradeInfo.fileSize / 1024 / 1024).toStringAsFixed(0) + 'MB',
  97. style: TextStyle(color: Colors.white),
  98. ),
  99. ),
  100. Container(
  101. margin: EdgeInsets.only(top: 10),
  102. child: Text(
  103. '更新时间:' + DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.fromMicrosecondsSinceEpoch(widget.upgradeInfo.publishTime * 1000)),
  104. style: TextStyle(color: Colors.white),
  105. ),
  106. ),
  107. Container(
  108. margin: EdgeInsets.only(top: 10),
  109. child: Text(
  110. '更新说明:',
  111. style: TextStyle(color: Colors.white),
  112. ),
  113. ),
  114. Container(
  115. margin: EdgeInsets.only(top: 6),
  116. child: Text(
  117. widget.upgradeInfo.newFeature,
  118. style: TextStyle(color: Colors.white),
  119. ),
  120. ),
  121. Container(
  122. margin: EdgeInsets.only(bottom: 20, top: 20),
  123. child: Row(
  124. children: <Widget>[
  125. widget.upgradeInfo.upgradeType == 2
  126. ? Container()
  127. : Expanded(
  128. child: MaterialButton(
  129. elevation: 0,
  130. highlightElevation: 0,
  131. minWidth: 100,
  132. height: 36,
  133. color: Color(0xFF4F5C87),
  134. child: Text(
  135. '下次再说',
  136. style: TextStyle(color: Colors.white),
  137. ),
  138. onPressed: () {
  139. Navigator.of(context).pop();
  140. },
  141. ),
  142. ),
  143. widget.upgradeInfo.upgradeType == 2 ? Container() : Container(width: 20),
  144. Expanded(
  145. child: MaterialButton(
  146. elevation: 0,
  147. highlightElevation: 0,
  148. minWidth: 100,
  149. height: 36,
  150. color: primaryColor,
  151. child: Text(
  152. '立即更新',
  153. style: TextStyle(color: Colors.white),
  154. ),
  155. onPressed: () async {
  156. PermissionStatus permission = await PermissionHandler().checkPermissionStatus(PermissionGroup.storage);
  157. if (permission == PermissionStatus.denied) {
  158. Map<PermissionGroup, PermissionStatus> permissions = await PermissionHandler().requestPermissions([PermissionGroup.storage]);
  159. if (permissions[PermissionGroup.storage] == PermissionStatus.denied) {
  160. showDialog(
  161. context: context,
  162. barrierDismissible: false,
  163. builder: (context) {
  164. return AlertDialog(
  165. content: Text(
  166. '需要获取外部存储权限来下载安装包',
  167. style: TextStyle(color: Colors.black),
  168. ),
  169. actions: <Widget>[
  170. FlatButton(
  171. child: Text('打开设置'),
  172. onPressed: () {
  173. Navigator.of(context).pop();
  174. PermissionHandler().openAppSettings();
  175. },
  176. ),
  177. ],
  178. );
  179. });
  180. return;
  181. }
  182. }
  183. Navigator.of(context).pop();
  184. await downloadApk(context, widget.upgradeInfo.apkUrl);
  185. },
  186. ),
  187. )
  188. ],
  189. ),
  190. )
  191. ],
  192. ),
  193. );
  194. }
  195. }
  196. class DownloadDialog extends StatefulWidget {
  197. final String url;
  198. DownloadDialog(this.url, {Key key}) : super(key: key);
  199. @override
  200. State<StatefulWidget> createState() {
  201. return DownloadDialogState();
  202. }
  203. }
  204. class DownloadDialogState extends State<DownloadDialog> {
  205. final Color primaryColor = Color(0xFF1990F8);
  206. final Color bgColor = Color(0xE6293559);
  207. Dio dio;
  208. CancelToken token;
  209. double progress = 0;
  210. @override
  211. void initState() {
  212. super.initState();
  213. Future.delayed(Duration.zero, () async {
  214. final Directory tempDir = await getExternalStorageDirectory();
  215. final String tempPath = tempDir.path;
  216. final String savePath = '$tempPath/update.apk';
  217. dio = Dio();
  218. token = CancelToken();
  219. final res = await dio.download(
  220. widget.url,
  221. savePath,
  222. onReceiveProgress: (int count, int total) {
  223. setState(() {
  224. progress = count / total;
  225. });
  226. },
  227. options: Options(receiveTimeout: 10 * 60 * 1000),
  228. cancelToken: token,
  229. ).catchError((_error) {
  230. return _error;
  231. });
  232. if (res != null && res.statusCode == 200) {
  233. OpenFile.open(savePath);
  234. }
  235. Navigator.of(context).pop();
  236. });
  237. }
  238. @override
  239. Widget build(BuildContext context) {
  240. return Container(
  241. width: 300,
  242. height: 60,
  243. padding: EdgeInsets.fromLTRB(15, 10, 15, 10),
  244. decoration: BoxDecoration(color: bgColor, border: Border.all(width: 1, color: primaryColor)),
  245. child: Column(
  246. children: <Widget>[
  247. Row(
  248. children: <Widget>[
  249. Expanded(
  250. child: Text(
  251. '正在下载更新',
  252. style: TextStyle(color: primaryColor, fontSize: 14),
  253. ),
  254. ),
  255. Text(
  256. (progress * 100).toStringAsFixed(0) + '%',
  257. style: TextStyle(color: Colors.white.withAlpha(128)),
  258. )
  259. ],
  260. ),
  261. Container(
  262. margin: EdgeInsets.only(top: 10),
  263. child: Align(
  264. alignment: Alignment.centerLeft,
  265. child: FractionallySizedBox(
  266. widthFactor: progress,
  267. child: Container(
  268. height: 2,
  269. color: primaryColor,
  270. ),
  271. ),
  272. ),
  273. )
  274. ],
  275. ),
  276. );
  277. }
  278. }