手机app软件更新(android应用版本更新策略)手机机软件 / 手机软件更新策略分析...

wufei123 发布于 2024-07-01 阅读(2)

开发中对版本进行检查并更新的需求基本是所有应用必须有的功能,可是在实际开发中有些朋友就容易忽略一些细节版本更新的基本流程:一般是将本地版本告诉服务器,服务器经过相关处理会返回客户端相关信息,告诉客户端需不需要更新,如果需要更新是强制更新还是非强制更新。

客户端得到服务器返回的相关信息后再进一步做逻辑处理强制更新:一般的处理就是进入应用就弹窗通知用户有版本更新,弹窗可以没有取消按钮并不能取消这样用户就只能选择更新或者关闭应用了,当然也可以添加取消按钮,但是如果用户选择取消则直接退出应用。

非强制更新一般的处理是在应用的设置中添加版本检查的操作,如果用户主动检查版本则弹窗告知用户有版本更新这时用户可以取消或者更新功能实际是比较简单清晰的,但之所以写这篇文章,是因为在我们公司的一个项目中,我把这个模块分给了一个有着4年工作经验的哥们编写,最后这哥们花了2个小时做完了。

我还想这哥们写得挺快,效率很高嘛,结果一测试发现问题不少:进入首页前关闭网络,进入后刷新界面发现强制更新提醒没有弹窗再进入其它界面也没有任何更新提醒在正常更新时点击确定更新,没有判断网络状态(wifi,移动网络)直接下载apk文件,如果用户在移动网络下将耗费非常多的流量,直接影响用户体验

下载过程在应用内没有进度条提醒,通知栏也没有进度提醒apk文件下载过程中,如果强制结束应用,下载被中断apk如果正常下载下来,弹出了安装界面,这时如果用户取消了安装回到应用,在需要强制更新的情况下并没有再次弹窗阻止用户进行任何其它操作,失去了强制更新的意义

首先声明下,我这丝毫没有吐槽的意思哟,只是想说作为一个合格的程序员大家最起码需要做到思维严谨这点,在有能力的情况下对用户体验能提点建议最好自己写的代码一定要经过严格测试再交付,不要指望测试人员帮你测试再去修改,你要知道现在很多公司是没有专业的测试人员甚至是没有测试人员的哟。

针对以上问题出现的原因分析及解决方案如下:对于1,2问题很明显他把检查更新的工作只写在了应用的首页(比如MainActivity)中了,在其它任何界面并没有检查更新的操作解决方案 每个界面都需要检查更新,当然咱们不能在每个Activity中都复制粘贴一样的代码。

这时定义一个BaseActivity,所有其它Activity都从它继承就显得很有价值了可以把检查更新的操作放到BaseActivity的相关方法中,比如放在onResume中,这样每当显示一个界面时都将执行检查更新的操作。

对于5问题,如果把下载的操作放在了Activity中进行,如果应用意外终止或者强制退出应用,则下载线程也将被终止解决方案 可以将下载任务放到Service中执行,这样即使应用被终止Service一样有保活机制(startForeground)让Service的任务有很大的机会继续得以执行

对于6问题,如果检查更新的操作没有在Activity的resume时再次执行,则回到Activity自然也就没有检查更新并弹窗了解决方案 在Activity的onResume中继续检查更新,如果是强制更新则弹窗阻止用户进行其它操作

对于3,4问题,我倒是觉得不是程序问题而是态度问题,实际加入非wifi和进度显示的功能非常简单整体解决方案定义Service类,比如VersionUpdateService.java主要提供版本检查及文件下载操作。

定义VersionUpdateHelper类,用来使用Service并提供和前台Activity的交互如果大家对Service的使用还有问题(需要频繁更新前台ui等),建议大家阅读android图片压缩上传系列-service篇这篇文章先做了解。

核心代码如下:publicclassVersionUpdateServiceextendsService{ private LocalBinder binder = new LocalBinder;

private DownLoadListener downLoadListener;//下载任务监听回调接口privateboolean downLoading; privateint progress;

private NotificationManager mNotificationManager; private NotificationUpdaterThread notificationUpdaterThread;

private Notification.Builder notificationBuilder; privatefinalint NOTIFICATION_ID = 100; private

VersionUpdateModel versionUpdateModel; private CheckVersionCallBack checkVersionCallBack;//检查结果监听回调接口

publicinterfaceDownLoadListener{ void begain; voidinProgress(float progress, long total)

; voiddownLoadLatestSuccess(File file); void downLoadLatestFailed; } publicinterface

CheckVersionCallBack{ void onSuccess; void onError; } ... privateclassNotificationUpdaterThread

extendsThread{ @Overridepublicvoid run { while (true) { notificationBuilder.setContentTitle(

"正在下载更新" + progress + "%"); // the label of the entry notificationBuilder.setProgress(100, progress,

false); ... } } } privatevoid starDownLoadForground { //创建通知栏 notificationBuilder =

new Notification.Builder(this); ... Notification notification = notificationBuilder.getNotification; startForeground(NOTIFICATION_ID, notification); }

privatevoid stopDownLoadForground { stopForeground(true); } //执行版本检查任务publicvoid doCheckUpdateTask {

//获取本定版本号finalint currentBuild = AppUtil.getVersionCode(this); //调用版本检查接口 ApiManager.getInstance.versionApi.upgradeRecords(currentBuild,

new RequestCallBack { @OverridepublicvoidonSuccess(Headers headers, String response){ versionUpdateModel = JSON.parseObject(response, VersionUpdateModel

.class); ... if (checkVersionCallBack != null) checkVersionCallBack.onSuccess; } @Overridepublic

voidonError(int code, String response){ ... } }); } publicvoid doDownLoadTask { starDownLoadForground;

//启动通知栏进度更新线程 notificationUpdaterThread = new NotificationUpdaterThread; notificationUpdaterThread.start;

//文件下载存放路径final File fileDir = FolderUtil.getDownloadCacheFolder; ... downLoading = true

; if (downLoadListener != null) { downLoadListener.begain; } NetManager.getInstance.download(url, fileDir.getAbsolutePath,

new DownloadCallBack { @OverridepublicvoidinProgress(float progress_, long total){ ... //执行进度更新if (downLoadListener !=

null) downLoadListener.inProgress(progress_, total); } @OverridepublicvoidonSuccess(Headers headers, String response)

{ //执行成功回调 ... installApk(destFile, VersionUpdateService.this); } @OverridepublicvoidonError(int

code, String response){ ... //执行失败回调 } }); } //安装apkpublicvoidinstallApk(File file, Context context)

{ ... } }publicclassVersionUpdateHelperimplementsServiceConnection{ private Context context;

private VersionUpdateService service; private AlertDialog waitForUpdateDialog; private ProgressDialog progressDialog;

privatestaticboolean isCanceled; privateboolean showDialogOnStart; publicstaticfinalint NEED_UPDATE =

2; publicstaticfinalint DONOT_NEED_UPDATE = 1; publicstaticfinalint CHECK_FAILD = -1; public

staticfinalint USER_CANCELED = 0; private CheckCallBack checkCallBack; publicinterfaceCheckCallBack

{ voidcallBack(int code); } publicVersionUpdateHelper(Context context){ this

.context = context; } publicvoid startUpdateVersion { if (isCanceled) return;

if (isWaitForUpdate || isWaitForDownload) { return; } if (service == null && context !=

null) { context.bindService(new Intent(context, VersionUpdateService.class), this, Context.BIND_AUTO_CREATE

); } } publicvoid stopUpdateVersion { unBindService; } privatevoid cancel { isCanceled =

true; unBindService; } privatevoid unBindService { if (isWaitForUpdate || isWaitForDownload) {

return; } if (service != null && !service.isDownLoading) { context.unbindService(this

); service = null; } } ... privatevoid showNotWifiDownloadDialog { final

AlertDialog.Builder builer = new AlertDialog.Builder(context); builer.setTitle("下载新版本"); builer.setMessage(

"检查到您的网络处于非wifi状态,下载新版本将消耗一定的流量,是否继续下载?"); builer.setNegativeButton("以后再说", new DialogInterface.OnClickListener {

@OverridepublicvoidonClick(DialogInterface dialog, int which){ ... //如果是强制更新 exit appif (mustUpdate) { MainApplication.getInstance.exitApp; } } }); builer.setPositiveButton(

"继续下载", new DialogInterface.OnClickListener { @OverridepublicvoidonClick(DialogInterface dialog, int

which){ dialog.cancel; service.doDownLoadTask; } }); ... } @Overridepublic

voidonServiceConnected(ComponentName name, IBinder binder){ service = ((VersionUpdateService.LocalBinder) binder).getService; service.setCheckVersionCallBack(

new VersionUpdateService.CheckVersionCallBack { @Overridepublicvoid onSuccess { VersionUpdateModel versionUpdateModel = service.getVersionUpdateModel;

//EventBus控制更新红点提示 EventBus.getDefault.postSticky(versionUpdateEvent); if (!versionUpdateModel.isNeedUpgrade) {

if(checkCallBack != null){ checkCallBack.callBack(DONOT_NEED_UPDATE); } cancel; return; } if (!versionUpdateModel.isMustUpgrade && !showDialogOnStart) { cancel;

return; } if(checkCallBack != null){ checkCallBack.callBack(NEED_UPDATE); } final AlertDialog.Builder builer = ...

//更新提示对话框 builer.setPositiveButton("立即更新", new DialogInterface.OnClickListener { @Overridepublicvoid

onClick(DialogInterface dialog, int which){ dialog.cancel; if (NetUtil.isWifi(context)) { service.doDownLoadTask; }

else { showNotWifiDownloadDialog; } } }); //当点取消按钮时进行登录if (!versionUpdateModel.isMustUpgrade) { builer.setNegativeButton(

"稍后更新", new DialogInterface.OnClickListener { publicvoidonClick(DialogInterface dialog, int which){ dialog.cancel; cancel;

if(checkCallBack != null){ checkCallBack.callBack(USER_CANCELED); } } }); } builer.setCancelable(

false); waitForUpdateDialog = builer.create; waitForUpdateDialog.show; } @Overridepublicvoid onError { unBindService; ... } }); service.setDownLoadListener(

new VersionUpdateService.DownLoadListener { @Overridepublicvoid begain { VersionUpdateModel versionUpdateModel = service.getVersionUpdateModel;

if (versionUpdateModel.isMustUpgrade) { progressDialog = ...//生成进度条对话框 } } @OverridepublicvoidinProgress

(float progress, long total){ ...//更新进度条 } @OverridepublicvoiddownLoadLatestSuccess(File file){ ...

//执行成功处理 unBindService; } @Overridepublicvoid downLoadLatestFailed { ...//执行失败处理 unBindService; } }); service.doCheckUpdateTask; } ... }

最后,使用方式还是非常简单的在BaseActivity中使用:private VersionUpdateHelper versionUpdateHelper; @Overrideprotectedvoid。

onResume { super.onResume; if(versionUpdateHelper == null) versionUpdateHelper = new

VersionUpdateHelper(this); versionUpdateHelper.startUpdateVersion; } @Overrideprotectedvoid onPause {

super.onPause; if(versionUpdateHelper != null) versionUpdateHelper.stopUpdateVersion; }保证在每进入一个界面和离开界面时都将检查更新(bindService)和取消检查(unBindService)。

这时有些朋友可能认为这样做会不会浪费资源呢?没有!1,如果应用是强制更新,那么在网络正常情况下进入应用就能检查出有新版本,这时弹窗后用户不能进入任何操作,没有机会进入别的界面,所有没有进行重复检查;如果进入应用主页由于网络问题,检查失败,这时虽然不会弹窗提示更新,但是如果用户的网络恢复后进入任何其它界面都将得到正常的版本更新检查并弹窗提示

2,如果应用是非强制更新时,在Helper代码里进行了如下的判断:if (!versionUpdateModel.isMustUpgrade && !showDialogOnStart) { cancel;

return; }这里的showDialogOnStart默认为false,也就是说如果不是强制更新则检查成功后就当“取消”处理,并在cancel方法中将变量isCanceled修改为true,这样如果有新的请求想要执行startUpdateVersion都将被忽略,注意isCanceled是static全局的。

如果想实现在设置中由用户手动检查更新,则只需执行类似如下代码: SettingActivity.javaprivate VersionUpdateHelper versionUpdateHelper;

@OnClick(R.id.rl_version_update) publicvoidonClickVersionUpdate(View view){ if(updateTips.getVisibility == View.VISIBLE){

return; } VersionUpdateHelper.resetCancelFlag;//重置cancel标记if (versionUpdateHelper == null) { versionUpdateHelper =

new VersionUpdateHelper(this); versionUpdateHelper.setShowDialogOnStart(true); versionUpdateHelper.setCheckCallBack(

new VersionUpdateHelper.CheckCallBack { @OverridepublicvoidcallBack(int code){ //EventBus发送消息通知红点消失

VersionUpdateEvent versionUpdateEvent = new VersionUpdateEvent; versionUpdateEvent.setShowTips(false

); EventBus.getDefault.postSticky(versionUpdateEvent); } }); } versionUpdateHelper.startUpdateVersion; }

写在最后由于代码较多,且多数代码和ui相关,所以在文章中很多ui相关或者getter和setter方法等非核心代码并没有列出演示代码中用了EventBus和OkHttp开源控件,具体使用方法望大家自己找相关资料学习。

本人打算有空的时候写个EventBus系列文章,望大家多多关注文件下载也是使用的okHttp实现的,大家可以换成任何你熟悉的下载框架VersionUpdateService.java和VersionUpdateHelper.java的完整代码可以到我的github上下载,由于时间关系并没有相关用法的完整案例还望见谅,等有时间一定奉上。

如果有任何问题可以在评论中加以提问,谢谢~~

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

河南中青旅行社综合资讯 奇遇综合资讯 盛世蓟州综合资讯 综合资讯 游戏百科综合资讯 新闻4986