flutter 配置安卓的签名

背景

最近遇到一个需求,需要实现app的热更新,了解了一下热更新方案时间的时间有点久,就做了个app升级的过渡版本,然后遇到问题 真机安装遇到签名不一致的问题

如下

安装过程

版本升级的代码如下

Dart 复制代码
 ///版本更新检查
  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 复制代码
bash: keytool: command not found

在java环境目录 打开cmd 执行后 复制key.jks 到你的安卓目录下 (android/)

在安卓目录下(android/) 新增key.properties 文件

写入 密码是你自己设置的密码

bash 复制代码
storePassword=789asd
keyPassword=789asd
keyAlias=LH
storeFile=../key.jks

最后在你 (android/app) 下的build.gradle 配置 buildTypes

bash 复制代码
// 最上面
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"
            }
        }

    }
Dart 复制代码
flutter build apk --release

这样就解决了升级遇到的签名版本不一致的问题

相关推荐
学习前端的小z3 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
神仙别闹10 分钟前
基于C#和Sql Server 2008实现的(WinForm)订单生成系统
开发语言·c#
XINGTECODE11 分钟前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
天天扭码17 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶17 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺22 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端
zwjapple28 分钟前
typescript里面正则的使用
开发语言·javascript·正则表达式
小五Five29 分钟前
TypeScript项目中Axios的封装
开发语言·前端·javascript
小曲程序29 分钟前
vue3 封装request请求
java·前端·typescript·vue
前端每日三省31 分钟前
面试题-TS(八):什么是装饰器(decorators)?如何在 TypeScript 中使用它们?
开发语言·前端·javascript