Github代码:https://github.com/SpikeKing/wcl-update-request-demo

逻辑

访问服务器, 根据是否包含新版本, 判断是否需要更新.
下载Apk, 下载完成后, 自动安装, 高版本会覆盖低版本.

逻辑:

public class MainActivity extends AppCompatActivity {private static final String APP_NAME = "Ped_android";private static final String VERSION = "1.0.0";private static final String INFO_NAME = "计步器";private static final String STORE_APK = "chunyu_apk";@Bind(R.id.main_b_install_apk) Button mBInstallApk;private UpdateAppUtils.UpdateCallback mUpdateCallback; // 更新回调@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);mUpdateCallback = new UpdateAppUtils.UpdateCallback() {@Override public void onSuccess(UpdateInfo updateInfo) {Toast.makeText(MainActivity.this, "有更新", Toast.LENGTH_SHORT).show();UpdateAppUtils.downloadApk(MainActivity.this, updateInfo, INFO_NAME, STORE_APK);}@Override public void onError() {Toast.makeText(MainActivity.this, "无更新", Toast.LENGTH_SHORT).show();}};mBInstallApk.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {UpdateAppUtils.checkUpdate(APP_NAME, VERSION, mUpdateCallback);}});}
}

UpdateAppUtils是核心下载类. 输入App的代号, 版本号, 异步回调, 发送到服务器, 判断是否需要更新. 如果存在新版本, 则下载Apk, 并自动安装更新.

网络请求

更新请求, 参数是App代号和当前版本号.

/*** 更新服务* <p>* Created by wangchenlong on 16/1/4.*/
public interface UpdateService {String ENDPOINT = "http://www.chunyuyisheng.com";// 获取App版本信息@GET("/cmsapi/app/update")Observable<UpdateInfo> getUpdateInfo(@Query("appName") String appName,@Query("version") String version);
}

创建服务的工厂类.

/*** 创建Retrofit服务* <p>* Created by wangchenlong on 16/1/4.*/
public class ServiceFactory {public static <T> T createServiceFrom(final Class<T> serviceClass, String endpoint) {Retrofit adapter = new Retrofit.Builder().baseUrl(endpoint).addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 添加Rx适配器.addConverterFactory(GsonConverterFactory.create()) // 添加Gson转换器.build();return adapter.create(serviceClass);}
}

更新信息的实体类.

/*** 更新信息* <p>* Created by wangchenlong on 16/1/4.*/
public class UpdateInfo {public Data data; // 信息public Integer error_code; // 错误代码public String error_msg; // 错误信息public static class Data {public String curVersion; // 当前版本public String appURL; // 下载地址public String description; // 描述public String minVersion; // 最低版本public String appName; // 应用名称}@Override public String toString() {return "当前版本: " + data.curVersion + ", 下载地址: " + data.appURL + ", 描述信息: " + data.description+ ", 最低版本: " + data.minVersion + ", 应用代称: " + data.appName+ ", 错误代码: " + error_code + ", 错误信息: " + error_msg;}
}

请求和下载

更新库的主类, 包含检查更新(checkUpdate)和下载Apk(downloadApk)两个重要方法.

/*** 更新管理器* <p>* Created by wangchenlong on 16/1/6.*/
@SuppressWarnings("unused")
public class UpdateAppUtils {@SuppressWarnings("unused")private static final String TAG = "DEBUG-WCL: " + UpdateAppUtils.class.getSimpleName();/*** 检查更新*/@SuppressWarnings("unused")public static void checkUpdate(String appCode, String curVersion, UpdateCallback updateCallback) {UpdateService updateService =ServiceFactory.createServiceFrom(UpdateService.class, UpdateService.ENDPOINT);updateService.getUpdateInfo(appCode, curVersion).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(updateInfo -> onNext(updateInfo, updateCallback),throwable -> onError(throwable, updateCallback));}// 显示信息private static void onNext(UpdateInfo updateInfo, UpdateCallback updateCallback) {Log.e(TAG, "返回数据: " + updateInfo.toString());if (updateInfo.error_code != 0 || updateInfo.data == null ||updateInfo.data.appURL == null) {updateCallback.onError(); // 失败} else {updateCallback.onSuccess(updateInfo);}}// 错误信息private static void onError(Throwable throwable, UpdateCallback updateCallback) {updateCallback.onError();}/*** 下载Apk, 并设置Apk地址,* 默认位置: /storage/sdcard0/Download** @param context    上下文* @param updateInfo 更新信息* @param infoName   通知名称* @param storeApk   存储的Apk*/@SuppressWarnings("unused")public static void downloadApk(Context context, UpdateInfo updateInfo,String infoName, String storeApk) {if (!isDownloadManagerAvailable()) {return;}String description = updateInfo.data.description;String appUrl = updateInfo.data.appURL;if (appUrl == null || appUrl.isEmpty()) {Log.e(TAG, "请填写\"App下载地址\"");return;}appUrl = appUrl.trim(); // 去掉首尾空格if (!appUrl.startsWith("http")) {appUrl = "http://" + appUrl; // 添加Http信息}Log.e(TAG, "appUrl: " + appUrl);DownloadManager.Request request;try {request = new DownloadManager.Request(Uri.parse(appUrl));} catch (Exception e) {e.printStackTrace();return;}request.setTitle(infoName);request.setDescription(description);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {request.allowScanningByMediaScanner();request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);}request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, storeApk);Context appContext = context.getApplicationContext();DownloadManager manager = (DownloadManager)appContext.getSystemService(Context.DOWNLOAD_SERVICE);// 存储下载KeySharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(appContext);sp.edit().putLong(PrefsConsts.DOWNLOAD_APK_ID_PREFS, manager.enqueue(request)).apply();}// 最小版本号大于9private static boolean isDownloadManagerAvailable() {return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;}// 错误回调public interface UpdateCallback {void onSuccess(UpdateInfo updateInfo);void onError();}
}

检查更新: 创建服务, 在新线程中发送请求, 在主线程中接收数据, 判断成功和失败.

/*** 检查更新*/@SuppressWarnings("unused")public static void checkUpdate(String appCode, String curVersion, UpdateCallback updateCallback) {UpdateService updateService =ServiceFactory.createServiceFrom(UpdateService.class, UpdateService.ENDPOINT);updateService.getUpdateInfo(appCode, curVersion).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(updateInfo -> onNext(updateInfo, updateCallback),throwable -> onError(throwable, updateCallback));}

下载Apk: 转换和解析Url, 设置通知信息和存储位置, 存储下载Id, 自动安装更新.

/*** 下载Apk, 并设置Apk地址,* 默认位置: /storage/sdcard0/Download** @param context    上下文* @param updateInfo 更新信息* @param infoName   通知名称* @param storeApk   存储的Apk*/@SuppressWarnings("unused")public static void downloadApk(Context context, UpdateInfo updateInfo,String infoName, String storeApk) {if (!isDownloadManagerAvailable()) {return;}String description = updateInfo.data.description;String appUrl = updateInfo.data.appURL;if (appUrl == null || appUrl.isEmpty()) {Log.e(TAG, "请填写\"App下载地址\"");return;}appUrl = appUrl.trim(); // 去掉首尾空格if (!appUrl.startsWith("http")) {appUrl = "http://" + appUrl; // 添加Http信息}Log.e(TAG, "appUrl: " + appUrl);DownloadManager.Request request;try {request = new DownloadManager.Request(Uri.parse(appUrl));} catch (Exception e) {e.printStackTrace();return;}request.setTitle(infoName);request.setDescription(description);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {request.allowScanningByMediaScanner();request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);}request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, storeApk);Context appContext = context.getApplicationContext();DownloadManager manager = (DownloadManager)appContext.getSystemService(Context.DOWNLOAD_SERVICE);// 存储下载KeySharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(appContext);sp.edit().putLong(PrefsConsts.DOWNLOAD_APK_ID_PREFS, manager.enqueue(request)).apply();}

使用DownloadManager下载文件是Android的推荐方式.
存储下载Id(manager.enqueue(request))是为了在安装应用时, 找到Apk.
默认存储地址/storage/sdcard0/Download.

自动安装

注册广播接收器, 接收消息ACTION_DOWNLOAD_COMPLETE, 下载完成会发送广播. 获取下载文件的Uri, 进行匹配, 发送安装消息, 自动安装.

/*** 安装下载接收器* <p>* Created by wangchenlong on 16/1/5.*/
public class InstallReceiver extends BroadcastReceiver {private static final String TAG ="DEBUG-WCL: " + InstallReceiver.class.getSimpleName();// 安装下载接收器@Override public void onReceive(Context context, Intent intent) {if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {long downloadApkId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);installApk(context, downloadApkId);}}// 安装Apkprivate void installApk(Context context, long downloadApkId) {// 获取存储IDSharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);long id = sp.getLong(PrefsConsts.DOWNLOAD_APK_ID_PREFS, -1L);if (downloadApkId == id) {DownloadManager dManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);Intent install = new Intent(Intent.ACTION_VIEW);Uri downloadFileUri = dManager.getUriForDownloadedFile(downloadApkId);if (downloadFileUri != null) {install.setDataAndType(downloadFileUri, "application/vnd.android.package-archive");install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(install);} else {Log.e(TAG, "下载失败");}}}
}

安装本应用下载的Apk, 不安装其他Apk, 存储下载Id, 与广播Id进行匹配.
下载失败, 也会发送下载完成(ACTION_DOWNLOAD_COMPLETE)广播, Uri可能为空, 需要判断, 否则发生崩溃.

Github下载地址
转自:http://blog.csdn.net//caroline_wendy/article/details/50475854

Retrofit实现App更新相关推荐

  1. Android APP更新下载工具类——简单封装DownloadManager

    几乎所有APP都包含了检查更新功能,更新下载功能的实现方式常用的有两种:1.使用App网络框架的文件下载请求:2.使用自带的DownloadManager类:本文介绍第二种,简单封装一下Downloa ...

  2. 一、app更新提示后台接口开发-(2)数据库表设计

    新建一张数据库表用来存储app更新信息 数据表为: CREATE TABLE APP_UPDATE_MESSAGE( APP_ID VARCHAR2(50),         --appId,01:a ...

  3. uniapp App更新解决方法

    uniapp App更新解决方法 最近项目碰到的app更新问题,安卓和iOS更新. 功能实现效果 安卓端:后台下载,自动弹出系统安装界面 iOS端:跳转 appStore app更新界面 1.获取用户 ...

  4. IOS APP更新问题

    苹果官方解释APP更新方式: https://support.apple.com/zh-cn/HT202180#iOS iOS app上架时由于包含版本升级更新而被拒 https://www.crif ...

  5. Android 蒲公英APP更新

    之前用蒲公英升级的时候遇到过一些坑,导致花了不少时间,现记录下来,便于自己和他人有更容易的认识和运用 蒲公英资料地址:https://www.pgyer.com/doc/view/new_sdk_an ...

  6. android app安装,Android App更新安装APK

    原标题:Android App更新安装APK 概要 一般地, Android App 都会被要求在App内进行软件更新提示, 让用户下载apk文件, 然后更新安装新版本, 一般过程如下: 检测是否有新 ...

  7. 淘客基地拾牛安卓APP更新至1.4版本

    淘客基地拾牛安卓APP更新至1.4版本,更新内容如下: 1.增加手机号登录.注册: 2.[商品详情]页面优化,增加店铺名.评论.产品参数等信息: 3.增加[找同款]功能(在商品详情页): 4.增加[代 ...

  8. **农商手机银行app更新代码后访问速度非常慢

    问题描述: **农商手机银行app更新代码后访问速度非常慢,几乎每个请求都非常的慢. 解决思路: 由于是远程支持解决,第一时间要了最近更新上去的代码,代码进行了review, 只是一些简单的业务代码更 ...

  9. 最骚气的APP更新文案盘点

    因为手机里 下了超多APP 每次打开AppStore都会很崩溃 这样的更新提示就问你怕不怕 要是一不小心按到「全部更新」 手机就彻底原!地!爆!炸! 所以我一般更新APP都会很谨慎 会看看更新了哪些东 ...

最新文章

  1. 『计算机视觉』经典RCNN_其一:从RCNN到Faster-RCNN
  2. Windows2008安装组件命令行工具ServerManagerCmd用法介绍
  3. Spring MVC拦截器示例
  4. altera fpga 型号说明_A/X家FPGA架构及资源评估
  5. python计算圆的面积
  6. 尤其是java程序员(转载)_JAVA程序员 学习任务(转载)
  7. 合格的前端不少,优秀的不多
  8. spring boot入门小案例
  9. Spark之StructuredStreaming
  10. 重设OS X (macOS)系统帐户密码的几种方法
  11. GDI+处理带透明区域的png图片
  12. 「前端早读君008」新手必踩坑之display: inline-block
  13. Python进阶全系列
  14. 计算机硬件技术基础教程mcs-51单片机原理及应用,mcs51单片机原理及应用
  15. js中定义变量时单引号和双引号的区别
  16. 开源数据库postgreSQL13在麒麟v10sp1源码安装
  17. 入门学习必收藏!精选Photoshop、D…
  18. 关于iPhone手机如何导入本地音乐
  19. MPEG最新进展 - 20191110
  20. 科技视界杂志科技视界杂志社科技视界编辑部2022年第21期目录

热门文章

  1. [HTML5-SVG]SVG是什么?SVG有什么用途?
  2. 苹果cms模板_苹果CMS提示“模板文件不存在”怎么办?
  3. 语言-汉语-官话-中原官话-兖菏片-菏泽方言:菏泽方言
  4. 小米 解析软件包时出现问题 解决
  5. 第二十三天 小丁再战链表
  6. 玩转【斗鱼直播APP】系列之实现无限轮播
  7. 苹果手机计算机隐藏应用,操作如此简单 iPhone十大隐藏功能汇总
  8. layui的lay-verify参数验证的问题
  9. 网络131黄宇倩--第二周作业
  10. Android开源项目 陌客随机聊天