一、為什么需要?
在我們?nèi)粘J褂肁pp中經(jīng)常會看到有版本需要更新。這有有兩個用處:
1.通知用戶有新版本,并且有什么更新內(nèi)容;
2.在一些bug性要求強制更新的情況可以強制必須更新。
二、更新樣式是什么?


三、需要的插件
插件有下面四個。我使用的是當(dāng)前版本,讀者根據(jù)最新版本使用
#dio
dio: ^3.0.8
#更新插件
ota_update: ^2.2.1
#獲取app信息
package_info: ^0.4.0+14
#跳轉(zhuǎn)第三方
url_launcher: ^5.4.2
把上面代碼寫在pubspec.yaml文件的以下位置
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
#這里寫插件
執(zhí)行package get
四、主要代碼是什么?
-首先定義一個版本模型,下面的BaseModel只是定義了一個抽象類,這里你們可以去掉
class VersionModel extends BaseModel{
String version;
bool mandatory;
List<String> updateContent;
String iosAddress;
String androidAddress;
VersionModel.fromJson(Map<String, dynamic> json) : super.fromJson(json){
version=json['version'];
mandatory=json['mandatory'];
updateContent=List.from(json['updateContent']);
iosAddress=json['iosAddress'];
androidAddress=json['androidAddress'];
}
@override
Map<String, dynamic> toJson() {
return {
'version':version,
'mandatory':mandatory,
'updateContent':updateContent,
'iosAddress':iosAddress,
'androidAddress':androidAddress,
};
}
}
先是檢查版本的方法
///檢測當(dāng)前app版本
_getCurrentVersion()async{
PackageInfo packageInfo=await PackageInfo.fromPlatform();
var currentVersion=packageInfo.version;
return currentVersion;
}
///版本校驗
_checkVersion()async {
/// 獲得服務(wù)器版本
//這寫上獲取json的url,json格式按照定義的versionModel
String url='http://xxxxxxxxxxxxxxxxxxx/version.json'
var json = await Dio().get(url);
if(json==null){
//獲取版本失敗 網(wǎng)絡(luò)或者其他原因 退出App
//ToastUtil.showToast('獲取版本失敗');
await SystemChannels.platform.invokeMethod('SystemNavigator.pop');
}
serviceVersion=VersionModel.fromJson(json);
var currentVersion = await _getCurrentVersion();
print(currentVersion);
if(currentVersion==serviceVersion.version){
//驗證通過
_goNextPage();
}else{
//版本不符彈出對話框
_showUpdateDialog();
}
}
_showUpdateDialog(){
showDialog(
context: context,
barrierDismissible: false,
builder: (_){
List<Widget> contentList=[];
var style=TextStyle(fontSize: 15,);
contentList.addAll(serviceVersion.updateContent.map((item){
return Text(item,style: style,);
}).toList());
contentList.insert(0, Container(height: 0.4,color: Colors.black,margin: EdgeInsets.only(top: 5,bottom: 5),));
return CupertinoAlertDialog(
title:Text('版本更新',style:TextStyle(fontSize: 18,fontWeight: FontWeight.w600)),
content: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: contentList
),
),
actions: <Widget>[
FlatButton(
child: Text('取消'),
textColor: Colors.grey,
onPressed: serviceVersion.mandatory?null:(){
_goNextPage();
},
),
FlatButton(
child: Text('更新'),
textColor: Colors.blue,
onPressed: ()async{
if(Platform.isAndroid){
//安卓應(yīng)用內(nèi)下載
Navigator.pop(context);
tryOtaUpdate();
}else{
//ios 跳轉(zhuǎn)商店
if(await canLaunch(serviceVersion.iosAddress)){
await launch(serviceVersion.iosAddress);
}else{
throw 'Could not launch ';
}
}
},
)
],
);
}
);
}
下面是安卓后臺下載更新方法
Future<void> tryOtaUpdate() async {
try {
OtaUpdate()
.execute(serviceVersion.androidAddress, destinationFilename: 'task_app.apk')
.listen(
(OtaEvent event) {
setState(() => currentEvent = event);
},
);
} catch (e) {
print('Failed to make OTA update. Details: $e');
}
}
頁面可以如下展示。也可根據(jù)自己實際情況更換
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: currentEvent != null && serviceVersion != null ? AppBar(
title: const Text('更新應(yīng)用'),
) : null,
body: Center(
child: Container(
padding: EdgeInsets.only(left: 20, right: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Image.asset(
'assets/images/check_logo.png', height: 100, width: 100,),
Container(
height: 100,
//如果currentEvent不為空則展示加載條
child: currentEvent != null ? Column(
children: <Widget>[
double.tryParse(currentEvent.value) is double
? LinearProgressIndicator(
semanticsLabel: currentEvent.value,
value: double.tryParse(currentEvent.value) / 100,
semanticsValue: currentEvent.value,
)
: Container(),
Container(
child: Text(
'${currentEvent.status == OtaStatus.DOWNLOADING
? '下載中'
: (currentEvent.status == OtaStatus.INSTALLING
? '安裝中...'
: '')} ${(currentEvent.status == OtaStatus.DOWNLOADING
? ':'
: '')} ${currentEvent.value}${currentEvent.status ==
OtaStatus.DOWNLOADING ? '%' : ''} \n'),
margin: EdgeInsets.only(bottom: 50),
)
],
) : Container()
)
],
),
),
)
);
}
下面是我給的示例驗證version.json
{
"version": "1.0.3",
"mandatory": false,
"updateContent": ["1、修復(fù)了一些顯示問題", "2、新增搜索頁面", "3、項目管理可切換成員搜索", "4、項目過期顯示橙色"],
"iosAddress": "https://apps.apple.com/cn/app/tasktodo/id1498326734",
"androidAddress": "http://lc-sys.oss-cn-shanghai.aliyuncs.com/apk/task_s103.apk"
}
五、安卓和ios設(shè)置
ios因為是跳轉(zhuǎn)到appstore去更新沒什么需要設(shè)置的
安卓使用Ota_update插件還需要一些其他設(shè)置
-首先在項目android/app/src/main/AndroidManifest.xml文件中添加如下代碼
...以上省略,這段代碼主要是用于ota_update插件的
<provider
android:name="sk.fourq.otaupdate.OtaUpdateFileProvider"
android:authorities="${applicationId}.ota_update_provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
-然后在android/app/src/main/res文件夾內(nèi)新建文件夾xml再往里面添加一個filepaths.xml文件,內(nèi)容是
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_download" path="Download"/>
</paths>
到此有很多小伙伴就成功了。。但是這里面還有幾個大坑
六、還有哪些坑?
1、如果你安卓下載地址是http的那么恭喜你成功入坑。
安卓從sdk 27開始http訪問很多情況下會被禁止。如何做呢?
在上面的xml文件夾內(nèi)再新建一個文件network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
然后在AndroidManifest.xml的
<application
android:name="io.flutter.app.FlutterApplication"
android:label="task todo"
android:networkSecurityConfig="@xml/network_security_config"
...以下省略。添加上面一句用來執(zhí)行剛才添加的network_security_config.xml
然后大功告成。
2、有很多朋友這里會發(fā)現(xiàn)下載成功了。安裝卻失敗了,那么你又進(jìn)坑了。
我測試很多次發(fā)現(xiàn)這是模擬器的問題。模擬器無法直接安裝apk。你不用管。直接安裝到手機上去就行了。手機上可以安裝成功。