参考
功能点:
1.更新弹窗UI
2.强更与非强更且别控制
3.屏蔽物理返回键(因为强更的时候点击返回键,弹窗会消失)
4.点击弹窗外透明区域时,弹窗不消失
先看下效果图:
Dialog实现代码:
import 'package:flutter/material.dart';
import 'package:xiaopijiang/utils/assets_util.dart';
import 'package:xiaopijiang/utils/toast_util.dart';
///created by WGH
///on 2020/7/23
///description:版本更新提示弹窗
class UpdateDialog extends Dialog {
final String upDateContent;
final bool isForce;
UpdateDialog({this.upDateContent, this.isForce});
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 319,
height: 370,
child: Stack(
children: <Widget>[
Image.asset(
AssetsUtil.getImagePath(
imageName: 'bg_update', suffix: 'png'),
fit: BoxFit.cover,
),
Container(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 110),
child: Text('发现新版本',
style: TextStyle(
fontSize: 20,
color: Colors.white,
decoration: TextDecoration.none)),
),
Text(upDateContent,
style: TextStyle(
fontSize: 16,
color: Colors.black54,
decoration: TextDecoration.none)),
Container(
width: 250,
height: 42,
margin: EdgeInsets.only(bottom: 15),
child: RaisedButton(
color: Colors.red,
shape: StadiumBorder(),
child: Text(
'立即更新',
style:
TextStyle(fontSize: 20, color: Colors.white),
),
onPressed: () {
ToastUtil.showTips('下载apk');
}),
)
],
),
),
],
),
),
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Offstage(
offstage: isForce,
child: Container(
margin: EdgeInsets.only(top: 30),
child: Image.asset(
AssetsUtil.getImagePath(
imageName: 'ic_update_close', suffix: 'png'),
width: 35,
height: 35,
)),
),
)
],
),
);
}
static showUpdateDialog(
BuildContext context, String mUpdateContent, bool mIsForce) {
return showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return WillPopScope(
child: UpdateDialog(
upDateContent: mUpdateContent, isForce: mIsForce),onWillPop: _onWillPop);
});
}
static Future<bool> _onWillPop() async{
return false;
}
}
调用Dialog:
_checkUpdate() async{
int serviceVersionCode = 101;
PackageInfo packageInfo = await PackageInfo.fromPlatform();
//获取当前的版本号
int currentVersionCode = int.parse(packageInfo.version.replaceAll('.', ''));
//如果获取服务器的版本号比当前应用程序的版本号还高,那么提示升级
if (serviceVersionCode > currentVersionCode) {
if(Platform.isAndroid){
//Android平台在应用内进行更新
//弹出"版本更新"的对话框
UpdateDialog.showUpdateDialog(context, '1.修复已知bug\n2.优化用户体验', false);
}else if(Platform.isIOS){
//iOS平台跳转道AppStore进行更新
}
}
}
重点说明:
屏蔽物理返回键(因为强更的时候点击返回键,弹窗会消失)
barrierDismissible: false,
4.点击弹窗外透明区域时,弹窗不消失
return WillPopScope(
child: UpdateDialog(
upDateContent: mUpdateContent, isForce: mIsForce),
onWillPop: _onWillPop);
static Future<bool> _onWillPop() async {
return false;
}
参考
前言:android
Flutter的APP打开后检测到有新版本,Android端能够强制更新APK或者跳转到 Google play 官网去下载,iOS端只能去 App Store 官网下载。由于咱们的应用是上架到 Google Play,因此当用户点击下载的按钮,直接跳转到 Google Play 官网或者 App Store 官网去下载APK便可。下面我简单总结一下在Flutter中实现“版本更新”的功能。服务器
思路:网络
1.第一次打开APP时执行"版本更新"的网络请求;app
2.比较服务器的版本号跟当前的版本号,来判断要不要升级APP应用程序;async
3.弹出“版本更新”对话框;ide
4.点击"Later"把时间戳保存下来,每次打开APP获取当前时间戳;ui
5.若是新旧时间戳的差大于或等于一天,执行网络请求(直到点击"DownLoad"为止);this
6.点击"DownLoad"直接到 Google Play 官网去下载APK。google
实现的步骤:url
1.在pubspec.yaml添加sdk
version: 1.0.2+3 #版本名称:1.0.2 版本号:3
dependencies:
...
cupertino_icons: ^0.1.0
package_info: ^0.3.2+1
2.导包
import 'package:package_info/package_info.dart';
3.第一次打开APP时执行"版本更新"的网络请求
class UpdatePagerState extends State<UpdaterPage> {
var _serviceVersionCode,
_serviceVersionName,
_serviceVersionPlatform,
_serviceVersionApp;;
@override
void initState() {
super.initState();
_getNewVersionAPP();
}
//执行版本更新的网络请求
_getNewVersionAPP() async {
String url = IHttpService.getNewVersionApp;
DioUtil.getInstance().get(context, url).then((response) {
if (response != null) {
setState(() {
var data = response.data;
_serviceVersionCode = data["versionCode"].toString(); //版本号
_serviceVersionName = data["versionName"].toString(); //版本名称
_serviceVersionPlatform = data["versionPlatform"].toString();//版本平台
_serviceVersionApp = data["versionApp"].toString();//下载的url
_checkVersionCode();
});
}
});
}
}
4.比较服务器的版本号跟当前的版本号,来判断要不要升级APP应用程序
void _checkVersionCode() {
PackageInfo.fromPlatform().then((PackageInfo packageInfo) {
var _currentVersionCode = packageInfo.version;//获取当前的版本号
int serviceVersionCode = int.parse(_serviceVersionCode); //String -> int
int currentVersionCode = int.parse(_currentVersionCode); //String -> int
//若是获取服务器的版本号比当前应用程序的版本号还高,那么提示升级
if (serviceVersionCode > currentVersionCode) {
_showNewVersionAppDialog();//弹出"版本更新"的对话框
}
});
}
5.弹出“版本更新”对话框
Future<void> _showNewVersionAppDialog() async {
if (_serviceVersionPlatform == "android") {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: new Row(
children: <Widget>[
new Image.asset("images/ic_launcher_icon.png",
height: 35.0, width: 35.0),
new Padding(
padding: const EdgeInsets.fromLTRB(30.0, 0.0, 10.0, 0.0),
child: new Text("项目名称",
style: dialogButtonTextStyle))
],
),
content: new Text(
'版本更新',
style: dialogTextStyle),
actions: <Widget>[
new FlatButton(
child: new Text('Later', style: dialogButtonTextStyle),
onPressed: () {
Navigator.of(context).pop();
},
),
new FlatButton(
child: new Text('DownLoad', style: dialogButtonTextStyle),
onPressed: () {
//https://play.google.com/store/apps/details?id=项目包名
launch(_serviceVersionApp);//到Google Play 官网下载
Navigator.of(context).pop();
},
)
],
);
});
}else{
//iOS
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: new Row(
children: <Widget>[
new Image.asset("images/ic_launcher_icon.png",
height: 35.0, width: 35.0),
new Padding(
padding: const EdgeInsets.fromLTRB(30.0, 0.0, 10.0, 0.0),
child: new Text(Strings.new_version_title,
style: dialogButtonTextStyle))
],
),
content: new Text(
"New version v$_serviceVersionName is available. " +
Strings.new_version_dialog_content,
style: dialogTextStyle),
actions: <Widget>[
new CupertinoDialogAction(
child: new Text(Strings.new_version_button_later,
style: dialogButtonTextStyle),
onPressed: () {
Navigator.of(context).pop();
},
),
new CupertinoDialogAction(
child: new Text(Strings.new_version_button_download,
style: dialogButtonTextStyle),
onPressed: () {
//_serviceVersionApp="http://itunes.apple.com/cn/lookup?id=项目包名"
launch(_serviceVersionApp);//到APP store 官网下载
Navigator.of(context).pop();
},
)
],
);
});
}
}
6.完整的代码
class UpdaterPage extends StatefulWidget {
final Widget child;
const UpdaterPage(this.child);
@override
UpdatePagerState createState() => UpdatePagerState();
}
class UpdatePagerState extends State<UpdaterPage> {
var _serviceVersionCode,
_serviceVersionName,
_serviceVersionPlatform,
_serviceVersionApp;
@override
void initState() {
super.initState();
//每次打开APP获取当前时间戳
var timeEnd = DateTime.now().millisecondsSinceEpoch;
//获取"Later"保存的时间戳
var timeStart = SpUtil.getInt(Constants.timeStart);
if (timeStart == 0) {//第一次打开APP时执行"版本更新"的网络请求
_getNewVersionAPP();
} else if (timeStart != 0 && timeEnd - timeStart >= 24 * 60 * 60 * 1000) {
//若是新旧时间戳的差大于或等于一天,执行网络请求
_getNewVersionAPP();
}
}
//执行版本更新的网络请求
_getNewVersionAPP() async {
String url = IHttpService.getNewVersionApp;
DioUtil.getInstance().get(context, url).then((response) {
if (response != null) {
setState(() {
var data = response.data;
_serviceVersionCode = data["versionCode"].toString();//版本号
_serviceVersionName = data["versionName"].toString();//版本名称
_serviceVersionPlatform = data["versionPlatform"].toString();//版本平台
_serviceVersionApp = data["versionApp"].toString();//下载的URL
_checkVersionCode();
});
}
});
}
//检查版本更新的版本号
_checkVersionCode() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String _currentVersionCode = packageInfo.version;
int serviceVersionCode = int.parse(_serviceVersionCode); //String -> int
int currentVersionCode = int.parse(_currentVersionCode); //String -> int
if (serviceVersionCode > currentVersionCode) {
_showNewVersionAppDialog();//弹出对话框
}
}
//弹出"版本更新"对话框
Future<void> _showNewVersionAppDialog() async {
if (_serviceVersionPlatform == "android") {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: new Row(
children: <Widget>[
new Image.asset("images/ic_launcher_icon.png",
height: 35.0, width: 35.0),
new Padding(
padding: const EdgeInsets.fromLTRB(30.0, 0.0, 10.0, 0.0),
child: new Text("项目名称",
style: dialogButtonTextStyle))
],
),
content: new Text(
'版本更新',
style: dialogTextStyle),
actions: <Widget>[
new FlatButton(
child: new Text('Later', style: dialogButtonTextStyle),
onPressed: () {
Navigator.of(context).pop();
var timeStart = DateTime.now().millisecondsSinceEpoch;
DataUtil.saveCurrentTimeMillis(timeStart);//保存当前的时间戳
},
),
new FlatButton(
child: new Text('DownLoad', style: dialogButtonTextStyle),
onPressed: () {
//https://play.google.com/store/apps/details?id=项目包名
launch(_serviceVersionApp);//到Google Play 官网下载
Navigator.of(context).pop();
},
)
],
);
});
}else{
//iOS
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: new Row(
children: <Widget>[
new Image.asset("images/ic_launcher_icon.png",
height: 35.0, width: 35.0),
new Padding(
padding: const EdgeInsets.fromLTRB(30.0, 0.0, 10.0, 0.0),
child: new Text(Strings.new_version_title,
style: dialogButtonTextStyle))
],
),
content: new Text(
"New version v$_serviceVersionName is available. " +
Strings.new_version_dialog_content,
style: dialogTextStyle),
actions: <Widget>[
new CupertinoDialogAction(
child: new Text(Strings.new_version_button_later,
style: dialogButtonTextStyle),
onPressed: () {
Navigator.of(context).pop();
var timeStart = DateTime.now().millisecondsSinceEpoch;
DataUtil.saveCurrentTimeMillis(timeStart);//保存当前的时间戳
},
),
new CupertinoDialogAction(
child: new Text(Strings.new_version_button_download,
style: dialogButtonTextStyle),
onPressed: () {
//_serviceVersionApp="http://itunes.apple.com/cn/lookup?id=项目包名"
launch(_serviceVersionApp);//到APP store 官网下载
Navigator.of(context).pop();
},
)
],
);
});
}
}
@override
Widget build(BuildContext context) => widget.child;
}
7.在首页调用”版本更新”的类
class IndexPage extends StatefulWidget {
@override
IndexPageState createState() => IndexPageState();
}
class IndexPageState extends State<IndexPage>{
@override
Widget build(BuildContext context) {
return UpdaterPage(Scaffold( //调用UpdaterPage
appBar: _buildAppBar(),
body: getScreen()
));
}
}
8.总结
当有新版本须要升级时,客户端会"版本更新"弹出对话框,Android用户跳转到 Google Play 官网去下载APK,而iOS用户跳转到 App Store 官网下载。APP版本更新的功能已经实现,欢迎你们围观。若是有什么疑问的话,能够留言联系我哦!
参考
升级说明:
Android:应用内更新下载+安装。iOS:跳转到appstore下载安装。
注:可以通过热更新技术进行升级(我不会)。
引用插件:
#获取当前版本
package_info: ^0.4.3+2
#版本内更新
ota_update: ^2.4.1
#网页打开工具
url_launcher: ^5.7.10
#事件车
event_bus: ^1.1.1
1
2
3
4
5
6
7
8
直接上代码:
class VersionUpdate {
///检查是否需要更新
///是否需要升级--判断
static Future<bool> isUpdating() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String localVersion = packageInfo.version;
SpUtil.putString('localVersion', localVersion);
ApiResponse<VersionEntity> res =
await PersonalCenterAPI.updatingVersion(versionNo: packageInfo.version);
if (res.status == Status.COMPLETED) {
//如果获取服务器的版本号与当前应用程序的版本号对比,,不等那么提示升级(判断条件修改为符合自己的)
SpUtil.putObject('netVersionInfo', res.data.toJson());
if (res.data.currentVersion != localVersion) {
BottomSheetDialog.overLayDialog();
}
}
//return isUpdating;
}
///android--去android应用内下载更新 ---ios跳去App Store
static downloadNewVersion({String Url}) async {
if (Platform.isIOS) {
String url = Url;
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
} else if (Platform.isAndroid) {
String url = Url;
try {
// destinationFilename 是对下载的apk进行重命名
OtaUpdate().execute(url, destinationFilename: 'gzzoc.apk').listen(
(OtaEvent event) {
switch (event.status) {
case OtaStatus.DOWNLOADING: // 下载中
//TestEventBus().bus.fire(ProgressEvent(data: event.value));
ProgressEventBus().bus.fire(ProgressEvents(data: event.value));
print('status:${event.status},value:${event.value}');
break;
case OtaStatus.INSTALLING: //安装中
break;
case OtaStatus.PERMISSION_NOT_GRANTED_ERROR: // 权限错误
print('更新失败');
break;
default: // 其他问题
break;
}
},
);
} catch (e) {
print('更新失败');
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
overLayDialog
overLayDialog() {
OverlayState overlayState = Application.globalKey.currentState.overlay;
OverlayEntry overlayEntry;
overlayEntry = new OverlayEntry(builder: (context) {
return OverLayDialog(
overlayEntry: overlayEntry,
);
});
overlayState.insert(overlayEntry);
}
1
2
3
4
5
6
7
8
9
10
OverLayDialog名字太像了(忘记改了)
class OverLayDialog extends StatefulWidget {
final OverlayEntry overlayEntry;
OverLayDialog({this.overlayEntry});
@override
_OverLayDialogState createState() => _OverLayDialogState();
}
class _OverLayDialogState extends State<OverLayDialog> {
VersionEntity _netVersionInfo;
String _progress;
@override
void initState() {
// TODO: implement initState
super.initState();
_netVersionInfo =
VersionEntity.fromJson(SpUtil.getObject('netVersionInfo'));
ProgressEventBus().bus.on<ProgressEvents>().listen((event) {
if (!mounted) return;
setState(() {
_progress = event.data;
});
});
}
@override
Widget build(BuildContext context) {
return Material(
color: MyColors.black_cc00,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 40),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Stack(
alignment: Alignment.bottomCenter,
children: [
Stack(
children: [
Image.asset(
'assets/images/version_update.png',
),
Container(
margin: EdgeInsets.only(top: 60),
padding: EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'发现新版本',
style: TextStyle(
color: MyColors.white,
fontWeight: FontWeight.bold,
fontSize: 21),
),
Text('版本:${_netVersionInfo.currentVersion}',
style: TextStyle(
color: MyColors.white, fontSize: 16)),
Container(
height: MediaQuery.of(context).size.height / 3,
padding: EdgeInsets.only(top: 22, bottom: 22),
child: ListView.builder(
// itemCount: _content.length,
itemCount: _netVersionInfo?.description
?.split(';')
?.length,
itemBuilder: (context, index) {
return Padding(
padding:
EdgeInsets.symmetric(vertical: 7),
child: Text(
_netVersionInfo?.description
?.split(';')[index],
style: TextStyle(
color: MyColors.white,
fontSize: 15),
),
);
}),
)
],
),
),
],
),
Column(
children: [
_progress == null
? SizedBox.shrink()
: Text(
'$_progress%',
style: TextStyle(
color: MyColors.white, fontSize: 12),
),
InkWell(
onTap: () {
if (_progress == null) {
VersionUpdate.downloadNewVersion(
Url: _netVersionInfo?.url);
//'https://itunes.apple.com/cn/app/id414478124'
}
},
child: Container(
margin: EdgeInsets.only(
left: 20, right: 20, top: 5, bottom: 15),
decoration: BoxDecoration(
color: MyColors.white,
borderRadius:
BorderRadius.all(Radius.circular(50)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.symmetric(vertical: 10),
child: Text(
'立刻升级',
style: TextStyle(
color: MyColors.yellow_17,
fontSize: 17,
fontWeight: FontWeight.bold),
),
)
],
),
),
)
],
)
],
),
SizedBox(
height: 14,
),
_netVersionInfo?.forceFlag == '1'
? SizedBox.shrink()
: InkWell(
onTap: () {
widget?.overlayEntry?.remove();
},
child: Icon(
Icons.cancel_outlined,
color: MyColors.white,
size: 30,
),
)
],
),
)),
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
使用:我是在闪屏页的初始化中调用的,按照自己的需求改就行
//版本更新
VersionUpdate.isUpdating();
1
2
3
说明:SpUtil.putString是个工具,就是存储本地版本号而已,改SharedPreferences去存就行。
Application.globalKey.currentState.overlay:
class Application {
/// 全局key
static final GlobalKey<NavigatorState> globalKey =
GlobalKey<NavigatorState>();
1
2
3
4
注:适合刚入门看。缺少什么或者不懂的可以留言我补。刚接触flutter不久,各位指导指导。
————————————————
版权声明:本文为CSDN博主「_诸葛青」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/C201624141155/article/details/113759869
参考
//开始检测按钮
ElevatedButton(
onPressed: () {
//__getPackageInfo()返回值是Future,用then拆开获得当前版本号
_getPackageInfo().then((value) {
//当前版本号赋值给version,最新版本号暂设置在全局newVersion
version = value;
//引用CheckVersion类比较当前版本号和最新版本号大小
CheckVersion.isNewVersion(version, newVersion)
? _needUpdate()//需要更新
: _needNotUpdate();//不需要更新
});
},
child: Text('检测新版本'),
),
//返回当前版本号
_getPackageInfo() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String version = packageInfo.version;
return version;
}
是否需要更新
//需要更新Dialog
void _needUpdate() async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("版本检测!"),
content: Text("发现新的版本,是否更新!"),
actions: <Widget>[
TextButton(
child: Text("否"),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text("是"),
onPressed: () {
_downLoad();//引用下载方法
Navigator.pop(context);//取消dialog
})
],
);
});
}
//不需要更新Dialog
_needNotUpdate() async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('版本检测'),
content: Text('无需更新,已是最新版本!'),
actions: [
TextButton(
child: Text("好"),
onPressed: () {
Navigator.pop(context, 'Cancle');//取消dialog
},
),
],
);
});
}
开始执行下载方法
//下载打开文件
_downLoad() async {
var permission = await this._checkPermission();//检测是否有权限
//如果有权限,配置安装路径
if (permission) {
Directory? directory = await getExternalStorageDirectory();
String? _localPath;
//注意Flutter2.2以后的版本加入了Null safety
if (directory != null) {
_localPath = directory.path;
String _appName = "app-release.apk";
String _savePath = "$_localPath/$_appName";
String apkUrl = "https://www.tobutomi.top/app/app-release.apk";
//实例化Dio网络请求库
Dio dio = new Dio();
//实例化下载进度Dialog库
ProgressDialog pd = ProgressDialog(context: context);
pd.show(max: 100, msg: '正在下载...');
//使用dio.download进行下载
await dio.download(apkUrl, _savePath,
onReceiveProgress: (received, total) {
//下载进度
int progress = (((received / total) * 100).toInt());
pd.update(value: progress);
});
await OpenFile.open(_savePath,
type: "application/vnd.android.package-archive");
} else {
print("获取目录失败");
}
} else {
print("没有权限");
}
}
//检查权限_checkPermission
Future<bool> _checkPermission() async {
if (Theme.of(context).platform == TargetPlatform.android) {
final status = await Permission.storage.status;
if (status != PermissionStatus.granted) {
final result = await Permission.storage.request();
if (result == PermissionStatus.granted) {
return true;
}
} else {
return true;
}
}
return false;
}
完整代码
CheckVersion工具类
class CheckVersion {
static bool isNew = false;
static isNewVersion(version, newversion) {
List verList = version.split('.');
List newVerList = newversion.split('.');
if (int.parse(newVerList[0]) > int.parse(verList[0])) {
isNew = true;
} else if (int.parse(newVerList[0]) == int.parse(verList[0])) {
if (int.parse(newVerList[1]) > int.parse(verList[1])) {
isNew = true;
} else if (int.parse(newVerList[1]) == int.parse(verList[1])) {
if (int.parse(newVerList[2]) > int.parse(verList[2])) {
isNew = true;
}
}
}
return isNew;
}
}
主页代码
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:open_file/open_file.dart';
import 'package:dio/dio.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../components/CheckVersion.dart';
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
class AppVersionPage extends StatefulWidget {
AppVersionPage({Key? key}) : super(key: key);
_AppVersionPageState createState() => _AppVersionPageState();
}
class _AppVersionPageState extends State<AppVersionPage> {
//设置新版本号,可以存于云端
var newVersion = '1.0.0';
var version;
//需要更新
void _needUpdate() async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("版本检测!"),
content: Text("发现新的版本,是否更新!"),
actions: <Widget>[
TextButton(
child: Text("否"),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text("是"),
onPressed: () {
_downLoad();
Navigator.pop(context);
})
],
);
});
}
//不需要更新
_needNotUpdate() async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('版本检测'),
content: Text('无需更新,已是最新版本!'),
actions: [
TextButton(
child: Text("好"),
onPressed: () {
Navigator.pop(context, 'Cancle');
},
),
],
);
});
}
//获取版本号
_getPackageInfo() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String version = packageInfo.version;
return version;
}
//检查权限
Future<bool> _checkPermission() async {
if (Theme.of(context).platform == TargetPlatform.android) {
final status = await Permission.storage.status;
if (status != PermissionStatus.granted) {
final result = await Permission.storage.request();
if (result == PermissionStatus.granted) {
return true;
}
} else {
return true;
}
}
return false;
}
//下载打开文件
_downLoad() async {
var permission = await this._checkPermission();
if (permission) {
Directory? directory = await getExternalStorageDirectory();
String? _localPath;
//注意Flutter2.2以后的版本加入了Null safety
if (directory != null) {
_localPath = directory.path;
String _appName = "aaa.apk";
String _savePath = "$_localPath/$_appName";
String apkUrl = "https://www.tobutomi.top/app/app-release.apk";
Dio dio = new Dio();
ProgressDialog pd = ProgressDialog(context: context);
pd.show(max: 100, msg: '正在下载...');
await dio.download(apkUrl, _savePath,
onReceiveProgress: (received, total) {
int progress = (((received / total) * 100).toInt());
pd.update(value: progress);
});
await OpenFile.open(_savePath,
type: "application/vnd.android.package-archive");
} else {
print("获取目录失败");
}
} else {
print("没有权限");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("app升级演示"),
),
body: Center(
child: ElevatedButton(
onPressed: () {
_getPackageInfo().then((value) {
version = value;
CheckVersion.isNewVersion(version, newVersion)
? _needUpdate()
: _needNotUpdate();
});
},
child: Text('检测新版本'),
),
),
);
}
}