import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_bugly/flutter_bugly.dart'; import 'package:intl/intl.dart'; import 'package:dio/dio.dart'; import 'package:path_provider/path_provider.dart'; import 'package:open_file/open_file.dart'; import 'package:permission_handler/permission_handler.dart'; Future checkUpgrade(context, key) async { final upgradeInfo = await FlutterBugly.getUpgradeInfo(); if (upgradeInfo == null) { return false; } return await showUpgradeDialog(context, upgradeInfo, key); } Future showUpgradeDialog(context, upgradeInfo, key) async { return await showGeneralDialog( context: context, barrierDismissible: false, pageBuilder: (BuildContext buildContext, Animation animation, Animation secondaryAnimation) { return WillPopScope( onWillPop: () { return Future.value(false); }, child: Center( child: Material( color: Colors.transparent, child: UpgradeDialog(upgradeInfo, key: key), ), ), ); }, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, barrierColor: Colors.black87, transitionDuration: const Duration(milliseconds: 300), ); } Future downloadApk(context, url) async { return await showGeneralDialog( context: context, barrierDismissible: false, pageBuilder: (BuildContext buildContext, Animation animation, Animation secondaryAnimation) { return Center( child: Material( color: Colors.transparent, child: DownloadDialog(url), ), ); }, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, barrierColor: Colors.black87, transitionDuration: const Duration(milliseconds: 300), ); } class UpgradeDialog extends StatefulWidget { final UpgradeInfo upgradeInfo; UpgradeDialog(this.upgradeInfo, {Key key}) : super(key: key); @override State createState() { return UpgradeDialogState(); } } class UpgradeDialogState extends State { final Color primaryColor = Color(0xFF1990F8); final Color bgColor = Color(0xE6293559); @override Widget build(BuildContext context) { return Container( width: 280, padding: EdgeInsets.only(left: 20, right: 20), decoration: BoxDecoration(color: bgColor, border: Border.all(width: 1, color: primaryColor)), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: [ Container( margin: EdgeInsets.only(top: 20), child: Text( widget.upgradeInfo.title, style: TextStyle(color: primaryColor, fontSize: 16, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), ), Container( margin: EdgeInsets.only(top: 15), child: Text( '版本:' + widget.upgradeInfo.versionName, style: TextStyle(color: Colors.white), ), ), Container( margin: EdgeInsets.only(top: 10), child: Text( '包大小:' + (widget.upgradeInfo.fileSize / 1024 / 1024).toStringAsFixed(0) + 'MB', style: TextStyle(color: Colors.white), ), ), Container( margin: EdgeInsets.only(top: 10), child: Text( '更新时间:' + DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.fromMicrosecondsSinceEpoch(widget.upgradeInfo.publishTime * 1000)), style: TextStyle(color: Colors.white), ), ), Container( margin: EdgeInsets.only(top: 10), child: Text( '更新说明:', style: TextStyle(color: Colors.white), ), ), Container( margin: EdgeInsets.only(top: 6), child: Text( widget.upgradeInfo.newFeature, style: TextStyle(color: Colors.white), ), ), Container( margin: EdgeInsets.only(bottom: 20, top: 20), child: Row( children: [ widget.upgradeInfo.upgradeType == 2 ? Container() : Expanded( child: MaterialButton( elevation: 0, highlightElevation: 0, minWidth: 100, height: 36, color: Color(0xFF4F5C87), child: Text( '下次再说', style: TextStyle(color: Colors.white), ), onPressed: () { Navigator.of(context).pop(); }, ), ), widget.upgradeInfo.upgradeType == 2 ? Container() : Container(width: 20), Expanded( child: MaterialButton( elevation: 0, highlightElevation: 0, minWidth: 100, height: 36, color: primaryColor, child: Text( '立即更新', style: TextStyle(color: Colors.white), ), onPressed: () async { PermissionStatus permission = await PermissionHandler().checkPermissionStatus(PermissionGroup.storage); if (permission == PermissionStatus.denied) { Map permissions = await PermissionHandler().requestPermissions([PermissionGroup.storage]); if (permissions[PermissionGroup.storage] == PermissionStatus.denied) { showDialog( context: context, barrierDismissible: false, builder: (context) { return AlertDialog( content: Text( '需要获取外部存储权限来下载安装包', style: TextStyle(color: Colors.black), ), actions: [ FlatButton( child: Text('打开设置'), onPressed: () { Navigator.of(context).pop(); PermissionHandler().openAppSettings(); }, ), ], ); }); return; } } Navigator.of(context).pop(); await downloadApk(context, widget.upgradeInfo.apkUrl); }, ), ) ], ), ) ], ), ); } } class DownloadDialog extends StatefulWidget { final String url; DownloadDialog(this.url, {Key key}) : super(key: key); @override State createState() { return DownloadDialogState(); } } class DownloadDialogState extends State { final Color primaryColor = Color(0xFF1990F8); final Color bgColor = Color(0xE6293559); Dio dio; CancelToken token; double progress = 0; @override void initState() { super.initState(); Future.delayed(Duration.zero, () async { final Directory tempDir = await getExternalStorageDirectory(); final String tempPath = tempDir.path; final String savePath = '$tempPath/update.apk'; dio = Dio(); token = CancelToken(); final res = await dio.download( widget.url, savePath, onReceiveProgress: (int count, int total) { setState(() { progress = count / total; }); }, options: Options(receiveTimeout: 10 * 60 * 1000), cancelToken: token, ).catchError((_error) { return _error; }); if (res != null && res.statusCode == 200) { OpenFile.open(savePath); } Navigator.of(context).pop(); }); } @override Widget build(BuildContext context) { return Container( width: 300, height: 60, padding: EdgeInsets.fromLTRB(15, 10, 15, 10), decoration: BoxDecoration(color: bgColor, border: Border.all(width: 1, color: primaryColor)), child: Column( children: [ Row( children: [ Expanded( child: Text( '正在下载更新', style: TextStyle(color: primaryColor, fontSize: 14), ), ), Text( (progress * 100).toStringAsFixed(0) + '%', style: TextStyle(color: Colors.white.withAlpha(128)), ) ], ), Container( margin: EdgeInsets.only(top: 10), child: Align( alignment: Alignment.centerLeft, child: FractionallySizedBox( widthFactor: progress, child: Container( height: 2, color: primaryColor, ), ), ), ) ], ), ); } }