第一步 导入三个库
path_provider: ^1.1.0 #文件路径
ota_update: ^4.0.1 #下载文件
open_file: ^2.0.3 #打开文件
然后pug get下
第二步 配置安卓AndroidManifest
1.添加provider
<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>
2.添加权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
第三步 widget中下载文件
class UpdaterAppPage extends BaseStatefulWidget {
final Widget child;
const UpdaterAppPage(this.child);
@override
BaseStatefulWidgetState<BaseStatefulWidget> getState() {
return UpdaterAppApageState();
}
}
class UpdaterAppApageState extends BaseStatefulWidgetState<UpdaterAppPage>
with UpdateCallBack {
var _serviceVersionCode,
_serviceVersionContent,
_serviceVersionPlatform,
_type,
_serviceVersionApp;
@override
Widget build(BuildContext context) {
return widget.child;
}
@override
void initState() {
super.initState();
_getNewVersionAPP();
}
//执行版本更新的网络请求
_getNewVersionAPP() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String _currentVersionCode = packageInfo.version;
var map = HashMap<String, dynamic>();
map["appVersion"] = _currentVersionCode; //版本号
map["clientType"] = Platform.isAndroid ? 0 : 1; //获取设备类型 0安卓 1 ios
TeamService.requestUpgrade(map, (response) async {
if (response != null) {
setState(() {
Data data = response.data;
_serviceVersionCode = data.lastVersion; //版本号
_serviceVersionContent = data.content; //版本名称
_serviceVersionApp = data.downloadUrl; //下载的URL
_type = data.type;
if (_type != 0) {
_showNewVersionAppDialog();
}
});
}
}, (error) async {});
}
var downLoading = "立即更新";
var _setState;
BuildContext? buildContext;
//弹出"版本更新"对话框
Future<void> _showNewVersionAppDialog() async {
showGeneralDialog(
context: context,
pageBuilder: (context, anim1, anim2) {
buildContext = context;
return WillPopScope(
child:
UpdateWidget(this, _type, downLoading, _serviceVersionContent),
onWillPop: () async {
return Future.value(_type==1?false:true);
});
},
barrierColor: Colors.grey.withOpacity(.4),
barrierDismissible: _type==1?false:true,
barrierLabel: "",
transitionDuration: Duration(milliseconds: 125),
);
}
@override
void callBack() {
_downLoad();
}
@override
void dismiss() {
if (buildContext != null) {
Navigator.pop(buildContext!);
}
}
//下载并打开文件
_downLoad() async {
// 获取APP安装路径
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
if (Platform.isIOS) {
String url =
'https://apps.apple.com/cn/app/%E9%87%8F%E5%8C%96%E4%BA%91/id1558978023'; //到时候换成自己的应用的地址
// 通过url_launcher插件来跳转AppStore
// if (await canLaunch(url)){
launch(url);
// }else {
// throw 'Could not launch $url';
// }
} else if (Platform.isAndroid) {
var fileName = "scr_app.apk";
try {
try {
//LINK CONTAINS APK OF FLUTTER HELLO WORLD FROM FLUTTER SDK EXAMPLES
OtaUpdate()
.execute(
_serviceVersionApp,
// OPTIONAL
destinationFilename: fileName,
//OPTIONAL, ANDROID ONLY - ABILITY TO VALIDATE CHECKSUM OF FILE:
)
.listen(
(OtaEvent event) {
print("${event.value}|${event.status}");
switch (event.status) {
case OtaStatus.DOWNLOADING: //下载中
eventBus
.fire(EventFn(EventConstant.downLoading, event.value));
break;
case OtaStatus.INSTALLING:
eventBus.fire(EventFn(EventConstant.downSuccess, ""));
OpenFile.open("${appDocPath}/${fileName}");
break;
case OtaStatus.PERMISSION_NOT_GRANTED_ERROR:
CommonToast.show("由于缺少权限,无法继续");
break;
default:
eventBus.fire(EventFn(EventConstant.downError, ""));
break;
}
},
);
} catch (e) {
print('Failed to make OTA update. Details: $e');
}
} catch (e) {
print('更新失败,请稍后再试');
}
}
}
}
上边的对话框是我自己自定义的 我也贴下代码
class UpdateWidget extends BaseStatefulWidget {
UpdateCallBack update;
int type;
String downLoading;
String content;
UpdateWidget(this.update, this.type, this.downLoading, this.content);
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@override
BaseStatefulWidgetState<BaseStatefulWidget> getState() {
return UpdateWidgetState();
}
}
class UpdateWidgetState extends BaseStatefulWidgetState<UpdateWidget> {
var downLoading = "立即下载";
bool isClick = false; //默认可以点击 下载中无法再次点击
var eventBusFn;
@override
void initState() {
super.initState();
eventBusFn = eventBus.on<EventFn>().listen((event) {
//全局通知接收器
if (event.eventCode == EventConstant.downLoading) {
//下载中
isClick = true;
downLoading = "正在下载中..." + event.eventMsg + "%";
stateSetter(() {});
} else if (event.eventCode == EventConstant.downSuccess) {
//下载完成
isClick = false;
setState(() {
downLoading = "已下载完成";
});
} else if (event.eventCode == EventConstant.downSuccess) {
//失败
setState(() {
downLoading = "下载失败";
});
isClick = false;
}
});
}
var count = 0;
var _list = [const Color(0xff4E46F4), const Color(0xff3241CC)];
var stateSetter;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: EdgeInsets.only(left: kScale(52), right: kScale(52)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: double.infinity,
child: Image.asset(
'assets/images/icon_update_head.png',
fit: BoxFit.fitWidth,
),
),
Container(
transform: Matrix4.translationValues(0.0, -2.0, 0.0),
decoration: BoxDecoration(
color: kColor.white,
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(25),
bottomRight: Radius.circular(25))),
child: Column(
children: [
Container(
margin: EdgeInsets.only(top: kScale(22),left: kScale(15),right: kScale(15)),
alignment: Alignment.center,
color: kColor.white,
width: double.infinity,
child: Text(
widget.content,
style:
TextStyle(fontSize: kScale(16), color: kColor.tabColor),
),
),
GestureDetector(
onTap: () {
if (isClick) return;
if (widget.update != null) {
widget.update.callBack();
}
},
child: Container(
decoration: BoxDecoration(
border: Border.all(color: kColor.update_border),
gradient: LinearGradient(colors: _list),
borderRadius: BorderRadius.circular(13)),
width: double.infinity,
margin: EdgeInsets.only(left: kScale(15),right: kScale(15),top: kScale(40),bottom: kScale(15)),
height: kScale(45),
child: StatefulBuilder(builder: (context, stateSetter) {
this.stateSetter = stateSetter;
return
Container(
margin: EdgeInsets.only(
left: kScale(21), right: kScale(21)),
height: kScale(45),
alignment: Alignment.center,
child: Text(
downLoading,
style: TextStyle(
fontSize: kScale(17), color: kColor.white),
),
)
;
}),
),
)
,
Visibility(
visible: widget.type!=1, //强制升级不显示
child: GestureDetector(onTap: (){
if (widget.update != null) {
widget.update.dismiss();
}
},child: Container(
color: kColor.white,
width: double.infinity,
margin: EdgeInsets.only(bottom: kScale(17.5)),
child: Center(
child: Text(
'退出',
style: TextStyle(
fontSize: kScale(15), color: kColor.exit),
),
),
),))
],
),
)
],
),
);
}
}
abstract class UpdateCallBack {
void callBack();
void dismiss();
}
通知使用的eventBus 你也可以用别的
接下来就是使用 找到main
嵌套在Scaffold 外边 我得BaseScaffold我得基类 也说明下,害怕小白不知道 这样大概就可以下载了升级了 接口需要后台支持才能升级的
IOS 只需要打开浏览器 打开appStore就行了 主要是安卓 权限获取 文件下载。
就到这了