一开始,我们先向服务器请求数据获取版本

  1. public ObservableField<VersionBean> appVersion = new ObservableField<>();
  2.  
  3. /**
  4. * 获取服务器版本并判断是否需要更新
  5. */
  6. public void getServiceAppVersionEvent() {
  7. resource.getAppVersionEvent()
  8. .observeOn(AndroidSchedulers.mainThread())
  9. .subscribe(response -> {
  10. if (EmptyUtil.isNotEmpty(response.body)) {
  11. appVersion.set(response.body);
  12. if (UpdateAppUtil.checkAppVersion(response.body)) {
  13. checkUpdate.set("发现新版本" + response.body.getVersion());
  14. }
  15. }
  16. });
  17. }

服务器返回的数据

  1. /**
  2. * Created by hyx on 17-9-29.
  3. */
  4.  
  5. public class VersionBean {
  6.  
  7. private String description;
  8. private String url;
  9. private String version;
  10.  
  11. public String getUrl() {
  12. return url;
  13. }
  14.  
  15. public void setUrl(String url) {
  16. this.url = url;
  17. }
  18.  
  19. public String getVersion() {
  20. return version;
  21. }
  22.  
  23. public void setVersion(String version) {
  24. this.version = version;
  25. }
  26.  
  27. public String getDescription() {
  28. return description;
  29. }
  30.  
  31. public void setDescription(String description) {
  32. this.description = description;
  33. }
  34. }

对比服务器和本地判断是否需要更新,我这里是根据VersionName判断

  1. /**
  2. * 获取versionName
  3. *
  4. * @return
  5. */
  6. public static String getAppVersionName() {
  7. if (EmptyUtil.isNotEmpty(CtrAppImpl.getContext())) {
  8. try {
  9. PackageManager manager = CtrAppImpl.getContext().getPackageManager();
  10. PackageInfo info = manager.getPackageInfo(CtrAppImpl.getContext().getPackageName(), 0);
  11. return info.versionName;
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. return "";
  15. }
  16.  
  17. } else {
  18. return null;
  19. }
  20. }
  21.  
  22. /**
  23. * 获取versionId
  24. *
  25. * @return
  26. */
  27. public static int getAppVersionCode() {
  28. if (EmptyUtil.isNotEmpty(CtrAppImpl.getContext())) {
  29. try {
  30. PackageManager manager = CtrAppImpl.getContext().getPackageManager();
  31. PackageInfo info = manager.getPackageInfo(CtrAppImpl.getContext().getPackageName(), 0);
  32. return info.versionCode;
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. return -1;
  36. }
  37.  
  38. } else {
  39. return -1;
  40. }
  41. }
  42.  
  43. /**
  44. * true 表示需要更新,false 表示当前版本是最新的
  45. *
  46. * @param versionBean
  47. * @return
  48. */
  49. public static boolean checkAppVersion(VersionBean versionBean) {
  50. if (EmptyUtil.isNotEmpty(versionBean)) {
  51. if (!getAppVersionName().equals(versionBean.getVersion())) {
  52. return true;
  53. } else {
  54. return false;
  55. }
  56. }
  57. return false;
  58. }

如果需要更新,我们根据存储的downloadId去查询下载状态,因为有可能用户之前已经下载了,没有安装,亦或正在下载中,下载暂停等情况,

  1. if (UpdateAppUtil.checkAppVersion(getViewModel().appVersion.get())) {
  2. //根据downloadId查询下载状态
  3. long downloadId = (long) SPUtil.get(PersonalActivity.this, "downloadId", -1L);
  4. UpdateAppUtil.checkDownloadStatus(downloadId, new DataBack<Integer>() {
  5. @Override
  6. public void take(Integer status) {
  7. if (status == -1) {
  8. new MaterialDialog.Builder(PersonalActivity.this)
  9. .title("版本更新")
  10. .content("发现新版本,是否更新?")
  11. .positiveText("确定")
  12. .negativeText("取消")
  13. .onPositive(((materialDialog, dialogAction) -> {
  14. ToastUtil.showShortToast("正在后台为您下载");
  15. UpdateAppUtil.downloadAPK(getViewModel().appVersion.get(), "ctrshoppix.apk");
  16. }))
  17. .onNegative((materialDialog, dialogAction) -> {
  18. materialDialog.dismiss();
  19. })
  20. .show();
  21. } else if (status == DownloadManager.STATUS_FAILED) {
  22. ToastUtil.showShortToast("下载失败,正在为您重新下载");
  23. UpdateAppUtil.downloadAPK(getViewModel().appVersion.get(), "ctrshoppix.apk");
  24. } else if (status == DownloadManager.STATUS_SUCCESSFUL) {
  25. if (UpdateAppUtil.compareApk(UpdateAppUtil.getApkInfo(UpdateAppUtil.getDownloadPath(downloadId)))) {
  26. UpdateAppUtil.installApp(UpdateAppUtil.getDownloadUri(downloadId));
  27. } else {
  28. UpdateAppUtil.removeDownloadId(downloadId);
  29. }
  30. }
  31. }
  32. });

具体的方法在下面UpdateAppUtil中查看,备注写的很清楚

  1. import android.app.Activity;
  2. import android.app.DownloadManager;
  3. import android.content.BroadcastReceiver;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.pm.PackageInfo;
  7. import android.content.pm.PackageManager;
  8. import android.database.Cursor;
  9. import android.net.Uri;
  10. import android.os.Build;
  11. import android.os.Environment;
  12. import android.support.v4.content.FileProvider;
  13. import android.text.BoringLayout;
  14.  
  15. import java.io.File;
  16. import java.io.IOException;
  17.  
  18. import ppm.ctr.cctv.ctr.application.CtrAppImpl;
  19. import ppm.ctr.cctv.ctr.common.AsyncCall;
  20. import ppm.ctr.cctv.ctr.common.DataBack;
  21. import ppm.ctr.cctv.ctr.network.entity.VersionBean;
  22. import ppm.ctr.cctv.ctr.services.file.UriPraseUtil;
  23.  
  24. /**
  25. * Created by css on 2017/10/30.
  26. */
  27.  
  28. public class UpdateAppUtil {
  29. private static DownloadManager downloadManager;
  30.  
  31. /**
  32. * 获取versionName
  33. *
  34. * @return
  35. */
  36. public static String getAppVersionName() {
  37. if (EmptyUtil.isNotEmpty(CtrAppImpl.getContext())) {
  38. try {
  39. PackageManager manager = CtrAppImpl.getContext().getPackageManager();
  40. PackageInfo info = manager.getPackageInfo(CtrAppImpl.getContext().getPackageName(), 0);
  41. return info.versionName;
  42. } catch (Exception e) {
  43. e.printStackTrace();
  44. return "";
  45. }
  46.  
  47. } else {
  48. return null;
  49. }
  50. }
  51.  
  52. /**
  53. * 获取versionId
  54. *
  55. * @return
  56. */
  57. public static int getAppVersionCode() {
  58. if (EmptyUtil.isNotEmpty(CtrAppImpl.getContext())) {
  59. try {
  60. PackageManager manager = CtrAppImpl.getContext().getPackageManager();
  61. PackageInfo info = manager.getPackageInfo(CtrAppImpl.getContext().getPackageName(), 0);
  62. return info.versionCode;
  63. } catch (Exception e) {
  64. e.printStackTrace();
  65. return -1;
  66. }
  67.  
  68. } else {
  69. return -1;
  70. }
  71. }
  72.  
  73. /**
  74. * true 表示需要更新,false 表示当前版本是最新的
  75. *
  76. * @param versionBean
  77. * @return
  78. */
  79. public static boolean checkAppVersion(VersionBean versionBean) {
  80. if (EmptyUtil.isNotEmpty(versionBean)) {
  81. if (!getAppVersionName().equals(versionBean.getVersion())) {
  82. return true;
  83. } else {
  84. return false;
  85. }
  86. }
  87. return false;
  88. }
  89.  
  90. /**
  91. * 检查下载状态
  92. *
  93. * @param downloadId
  94. * @param dataBack
  95. */
  96. public static void checkDownloadStatus(long downloadId, DataBack<Integer> dataBack) {
  97. DownloadManager.Query query = new DownloadManager.Query();
  98. //通过下载的id查找
  99. query.setFilterById(downloadId);
  100. //获取DownloadManager
  101. if (EmptyUtil.isEmpty(downloadManager)) {
  102. downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
  103. }
  104. Cursor c = downloadManager.query(query);
  105. if (c.moveToFirst()) {
  106. int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
  107. switch (status) {
  108. case -1:
  109. dataBack.take(-1);
  110. break;
  111. //下载暂停
  112. case DownloadManager.STATUS_PAUSED:
  113. ToastUtil.showShortToast("下载暂停");
  114. break;
  115. //下载延迟
  116. case DownloadManager.STATUS_PENDING:
  117. ToastUtil.showShortToast("下载延迟");
  118. break;
  119. //正在下载
  120. case DownloadManager.STATUS_RUNNING:
  121. ToastUtil.showShortToast("正在下载");
  122. break;
  123. //下载完成
  124. case DownloadManager.STATUS_SUCCESSFUL:
  125. dataBack.take(DownloadManager.STATUS_SUCCESSFUL);
  126.  
  127. break;
  128. //下载失败
  129. case DownloadManager.STATUS_FAILED:
  130. dataBack.take(DownloadManager.STATUS_FAILED);
  131. break;
  132. default:
  133. dataBack.take(-1);
  134. break;
  135. }
  136.  
  137. dataBack.take(status);
  138. } else {
  139. //可能用户误删之前已经下载得apk
  140. dataBack.take(-1);
  141. }
  142. c.close();
  143. }
  144.  
  145. /**
  146. * 根据downloadID获取本地存储的文件path
  147. *
  148. * @param downloadId
  149. * @return
  150. */
  151. public static String getDownloadPath(long downloadId) {
  152. //获取DownloadManager
  153. if (EmptyUtil.isEmpty(downloadManager)) {
  154. downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
  155. }
  156. String downloadPath = new File(UriPraseUtil.uriToFile(downloadManager.getUriForDownloadedFile(downloadId), CtrAppImpl.getContext())).toString();
  157. return downloadPath;
  158. }
  159.  
  160. /**
  161. * 根据downloadID 获取获取本地文件存储的uri
  162. *
  163. * @param downloadId
  164. * @return
  165. */
  166. public static Uri getDownloadUri(long downloadId) {
  167. //获取DownloadManager
  168. if (EmptyUtil.isEmpty(downloadManager)) {
  169. downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
  170. }
  171. Uri downloadFileUri = downloadManager.getUriForDownloadedFile(downloadId);
  172. //适配不同的手机,有的手机不能识别,所以再转一遍
  173. Uri uri = Uri.fromFile(new File(UriPraseUtil.uriToFile(downloadFileUri, CtrAppImpl.getContext())));
  174. return uri;
  175. }
  176.  
  177. /**
  178. * 获取apk程序信息
  179. *
  180. * @param path apk path
  181. */
  182. public static PackageInfo getApkInfo(String path) {
  183. PackageManager pm = CtrAppImpl.getContext().getPackageManager();
  184. PackageInfo info = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
  185. if (info != null) {
  186. return info;
  187. }
  188. return null;
  189. }
  190.  
  191. /**
  192. * 下载的apk和当前程序版本比较
  193. *
  194. * @param apkInfo apk file's packageInfo
  195. * @return 如果当前应用版本小于apk的版本则返回true
  196. */
  197. public static boolean compareApk(PackageInfo apkInfo) {
  198. if (apkInfo == null) {
  199. return false;
  200. }
  201. if (!apkInfo.versionName.equals(getAppVersionName())) {
  202. return true;
  203. }
  204. return false;
  205.  
  206. }
  207.  
  208. /**
  209. * 下载apk
  210. *
  211. * @param versionBean
  212. * @param apkName
  213. */
  214. public static void downloadAPK(VersionBean versionBean, String apkName) {
  215. //创建下载任务
  216. DownloadManager.Request request = new DownloadManager.Request(Uri.parse(versionBean.getUrl()));
  217. //移动网络情况下是否允许漫游
  218. request.setAllowedOverRoaming(false);
  219. // 设置在通知栏是否显示下载通知(下载进度), 有 3 个值可选:
  220. // VISIBILITY_VISIBLE: 下载过程中可见, 下载完后自动消失 (默认)
  221. // VISIBILITY_VISIBLE_NOTIFY_COMPLETED: 下载过程中和下载完成后均可见
  222. // VISIBILITY_HIDDEN: 始终不显示通知
  223. request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
  224. request.setTitle("单单拍");
  225. request.setDescription("");
  226. request.setVisibleInDownloadsUi(true);
  227.  
  228. //设置下载的路径
  229. request.setDestinationInExternalPublicDir(Environment.getExternalStorageDirectory().getAbsolutePath(), apkName);
  230.  
  231. //获取DownloadManager
  232. if (EmptyUtil.isEmpty(downloadManager)) {
  233. downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
  234. }
  235. //将下载请求加入下载队列,加入下载队列后会给该任务返回一个long型的id,通过该id可以取消任务,重启任务、获取下载的文件等等
  236. long downloadId = downloadManager.enqueue(request);
  237. SPUtil.put(CtrAppImpl.getContext(), "downloadId", downloadId);
  238. }
  239.  
  240. /**
  241. * 移除本地存储的downloadid 和相关文件
  242. *
  243. * @param downloadId
  244. */
  245. public static void removeDownloadId(long downloadId) {
  246. //获取DownloadManager
  247. if (EmptyUtil.isEmpty(downloadManager)) {
  248. downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
  249. }
  250. downloadManager.remove(downloadId);
  251. SPUtil.remove(CtrAppImpl.getContext(), "downloadId");
  252. }
  253.  
  254. /**
  255. * 安装app
  256. *
  257. * @param uri
  258. */
  259. public static void installApp(Uri uri) {
  260. Intent intent = new Intent();
  261. intent.setDataAndType(uri, "application/vnd.android.package-archive");
  262. intent.setAction(Intent.ACTION_VIEW);
  263. intent.addCategory(Intent.CATEGORY_DEFAULT);
  264. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  265. intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  266. CtrAppImpl.getContext().startActivity(intent);
  267. }
  268.  
  269. /**
  270. * 安装app
  271. *
  272. * @param apkPath
  273. */
  274. public static void installApp(String apkPath) {
  275. File file = new File(apkPath);
  276. Uri uri = null;
  277. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  278. String command = "chmod " + "777" + " " + file;
  279. Runtime runtime = Runtime.getRuntime();
  280. try {
  281. runtime.exec(command);
  282. } catch (IOException e) {
  283. e.printStackTrace();
  284. }
  285. uri = FileProvider.getUriForFile(CtrAppImpl.getContext(), "ppm.ctr.cctv.ctr.provider", file);
  286. } else {
  287. uri = Uri.fromFile(file);
  288. }
  289. Intent intent = new Intent();
  290. intent.setDataAndType(uri, "application/vnd.android.package-archive");
  291. intent.setAction(Intent.ACTION_VIEW);
  292. intent.addCategory(Intent.CATEGORY_DEFAULT);
  293. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  294. intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  295. CtrAppImpl.getContext().startActivity(intent);
  296. }
  297.  
  298. }

Android App自动更新解决方案(DownloadManager)的更多相关文章

  1. Android学习系列(3)--App自动更新之自定义进度视图和内部存储

    友好的视觉感知和稳定的不出错表现,来自于我们追求美感和考虑的全面性,博客园从技术的角度,一直我都很欣赏.这篇文章是android开发人员的必备知识,是我特别为大家整理和总结的,不求完美,但是有用. 这 ...

  2. H5+app -- 自动更新

    一.最近做了一个app自动更新功能,用的基本都是网上找得到的. 1.h5+ 规范 :  http://www.html5plus.org/doc/zh_cn/maps.html 2.环形进度条插件:h ...

  3. web app升级—带进度条的App自动更新

    带进度条的App自动更新,效果如下图所示:   技术:vue.vant-ui.5+ 封装独立组件AppProgress.vue: <template> <div> <va ...

  4. Android实现自动更新功能

    Android实现自动更新功能 Android自动更新的功能可以使用第三方的SDK来实现,但是类似友盟,就不支持x86手机的自动更新,科大讯飞,弹窗是全局的,小米手机就会默认把弹窗权限关掉不允许弹出提 ...

  5. Android应用自动更新功能的实现!

    Android应用自动更新功能的实现!http://blog.csdn.net/android_tutor/article/details/7015986 private static final i ...

  6. Web APP自动更新

    我们的手机软件每天都要经营,经常需要更新,比如程序的Bug,好的功能,好的洁面... ... 这就需要我们的用户打开web app时候自动更新客户端程序,而不是再去应用程序商店从新下载.今天的笔记就是 ...

  7. NEO4J中文分词全文索引自动更新解决方案

    NEO4J中文分词全文索引自动更新解决方案 一.样例数据 二.英文与中文全文索引差别 1.创建NEO4J默认索引 2.删除索引 3.创建支持中文分词的索引 三.APOC自带英文全文索引过程(可自动更新 ...

  8. App自动更新(DownloadManager下载器)

    一.开门见山 代码: object AppUpdateManager { const val APP_UPDATE_APK = "update.apk" private var b ...

  9. Android 云服务器的搭建和友盟APP自动更新功能的实现

    setContentView(R.layout.activity_splash); //Bmob SDK初始化--只需要这一段代码即可完成初始化 //请到Bmob官网(http://www.bmob. ...

随机推荐

  1. 深入selenium三种等待方式使用

    深入selenium三种等待方式使用 处理由于网络延迟造成没法找到网页元素 方法一 用time模块不推荐使用 用time模块中的time.sleep来完成等待 from selenium import ...

  2. win7系统防止中招勒索病毒

    echo @@ netsh advfirewall firewall add rule name= netsh advfirewall firewall add rule name= netsh ad ...

  3. Pandas处理超大规模数据

    对于超大规模的csv文件,我们无法一下将其读入内存当中,只能分块一部分一部分的进行读取: 首先进行如下操作: import pandas as pd reader = pd.read_csv('dat ...

  4. Violet音乐社区设计文档

    目录 Violet音乐社区设计文档 一.引言 1.1 编写目的 1.2 开发背景 二.用例图设计 2.1游客实例设计 2.2 管理员实例设计 2.3 普通用户实例设计 三.类图设计 3.1 歌手类 3 ...

  5. 并发编程~~~多线程~~~守护线程, 互斥锁, 死锁现象与递归锁, 信号量 (Semaphore), GIL全局解释器锁

    一 守护线程 from threading import Thread import time def foo(): print(123) time.sleep(1) print('end123') ...

  6. QPNP 8909 8916 充电相关(1)【转】

    最近一直在搞电源管理相关内容,之前是8610的bms,现在8916的bms,发现两者还是有点区别的,8916把对last_ocv_uv的估值算法分装成执行文件,作为服务一直运行. 电源管理方面,应该是 ...

  7. [Linux] ubuntu环境安装和使用elasticsearch

    wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -apt-get install ap ...

  8. Codeforces Round #594 (Div. 2)

    传送门 C. Ivan the Fool and the Probability Theory 题意: 给出一个\(n*m\)的方格,现在要给方格中的元素黑白染色,要求任一颜色最多有一个颜色相同的格子 ...

  9. oracle xmltype + blob + clob

    oracle varchar2最大存储长度为4000,所以当字段长度超限时可尝试存储为blob或xmltype格式 xmltype --1.创建xml表 Create TABLE testxml( i ...

  10. 开放平台API接口安全策略汇总

    在设计开放平台接口过程中,往往会涉及接口传输安全性相关的问题,本文对接口加密及签名的相关知识做了一个总结,在方便自己查阅的同时也分享给大家做一些参考. 接口安全性问题思考 接口安全性问题主要来源于几方 ...