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

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

相关推荐
神仙别闹33 分钟前
基于java的改良版超级玛丽小游戏
java
Dream_Snowar43 分钟前
速通Python 第三节
开发语言·python
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭1 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫1 小时前
泛型(2)
java
超爱吃士力架1 小时前
邀请逻辑
java·linux·后端
南宫生1 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石2 小时前
12/21java基础
java
拭心2 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
高山我梦口香糖2 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
李小白662 小时前
Spring MVC(上)
java·spring·mvc