赞
踩
背景
最近遇到一个需求,需要实现app的热更新,了解了一下热更新方案时间的时间有点久,就做了个app升级的过渡版本,然后遇到问题 真机安装遇到签名不一致的问题
如下
安装过程
版本升级的代码如下
- ///版本更新检查
- static Future<VersionEntity> checkVersionUpdate() async {
- if (isWeb) {
- return VersionEntity(need: false);
- }
-
- PackageInfo packageInfo = await PackageInfo.fromPlatform();
- String version = packageInfo.version;
-
- // String jsonStr = await rootBundle.loadString('assets/json/version.json');
- // Map<String, dynamic> jsonData = json.decode(jsonStr);
- Map<String, dynamic> jsonData = await getVersion();
- VersionEntity versionEntity = VersionEntity.fromJson(jsonData);
-
- Version latestVersion = Version.parse(versionEntity.version ?? version);
- Version currentVersion = Version.parse(version);
- print(1);
- if (latestVersion > currentVersion) {
- _toUpdate(versionEntity);
- } else {
- return VersionEntity(need: false);
- }
-
- /// 非强制更新
- // if (versionEntity.data!.need! && !(versionEntity.data!.necessary!)) {
- // _toUpdate(versionEntity);
- // } // 强制更新
- // else if (versionEntity.data!.need! && versionEntity.data!.necessary!) {
- // _toUpdate(versionEntity);
- // } else {
- // // KLogUtil.d('无需更新');
- // }
-
- return versionEntity;
- }
-
- ///版本更新弹窗
- static _toUpdate(VersionEntity versionEntity) {
- // 进度
- String progress = '';
- double downloadProgress = 0.0;
- bool downloadStart = false;
- // 禁止返回
- bool disBack = versionEntity.necessary!;
- Get.bottomSheet(
- isDismissible: !(versionEntity.necessary!),
- enableDrag: !(versionEntity.necessary!),
- StatefulBuilder(
- builder: (context, state) {
- String fileAddress = '';
- return WillPopScope(
- onWillPop: () => _onBackPressed(disBack),
- child: AppToast.bottomSheetContainer(
- padding: EdgeInsets.fromLTRB(20.w, 5.h, 20.w, 20.h),
- height: 429.h,
- bgColor: const Color(0xFF25272B),
- child: Column(
- children: [
- Container(
- width: 36.w,
- height: 4.h,
- decoration: BoxDecoration(
- color: versionEntity.necessary!
- ? Colors.transparent
- : const Color(0xFF3B3D40),
- borderRadius: BorderRadius.circular(3.r),
- ),
- ),
- 10.verticalSpace,
- Assets.images.versionUpdate
- .image(width: 100.r, height: 100.r),
- Padding(
- padding: EdgeInsets.symmetric(vertical: 20.h),
- child: Text(
- "Update to ${versionEntity.version}",
- style: TextStyle(
- color: Colors.white,
- fontSize: 16.sp,
- ),
- ),
- ),
- Padding(
- padding: EdgeInsets.symmetric(vertical: 5.h),
- child: Row(
- children: [
- Text(
- "更新内容:",
- style: TextStyle(
- color: Colors.white,
- fontSize: 14.sp,
- ),
- ),
- ],
- ),
- ),
- Expanded(
- child: ListView.builder(
- itemCount: versionEntity.contents?.length ?? 0,
- itemBuilder: (context, index) {
- return Text(
- versionEntity!.contents![index],
- style: TextStyle(
- color: Colors.grey,
- fontSize: 13.sp,
- ),
- );
- },
- ),
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- versionEntity.necessary == false && disBack == false
- ? Expanded(
- child: SizedBox(
- height: 56.h,
- child: ElevatedButton(
- onPressed: () {
- /// 每天弹一次更新
- Get.back();
- },
- style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all(
- const Color(0xFF25272B)),
- shape: MaterialStateProperty.all(
- RoundedRectangleBorder(
- borderRadius:
- BorderRadius.circular(16.r),
- ),
- ),
- ),
- child: Text(
- "Not Now ",
- style: TextStyle(
- color: const Color(0xFF25272B),
- fontSize: 14.sp,
- fontWeight: FontWeight.bold,
- ),
- ),
- ),
- ),
- )
- : Container(),
- versionEntity.necessary == false && disBack == false
- ? SizedBox(width: 15.w)
- : Container(),
- Visibility(
- visible: progress == '',
- child: Expanded(
- child: SizedBox(
- height: 56.h,
- child: ElevatedButton(
- onPressed: () async {
- if (Platform.isIOS) {
- InstallPlugin.install(iosAppStoreUrl);
- // AppInstaller.goStore(
- // iosAppStoreUrl, "id1375433239",
- // review: true);
- return;
- }
- if (progress == '') {
- state(() {
- downloadStart = true;
- });
- disBack = true; //开始下载后禁止退出弹窗
- final filePath =
- await getExternalStorageDirectory();
- fileAddress = '${filePath!.path}/app-LH.apk';
- try {
- Dio dio = Dio(
- BaseOptions(
- connectTimeout:
- const Duration(milliseconds: 10000),
- receiveTimeout: const Duration(
- milliseconds: 100000),
- sendTimeout:
- const Duration(milliseconds: 10000),
- ),
- );
- await dio.download(
- versionEntity.url!,
- fileAddress,
- onReceiveProgress: (received, total) {
- if (total != -1) {
- state(() {
- progress =
- "${(received / total * 100).toStringAsFixed(2)}%";
- downloadProgress = received / total;
- });
- }
- },
- ).then(
- (response) async {
- if (response.statusMessage == 'OK') {
- // AppInstaller.installApk(fileAddress);
- InstallPlugin.install(fileAddress);
- // await AppInstaller.installApk(
- // fileAddress);
- } else {
- AppToast.toast(
- stateType: StateType.error,
- tips: "Failed to download");
- disBack = false;
- }
- },
- );
- } catch (e) {
- print(e);
- }
- }
- },
- style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all(
- const Color(0xFF4677FF)),
- shape: MaterialStateProperty.all(
- RoundedRectangleBorder(
- borderRadius:
- BorderRadius.circular(16.r)),
- ),
- ),
- child: downloadStart
- ? CircularProgressIndicator(
- valueColor: const AlwaysStoppedAnimation(
- Colors.white),
- backgroundColor:
- Colors.white.withOpacity(.1),
- )
- : Text("Update",
- style: TextStyle(
- fontSize: 14.sp,
- fontWeight: FontWeight.bold,
- color: Colors.white,
- )),
- ),
- ),
- ),
- ),
- Visibility(
- visible: progress != '',
- child: Expanded(
- child: Container(
- decoration: BoxDecoration(
- color: Colors.white.withOpacity(.1),
- borderRadius: BorderRadius.circular(16.r),
- ),
- clipBehavior: Clip.hardEdge,
- child: Stack(
- alignment: AlignmentDirectional.center,
- children: [
- InkWell(
- child: SizedBox(
- height: 56.h,
- width: double.infinity,
- child: LinearProgressIndicator(
- value: downloadProgress,
- backgroundColor: Colors.transparent,
- valueColor: const AlwaysStoppedAnimation(
- Color(0xFF4677FF)),
- ),
- ),
- onTap: () async {
- if (progress == "100.00%") {
- await InstallPlugin.install(fileAddress);
- }
- },
- ),
- Text(
- progress == ''
- ? "Update"
- : (progress == "100.00%"
- ? "安装app"
- : progress),
- style: TextStyle(
- fontSize: 14.sp,
- fontWeight: FontWeight.bold,
- ))
- ],
- ),
- ),
- ),
- ),
- ],
- ),
- ],
- ),
- ),
- );
- },
- ),
- );
- }
-
- static Future<bool> _onBackPressed(bool necessary) async {
- // 强更 禁止退出弹窗
- if (necessary) {
- return false;
- } else {
- return true;
- }
- }
-
-
-
- class VersionEntity {
- bool? necessary;
- bool? need;
- String? version;
- String? url;
- List<String>? contents;
-
- VersionEntity({this.necessary, this.need, this.version, this.url});
-
- VersionEntity.fromJson(Map<String, dynamic> json) {
- necessary = json['necessary'];
- need = json['need'];
- version = json['version'];
- url = json['url'];
- contents = json['contents'].cast<String>();
- }
-
- Map<String, dynamic> toJson() {
- final Map<String, dynamic> data = <String, dynamic>{};
- data['necessary'] = necessary;
- data['need'] = need;
- data['version'] = version;
- data['url'] = url;
- data['contents'] = contents;
- return data;
- }
- }

下面是解决签名不一致的问题 解决方案
keytool -genkey -v -keystore ./key.jks -keyalg RSA -keysize 2048 -validity 20000 -alias HL
很多会遇到 原因是keytool 是java的库 需要配置java环境 或者 在java目录下进行操作
bash: keytool: command not found
在java环境目录 打开cmd 执行后 复制key.jks 到你的安卓目录下 (android/)
在安卓目录下(android/) 新增key.properties 文件
写入 密码是你自己设置的密码
- storePassword=789asd
- keyPassword=789asd
- keyAlias=LH
- storeFile=../key.jks
最后在你 (android/app) 下的build.gradle 配置 buildTypes
- // 最上面
- def keystorePropertiesFile = rootProject.file("key.properties")
- def keystoreProperties = new Properties()
- keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
-
-
-
- //签名信息
- signingConfigs {
- release {
- keyAlias keystoreProperties['keyAlias']
- keyPassword keystoreProperties['keyPassword']
- storeFile file(keystoreProperties['storeFile'])
- storePassword keystoreProperties['storePassword']
- }
- }
-
-
- buildTypes {
- release {
- // TODO: Add your own signing config for the release build.
- // Signing with the debug keys for now, so `flutter run --release` works.
- debuggable false
- minifyEnabled true
- // signingConfig signingConfigs.debug
- signingConfig signingConfigs.release
- ndk{ // 必须加入这部分,否则可能导致编译成功的release包在真机中会闪退
- abiFilters "armeabi-v7a"
- }
- }
- debug {
- ndk {
- //这里要加上,否则debug包会出问题,后面三个为可选,x86建议加上不然部分模拟器回报错
- abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86"
- }
- }
-
- }

flutter build apk --release
这样就解决了升级遇到的签名版本不一致的问题
生成签名
keytool -genkeypair -alias key -keyalg RSA -keypass 123456 -storepass 123456 -validity 3650 -keystore key.jks
-genkey
:表示要生成一个密钥
-alias
:后跟密钥的别名 可以设置给项目名字 对应 keyAlias
-keyalg
:使用的密钥算法,这里使用的是 RSA
-keysize
:密钥的长度,这里是 2048 位
-keystore
:指定密钥库的文件名和类型,这里是 key.jks
-validity
:密钥的有效期,这里是 3650 天
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。