参考
功能点:
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';
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){
UpdateDialog.showUpdateDialog(context, '1.修复已知bug\n2.优化用户体验', false);
}else if(Platform.isIOS){
}
}
}
重点说明:
屏蔽物理返回键(因为强更的时候点击返回键,弹窗会消失)
barrierDismissible: false,
4.点击弹窗外透明区域时,弹窗不消失
return WillPopScope(
child: UpdateDialog(
upDateContent: mUpdateContent, isForce: mIsForce),
onWillPop: _onWillPop);
static Future<bool> _onWillPop() async {
return false;
}
- 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
- 155
参考
前言: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();
_checkVersionCode();
});
}
});
}
}
4.比较服务器的版本号跟当前的版本号,来判断要不要升级APP应用程序
void _checkVersionCode() {
PackageInfo.fromPlatform().then((PackageInfo packageInfo) {
var _currentVersionCode = packageInfo.version;
int serviceVersionCode = int.parse(_serviceVersionCode);
int currentVersionCode = int.parse(_currentVersionCode);
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: () {
launch(_serviceVersionApp);
Navigator.of(context).pop();
},
)
],
);
});
}else{
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: () {
launch(_serviceVersionApp);
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();
var timeEnd = DateTime.now().millisecondsSinceEpoch;
var timeStart = SpUtil.getInt(Constants.timeStart);
if (timeStart == 0) {
_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();
_checkVersionCode();
});
}
});
}
_checkVersionCode() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String _currentVersionCode = packageInfo.version;
int serviceVersionCode = int.parse(_serviceVersionCode);
int currentVersionCode = int.parse(_currentVersionCode);
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: () {
launch(_serviceVersionApp);
Navigator.of(context).pop();
},
)
],
);
});
}else{
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: () {
launch(_serviceVersionApp);
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(
appBar: _buildAppBar(),
body: getScreen()
));
}
}
8.总结
当有新版本须要升级时,客户端会"版本更新"弹出对话框,Android用户跳转到 Google Play 官网去下载APK,而iOS用户跳转到 App Store 官网下载。APP版本更新的功能已经实现,欢迎你们围观。若是有什么疑问的话,能够留言联系我哦!
- 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
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
参考
升级说明:
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();
}
}
}
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 {
OtaUpdate().execute(url, destinationFilename: 'gzzoc.apk').listen(
(OtaEvent event) {
switch (event.status) {
case OtaStatus.DOWNLOADING:
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() {
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: _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);
}
},
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 {
static final GlobalKey<NavigatorState> globalKey =
GlobalKey<NavigatorState>();
1
2
3
4
注:适合刚入门看。缺少什么或者不懂的可以留言我补。刚接触flutter不久,各位指导指导。
————————————————
版权声明:本文为CSDN博主「_诸葛青」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https:
- 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
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443
- 444
- 445
- 446
- 447
- 448
- 449
- 450
- 451
- 452
- 453
- 454
- 455
- 456
- 457
- 458
- 459
- 460
- 461
- 462
- 463
- 464
- 465
- 466
- 467
- 468
- 469
- 470
- 471
- 472
- 473
- 474
- 475
- 476
- 477
- 478
- 479
- 480
- 481
- 482
- 483
- 484
- 485
- 486
- 487
- 488
参考
ElevatedButton(
onPressed: () {
_getPackageInfo().then((value) {
version = value;
CheckVersion.isNewVersion(version, newVersion)
? _needUpdate()
: _needNotUpdate();
});
},
child: Text('检测新版本'),
),
_getPackageInfo() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String version = packageInfo.version;
return 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');
},
),
],
);
});
}
开始执行下载方法
_downLoad() async {
var permission = await this._checkPermission();
if (permission) {
Directory? directory = await getExternalStorageDirectory();
String? _localPath;
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 = 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("没有权限");
}
}
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;
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('检测新版本'),
),
),
);
}
}
- 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
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282