我的编程空间,编程开发者的网络收藏夹
学习永远不晚

安卓(Android)应用版本更新方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

安卓(Android)应用版本更新方法

开发中对版本进行检查并更新的需求基本是所有应用必须有的功能,可是在实际开发中有些朋友就容易忽略一些细节。

版本更新的基本流程:

一般是将本地版本告诉服务器,服务器经过相关处理会返回客户端相关信息,告诉客户端需不需要更新,如果需要更新是强制更新还是非强制更新。客户端得到服务器返回的相关信息后再进一步做逻辑处理。

强制更新:

一般的处理就是进入应用就弹窗通知用户有版本更新,弹窗可以没有取消按钮并不能取消。这样用户就只能选择更新或者关闭应用了,当然也可以添加取消按钮,但是如果用户选择取消则直接退出应用。

非强制更新

一般的处理是在应用的设置中添加版本检查的操作,如果用户主动检查版本则弹窗告知用户有版本更新。这时用户可以取消或者更新。

功能实际是比较简单清晰的,但之所以写这篇文章,是因为在我们公司的一个项目中,我把这个模块分给了一个有着4年工作经验的哥们编写,最后这哥们花了2个小时做完了。我还想这哥们写得挺快,效率很高嘛,结果一测试发现问题不少:

   1. 进入首页前关闭网络,进入后刷新界面发现强制更新提醒没有弹窗
  2.  再进入其它界面也没有任何更新提醒
 3.   在正常更新时点击确定更新,没有判断网络状态(wifi,移动网络)直接下载apk文件,如果用户在移动网络下将耗费非常多的流量,直接影响用户体验
  4.  下载过程在应用内没有进度条提醒,通知栏也没有进度提醒
  5.  apk文件下载过程中,如果强制结束应用,下载被中断
  6.  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篇这篇文章先做了解。

核心代码如下:


public class VersionUpdateService extends Service {
 private LocalBinder binder = new LocalBinder();
 private DownLoadListener downLoadListener;//下载任务监听回调接口
 private boolean downLoading;
 private int progress;
 private NotificationManager mNotificationManager;
 private NotificationUpdaterThread notificationUpdaterThread;
 private Notification.Builder notificationBuilder;
 private final int NOTIFICATION_ID = 100;
 private VersionUpdateModel versionUpdateModel;
 private CheckVersionCallBack checkVersionCallBack;//检查结果监听回调接口
 public interface DownLoadListener {
  void begain();
  void inProgress(float progress, long total);
  void downLoadLatestSuccess(File file);
  void downLoadLatestFailed();
 }
 public interface CheckVersionCallBack {
  void onSuccess();
  void onError();
 }
 ...
 private class NotificationUpdaterThread extends Thread {
  @Override
  public void run() {
   while (true) {
    notificationBuilder.setContentTitle("正在下载更新" + progress + "%"); // the label of the entry
    notificationBuilder.setProgress(100, progress, false);
    ...
   }
  }
 }
 private void starDownLoadForground() {
  //创建通知栏
  notificationBuilder = new Notification.Builder(this);
  ...
  Notification notification = notificationBuilder.getNotification();
  startForeground(NOTIFICATION_ID, notification);
 }
 private void stopDownLoadForground() {
  stopForeground(true);
 }
 //执行版本检查任务
 public void doCheckUpdateTask() {
  //获取本定版本号
  final int currentBuild = AppUtil.getVersionCode(this);
  //调用版本检查接口
  ApiManager.getInstance().versionApi.upgradeRecords(currentBuild, new RequestCallBack() {
   @Override
   public void onSuccess(Headers headers, String response) {
     versionUpdateModel = JSON.parseObject(response, VersionUpdateModel.class);
     ...
     if (checkVersionCallBack != null)
      checkVersionCallBack.onSuccess();
   }
   @Override
   public void onError(int code, String response) {
    ...
   }
  });
 }
 public void 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() {
   @Override
   public void inProgress(float progress_, long total) {
    ...
    //执行进度更新
    if (downLoadListener != null) 
     downLoadListener.inProgress(progress_, total);
    }
   @Override
   public void onSuccess(Headers headers, String response) {
    //执行成功回调
    ...
    installApk(destFile, VersionUpdateService.this);
   }
   @Override
   public void onError(int code, String response) {
    ...
    //执行失败回调
   }
  });
 }
 //安装apk
 public void installApk(File file, Context context) {
  ...
 }
}

public class VersionUpdateHelper implements ServiceConnection {
 private Context context;
 private VersionUpdateService service;
 private AlertDialog waitForUpdateDialog;
 private ProgressDialog progressDialog;
 private static boolean isCanceled;
 private boolean showDialogOnStart;
 public static final int NEED_UPDATE = 2;
 public static final int DONOT_NEED_UPDATE = 1;
 public static final int CHECK_FAILD = -1;
 public static final int USER_CANCELED = 0;
 private CheckCallBack checkCallBack;
 public interface CheckCallBack{
  void callBack(int code);
 }
 public VersionUpdateHelper(Context context) {
  this.context = context;
 }
 public void 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);
  }
 }
 public void stopUpdateVersion() {
  unBindService();
 }
 private void cancel() {
  isCanceled = true;
  unBindService();
 }
 private void unBindService() {
  if (isWaitForUpdate() || isWaitForDownload()) {
   return;
  }
  if (service != null && !service.isDownLoading()) {
   context.unbindService(this);
   service = null;
  }
 }
 ...
 private void showNotWifiDownloadDialog() {
  final AlertDialog.Builder builer = new AlertDialog.Builder(context);
  builer.setTitle("下载新版本");
  builer.setMessage("检查到您的网络处于非wifi状态,下载新版本将消耗一定的流量,是否继续下载?");
  builer.setNegativeButton("以后再说", new DialogInterface.OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
    ...
    //如果是强制更新 exit app
    if (mustUpdate) {
     MainApplication.getInstance().exitApp();
    }
   }
  });
  builer.setPositiveButton("继续下载", new DialogInterface.OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
    dialog.cancel();
    service.doDownLoadTask();
   }
  });
  ...
 }
 @Override
 public void onServiceConnected(ComponentName name, IBinder binder) {
  service = ((VersionUpdateService.LocalBinder) binder).getService();
  service.setCheckVersionCallBack(new VersionUpdateService.CheckVersionCallBack() {
   @Override
   public void 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() {
     @Override
     public void onClick(DialogInterface dialog, int which) {
      dialog.cancel();
      if (NetUtil.isWifi(context)) {
       service.doDownLoadTask();
      } else {
       showNotWifiDownloadDialog();
      }
     }
    });
    //当点取消按钮时进行登录
    if (!versionUpdateModel.isMustUpgrade()) {
     builer.setNegativeButton("稍后更新", new DialogInterface.OnClickListener() {
      public void onClick(DialogInterface dialog, int which) {
       dialog.cancel();
       cancel();
       if(checkCallBack != null){
        checkCallBack.callBack(USER_CANCELED);
       }
      }
     });
    }
    builer.setCancelable(false);
    waitForUpdateDialog = builer.create();
    waitForUpdateDialog.show();
   }
   @Override
   public void onError() {
    unBindService();
    ...
   }
  });
  service.setDownLoadListener(new VersionUpdateService.DownLoadListener() {
   @Override
   public void begain() {
    VersionUpdateModel versionUpdateModel = service.getVersionUpdateModel();
    if (versionUpdateModel.isMustUpgrade()) {
     progressDialog = ...//生成进度条对话框
    }
   }
   @Override
   public void inProgress(float progress, long total) {
    ...//更新进度条
   }
   @Override
   public void downLoadLatestSuccess(File file) {
    ...//执行成功处理
    unBindService();
   }
   @Override
   public void downLoadLatestFailed() {
    ...//执行失败处理
    unBindService();
   }
  });
  service.doCheckUpdateTask();
 }
 ...
}

最后,使用方式还是非常简单的。在BaseActivity中使用:


private VersionUpdateHelper versionUpdateHelper;
@Override
protected void onResume() {
 super.onResume();
 if(versionUpdateHelper == null)
  versionUpdateHelper = new VersionUpdateHelper(this);
 versionUpdateHelper.startUpdateVersion();
}
@Override
protected void onPause() {
 super.onPause();
 if(versionUpdateHelper != null)
  versionUpdateHelper.stopUpdateVersion();
}

保证在每进入一个界面和离开界面时都将检查更新(bindService)和取消检查(unBindService)。这时有些朋友可能认为这样做会不会浪费资源呢?没有!

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

2,如果应用是非强制更新时,在Helper代码里进行了如下的判断:


SettingActivity.java
private VersionUpdateHelper versionUpdateHelper;
@OnClick(R.id.rl_version_update)
public void onClickVersionUpdate(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() {
   @Override
   public void callBack(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上下载,由于时间关系并没有相关用法的完整案例还望见谅,等有时间一定奉上。

您可能感兴趣的文章:Android编程实现自动检测版本及自动升级的方法android实现程序自动升级到安装示例分享(下载android程序安装包)Android编程实现应用自动更新、下载、安装的方法Android App实现应用内部自动更新的最基本方法示例Android应用自动更新功能实现的方法Android应用APP自动更新功能的代码实现Android应用强制更新APP的示例代码Android应用App更新实例详解非常实用的小功能 Android应用版本的更新实例Android应用更新之自动检测版本及自动升级


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

安卓(Android)应用版本更新方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

安卓(Android)应用版本更新方法

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

python3.7 更新pip版本的方法

在安装python的一个库时,我发现了有这样的报错:"You are using pip version 10.0.1, however version 18.0 is available."解决方法:1.cd到pip所在文件夹下,例如我的
2023-01-31

Android程序版本更新之通知栏更新下载安装

Android应用检查版本更新后,在通知栏下载,更新下载进度,下载完成自动安装,效果图如下:检查当前版本号AndroidManifest文件中的versionCode用来标识版本,在服务器放一个新版本的apk,versioncode大于当前
2022-06-06

win102004版本系统更新的方法

本篇内容主要讲解“win102004版本系统更新的方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“win102004版本系统更新的方法”吧!win102004版本系统怎么样更新如果已经安装可w
2023-07-01

Win8.1系统应用程序无法更新为最新版本的解决方法

Win8.1系统应用程序无法更新为最新版本的解决方法:1、先重新启动下Win8.1系统;2、然后按住键盘上的WIN+X键,之后移动鼠标点击 命令提示符(管理员)选项;3、在命令提示符中键入:wsreset 并回车 (wsreset 命令为清
2022-06-05

package.json的版本号更新优化方法

这篇文章主要为大家介绍了package.json的版本号更新优化方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-15

word更新版本的方法是什么

Word的更新版本方法通常有两种途径:1. 自动更新:当你的电脑连接到互联网时,Word会自动检查是否有可用的更新版本,并在有更新时提示你进行更新。你可以按照提示点击更新按钮,然后等待更新完成。2. 手动更新:你可以手动检查是否有可用的更新
2023-09-11

更新tensorflow版本的方法是什么

要更新TensorFlow版本,可以使用以下命令:使用pip命令更新TensorFlow:pip install --upgrade tensorflow如果您使用的是GPU版本的TensorFlow,可以使用以下命令:pip insta
更新tensorflow版本的方法是什么
2024-03-14

非常实用的小功能 Android应用版本的更新实例

每一个应用都是具备一个功能,那就是版本更新,我记得我之前在面试的时候,面试官让我介绍一下应用版本更新的一些具体操作。我当时因为做过这个功能,所以回答的还是很流畅,现在我把这个分享给大家,需要能够共同进步。 我当时是这么说的: 首先呢,我们是
2022-06-06

【Android】app应用内版本更新升级(DownloadManager下载,适配Android6.0以上所有版本)

目录 前言一、实现思路二、服务端接口三、UI页面三、工具类实现1.检查版本号2.下载apk3.安装apk4.实时更新下载进度5.完整代码 三、外部使用总结 前言 版本的升级和更新是一个线上App所必备的功能,App的升级安
2023-08-19

Linux更新Python版本及修改python默认版本的方法

linux下更新Python版本并修改默认版本,有需要的朋友可以参考下。很多情况下拿到的服务器python版本很低,需要自己动手更改默认python版本1、从官网下载python安装包(这个版本可以是任意版本3.3 2.7 2.6等等)wg
2022-06-04

Android编程实现应用自动更新、下载、安装的方法

本文实例讲述了Android编程实现应用自动更新、下载、安装的方法。分享给大家供大家参考,具体如下: 我们看到很多Android应用都具有自动更新功能,用户一键就可以完成软件的升级更新。得益于Android系统的软件包管理和安装机制,这一功
2022-06-06

Android应用自动更新功能实现的方法

本文给大家分享Android里应用版本更新功能这一块的实现。 一个好的应用软件都是需要好的维护,从初出版本到最后精品,这个过程需要版本不停的更新,那么如何让用户第一时间获取最新的应用安装包呢?那么就要求我们从第一个版本就要实现升级模块这一功
2022-06-06

ssl证书版本更新的方法是什么

SSL证书版本更新的方法一般有以下几种:1、自行更新证书如果您使用的是自签名的证书,可以通过自行更新证书的方式来更新证书版本。首先需要生成新的证书,然后在忆速云yisuyun服务器上替换旧证书,最后重新启动Web服务器即可。2、续期商业证书
2023-05-13

Linux下更新python版本的方法是什么

本篇内容介绍了“Linux下更新python版本的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、下载python版本  wge
2023-06-28

ubuntu更新gcc版本号的方法是什么

本文小编为大家详细介绍“ubuntu更新gcc版本号的方法是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“ubuntu更新gcc版本号的方法是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1、使用快捷键
2023-07-04

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录