背景
最近遇到一个需求,需要实现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 falseminifyEnabled true// signingConfig signingConfigs.debugsigningConfig signingConfigs.releasendk{ // 必须加入这部分,否则可能导致编译成功的release包在真机中会闪退abiFilters "armeabi-v7a"}}debug {ndk {//这里要加上,否则debug包会出问题,后面三个为可选,x86建议加上不然部分模拟器回报错abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86"}}}
flutter build apk --release
这样就解决了升级遇到的签名版本不一致的问题