一键实现Flutter应用版本更新
一键实现Flutter应用版本更新
演示

- 默认版本更新

- 支持后台更新

- 屏幕宽高比限制显示更新

- 强制更新

- 自定义更新提示弹窗样式

创建项目
flutter create 项目名
安装依赖
flutter_xupdate: ^2.0.3
Android设置
xupdate需要我们将android主题修改为AppCompat,打开文件:android/app/src/main/res/values/styles.xml,将LaunchTheme主题修改为Theme.AppCompat.Light.NoActionBar。
<resources>
<style name="LaunchTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
</resources>
初始化插件
- 调用FlutterXUpdate.init方法进行初始化
- 调用FlutterXUpdate.setErrorHandler方法设置错误监听
import 'package:flutter_xupdate/flutter_xupdate.dart';
///初始化
void initXUpdate() {
if (Platform.isAndroid) {
FlutterXUpdate.init(
///是否输出日志
debug: true,
///是否使用post请求
isPost: false,
///post请求是否是上传json
isPostJson: false,
///是否开启自动模式
isWifiOnly: false,
///是否开启自动模式
isAutoMode: false,
///需要设置的公共参数
supportSilentInstall: false,
///在下载过程中,如果点击了取消的话,是否弹出切换下载方式的重试提示弹窗
enableRetry: false
).then((value) {
updateMessage("初始化成功: $value");
}).catchError((error) {
print(error);
});
FlutterXUpdate.setErrorHandler(
onUpdateError: (Map<String, dynamic> message) async {
print(message);
setState(() {
_message = "$message";
});
});
} else {
updateMessage("ios暂不支持XUpdate更新");
}
}
更新应用
xupdate最主要的方法就是checkUpdate,在做好初始化和服务端的处理后,只需要一行代码即可完成在线更新,支持后台更新,静默安装需要有root权限,静默安装就算了,现在Android 的权限控制越来越多,很难做到静默安装了。我们有一些应用和一些设备的小厂合作,在出厂时就内置,这个时候用这个静默安装就很舒服了。
///默认App更新
void checkUpdateDefault() {
FlutterXUpdate.checkUpdate(url: _updateUrl);
}
///默认App更新 + 支持后台更新
void checkUpdateSupportBackground() {
FlutterXUpdate.checkUpdate(url: _updateUrl, supportBackgroundUpdate: true);
}
///调整宽高比显示的版本更新
void checkUpdateSupportBackgrounds() {
FlutterXUpdate.checkUpdate(url: _updateUrl, widthRatio: 0.6);
}
///自动模式, 如果需要完全无人干预,自动更新,需要root权限【静默安装需要】
void checkUpdateAutoMode() {
FlutterXUpdate.checkUpdate(url: _updateUrl, isAutoMode: true);
}
准备数据
对于在线更新的插件基本流程都是一致的,客户端在向服务器请求获取更新数据,服务端将最新的版本信息返回给客户端(一般都是json格式),客户端分析json文件,查看本地版本是不是已经过时了,如果过时则下载apk并进行安装,如果没有过时则放弃。这里能够扩展的业务有更新内容,是否强制更新等。xupdate也是这样一个过程,作者默认提供了一个json文件的格式包括对应的model,如果有特殊需求也支持自定义json格式。一般的业务默认的json就够用了。
默认的json内容
{
"Code": 0, //0代表请求成功,非0代表失败
"Msg": "", //请求出错的信息
"UpdateStatus": 1, //0代表不更新,1代表有版本更新,不需要强制升级,2代表有版本更新,需要强制升级
"VersionCode": 3, //编译版本号(唯一)
"VersionName": "1.0.2", //版本名(用于展示)
"ModifyContent": "1、优化api接口。\r\n2、添加使用demo演示。\r\n3、新增自定义更新服务API接口。\r\n4、优化更新提示界面。", //更新内容
"DownloadUrl": "https://raw.githubusercontent.com/xuexiangjys/XUpdate/master/apk/xupdate_demo_1.0.2.apk",// 文件下载地址
"ApkSize": 2048, //文件的大小(单位:kb)
"ApkMd5": "e2eedae8d50b4454dbf219ea426548a3" //md5值没有的话,就无法保证apk是否完整,每次都会重新下载。框架默认使用的是md5加密。
}
这里有一个apk的md5,作者对md5值的描述是这样的:
这里需要说明的是,这里填写的MD5值是APK文件进行MD5加密后的值,并不是对APK签名的MD5。框架默认使用的是MD5加密,如果你觉得不够安全,也可以使用其他加密方式,不过这可能涉及到原生的编码,详情参见:自定义文件加密校验器.
如果不想使用MD5的话就不需要配置这个字段,不过这样每次检查的话都会去重新下载APK,建议配置。
开始更新
1、创建文件夹及文件

import 'dart:io';
import 'package:flutter_xupdate/flutter_xupdate.dart';
import 'package:flutter/material.dart';
class Xupdate extends StatefulWidget {
const Xupdate({Key? key}) : super(key: key);
@override
State<Xupdate> createState() => _XupdateState();
}
class _XupdateState extends State<Xupdate> {
//初始化XUpdate
void initXUpdate() {
if (Platform.isAndroid) {
FlutterXUpdate.init(
//是否输出日志
debug: true,
//是否使用post请求
isPost: false,
//post请求是否是上传json
isPostJson: false,
//请求响应超时时间
timeout: 25000,
//是否开启自动模式
isWifiOnly: false,
//是否开启自动模式
isAutoMode: false,
//需要设置的公共参数
supportSilentInstall: false,
//在下载过程中,如果点击了取消的话,是否弹出切换下载方式的重试提示弹窗
enableRetry: false
)
.then((value) {
print("初始化成功: $value");
}).catchError((error) {
print(error);
});
FlutterXUpdate.setErrorHandler(
onUpdateError: (Map<String, dynamic>? message) async {
print(message);
});
} else {
debugPrint("ios暂不支持XUpdate更新");
}
}
@override
void initState(){
super.initState();
//初始化方法
initXUpdate();
}
//升级信息,也可以使用接口方式
final _updateUrl = "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cc878a75-2a2d-4a3c-abcf-2938e3f4037f/b27ac73b-d66b-4268-857a-e98ec34fc9f5.json";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('XUpdate演示'),
),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () {
FlutterXUpdate.checkUpdate(url: _updateUrl);
},
child: const Text('默认更新'),
),
ElevatedButton(
onPressed: () {
FlutterXUpdate.checkUpdate(
url: _updateUrl,
supportBackgroundUpdate: true,
);
},
child: const Text('支持后台更新'),
),
],
),
),
);
}
}
2、main.dart调用升级文件
import 'package:flutter/material.dart';
import 'package:flutter_star/xupdate/Xupdate.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
//这里调用升级文件
home: Xupdate(),
);
}
}
3、使用结果
默认APP更新

支持后台更新

启用后台更新

文件MD5值计算
使用Dart获取MD5也很简单。
import 'dart:io';
import 'package:crypto/crypto.dart';
void main() async {
var file = File(<Apk文件地址>);
print(md5.convert(file.readAsBytesSync()));
}
查看版本信息
引入插件
dependencies:
package_info_plus: ^1.4.2
编写获取信息的方法
void initVersionInfo() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
appName = packageInfo.appName;
packageName = packageInfo.packageName;
version = packageInfo.version;
buildNumber = packageInfo.buildNumber;
}
初始化数据
@override
void initState() {
super.initState();
Future.delayed(
Duration.zero,
() => setState(
() {
initVersionInfo();
},
),
);
initXUpdate();
}
展示数据
Text("appName: $appName"),
Text("packageName: $packageName"),
Text("version: $version"),
Text("buildNumber: $buildNumber"),