XUpdate 一个轻量级、高可用性的Android版本更新框架

相信大家平时在做应用开发的时候,避免不了需求变更、功能增加,这个时候一定会想办法对应用进行更新。而应用更新可分为全量更新和增量更新,对于线上的一些小而急的bug,我们可以使用热更新这种增量更新的方式,及时有效地解决问题,但如果是一个比较大的功能迭代的话,就势必要用到全量更新。

今天给大家介绍的XUpdate就是一个轻量级、高可用性的Android全量更新的框架。全量更新没有增量更新那么复杂的处理逻辑,核心内容无非以下三点:

  • 查询是否有新版本。

  • 版本信息展示。

  • 新版本APK下载和安装。

没有任何复杂的东西,流程也相对比较单一固定,和业务绑定较少,因此完全可以做成库,方便使用。

项目地址:

https://github.com/xuexiangjys/XUpdate

特征

  • 支持post和get两种版本检查方式,支持自定义网络请求。

  • 支持设置只在wifi下进行版本更新。

  • 支持静默下载(后台更新)、自动版本更新。

  • 提供界面友好的版本更新提示弹窗,可自定义其主题样式。

  • 支持自定义版本更新检查器、版本更新解析器、版本更新提示器、版本更新下载器、版本更新安装、出错处理。

  • 支持MD5文件校验、版本忽略、版本强制更新等功能。

  • 支持自定义请求API接口。

  • 兼容Android6.0、7.0和8.0。

  • 支持中文和英文两种语言显示(国际化)

组成结构

本框架借鉴了AppUpdate中的部分思想和UI界面,将版本更新中的各部分环节抽离出来,形成了如下几个部分:

  • 版本更新检查器 IUpdateChecker

    检查是否有最新版本。

  • 版本更新解析器 IUpdateParser

    解析服务端返回的数据结果。

  • 版本更新提示器 IUpdatePrompter

    展示最新的版本信息。

  • 版本更新下载器 IUpdateDownloader

    下载最新的版本APK安装包。

  • 网络请求服务接口 IUpdateHttpService


定义了进行网络请求的相关接口。 除此之外,还有两个监听器:

  • 版本更新失败的监听器 OnUpdateFailureListener

  • 版本更新apk安装的监听器 OnInstallListener

更新调度核心:

  • 版本更新业务代理 IUpdateProxy:负责版本更新的流程控制,调用update开始进行版本更新流程。

更新流程

调用update之后的流程:

  
  
  
  1. IUpdateProxy/XUpdate --- (update) ---> IUpdateChecker --->(请求服务器,获取最新版本信息)---> IUpdateParser ---> (解析服务器返回的数据,并构建UpdateEntity版本更新实体)---> IUpdateProxy ---> (如无最新版本,直接结束,否则进行下面流程)


  2.    ---自动模式---> IUpdateDownloader ---> (下载最新的应用apk) ---> 安装应用


  3.    ---非自动模式---> IUpdatePrompter ---> 给出版本更新的提示


  4.                                                        ---> 用户点击更新 ---> IUpdateDownloader ---> (下载最新的应用apk) ---> 跳转到应用安装界面


  5.                                                        ---> 用户点击(取消或忽略) ---> 结束

1、演示(请star支持)

  • 默认版本更新

  • 强制版本更新

  • 自定义提示弹窗主题

  • 使用系统弹窗提示

  • Demo更新后台服务

由于github最近访问比较慢,如果需要更好地体验XUpdate,你可以点击自己搭建一个简易的版本更新服务。

Demo下载

2、如何使用

2.1、添加Gradle依赖

1.先在项目根目录的 build.gradle 的 repositories 添加:

  
  
  
  1. allprojects {

  2.     repositories {

  3.        ...

  4.        maven { url "https://jitpack.io" }

  5.    }

  6. }

2.然后在dependencies添加:

  
  
  
  1. dependencies {

  2.  ...

  3.  implementation 'com.github.xuexiangjys:XUpdate:1.0.6'

  4. }

2.2、初始化XUpdate

在Application进行初始化配置:

  
  
  
  1. XUpdate.get()

  2.        .debug(true) //开启debug模式,可用于问题的排查

  3.        .isWifiOnly(true)     //默认设置只在wifi下检查版本更新

  4.        .isGet(true)          //默认设置使用get请求检查版本

  5.        .isAutoMode(false)    //默认设置非自动模式,可根据具体使用配置

  6.        .param("VersionCode", UpdateUtils.getVersionCode(this)) //设置默认公共请求参数

  7.        .param("AppKey", getPackageName())

  8.        .setOnUpdateFailureListener(new OnUpdateFailureListener() { //设置版本更新出错的监听

  9.            @Override

  10.            public void onFailure(UpdateError error) {

  11.                ToastUtils.toast(error.toString());

  12.            }

  13.        })

  14.        .setIUpdateHttpService(new OKHttpUpdateHttpService()) //这个必须设置!实现网络请求功能。

  15.        .init(this);   //这个必须初始化

【注意】:如果出现任何问题,可开启debug模式来追踪问题。如果你还需要将日志记录在磁盘上,可实现以下接口

  
  
  
  1. XUpdate.get().setILogger(new ILogger() {

  2.    @Override

  3.    public void log(int priority, String tag, String message, Throwable t) {

  4.        //实现日志记录功能

  5.    }

  6. });

2.3、版本更新实体信息

(1) UpdateEntity字段属性

字段名 类型 默认值 备注
mHasUpdate boolean false 是否有新版本
mIsForce boolean false 是否强制安装:不安装无法使用app
mIsIgnorable boolean false 是否可忽略该版本
mVersionCode int 0 最新版本code
mVersionName String unknown_version 最新版本名称
mUpdateContent String "" 更新内容
mDownloadEntity DownloadEntity 下载信息实体
mIsSilent boolean false 是否静默下载:有新版本时不提示直接下载
mIsAutoInstall boolean true 是否下载完成后自动安装

(2) DownloadEntity字段属性

字段名 类型 默认值 备注
mDownloadUrl String "" 下载地址
mCacheDir String "" 文件下载的目录
mMd5 String "" 下载文件的md5值,用于校验,防止下载的apk文件被替换
mSize long 0 下载文件的大小【单位:KB】
mIsShowNotification boolean false 是否在通知栏上显示下载进度

3、版本更新

3.1、默认版本更新

直接调用如下代码即可完成版本更新操作:

  
  
  
  1. XUpdate.newBuild(getActivity())

  2.        .updateUrl(mUpdateUrl)

  3.        .update();

需要注意的是,使用默认版本更新,请求服务器返回的json格式应包括如下内容:

  
  
  
  1. {

  2.  "Code": 0,

  3.  "Msg": "",

  4.  "UpdateStatus": 1,

  5.  "VersionCode": 3,

  6.  "VersionName": "1.0.2",

  7.  "ModifyContent": "1、优化api接口。\r\n2、添加使用demo演示。\r\n3、新增自定义更新服务API接口。\r\n4、优化更新提示界面。",

  8.  "DownloadUrl": "https://raw.githubusercontent.com/xuexiangjys/XUpdate/master/apk/xupdate_demo_1.0.2.apk",

  9.  "ApkSize": 2048

  10.  "ApkMd5": "..."  //md5值没有的话,就无法保证apk是否完整,每次都会重新下载。

  11. }

3.2、自动版本更新

自动版本更新:自动检查版本 + 自动下载apk + 自动安装apk(静默安装)。 只需要设置 isAutoMode(true),不过如果设备没有root权限的话,是无法做到完全的自动更新(因为静默安装需要root权限)。

  
  
  
  1. XUpdate.newBuild(getActivity())

  2.        .updateUrl(mUpdateUrl)

  3.        .isAutoMode(true) //如果需要完全无人干预,自动更新,需要root权限【静默安装需要】

  4.        .update();

3.3、强制版本更新

就是用户不更新的话,程序将无法正常使用。只需要服务端返回 UpdateStatus字段为2即可。

当然如果你自定义请求返回api的话,只需要设置 UpdateEntity的 mIsForce字段为true即可。

3.4、自定义版本更新提示弹窗的主题

可设置弹窗的标题背景和按钮颜色。

  • themeColor: 设置主题颜色(升级/安装按钮的背景色)

  • topResId: 弹窗的标题背景的资源图片

  
  
  
  1. XUpdate.newBuild(getActivity())

  2.        .updateUrl(mUpdateUrl)

  3.        .themeColor(ResUtils.getColor(R.color.update_theme_color))

  4.        .topResId(R.mipmap.bg_update_top)

  5.        .update();

3.5、自定义版本更新解析器

实现IUpdateParser接口即可实现解析器的自定义。

  
  
  
  1. XUpdate.newBuild(getActivity())

  2.        .updateUrl(mUpdateUrl3)

  3.        .updateParser(new CustomUpdateParser()) //设置自定义的版本更新解析器

  4.        .update();


  5. public class CustomUpdateParser implements IUpdateParser {

  6.    @Override

  7.    public UpdateEntity parseJson(String json) throws Exception {

  8.        CustomResult result = JsonUtil.fromJson(json, CustomResult.class);

  9.        if (result != null) {

  10.            return new UpdateEntity()

  11.                    .setHasUpdate(result.hasUpdate)

  12.                    .setIsIgnorable(result.isIgnorable)

  13.                    .setVersionCode(result.versionCode)

  14.                    .setVersionName(result.versionName)

  15.                    .setUpdateContent(result.updateLog)

  16.                    .setDownloadUrl(result.apkUrl)

  17.                    .setSize(result.apkSize);

  18.        }

  19.        return null;

  20.    }

  21. }

3.6、自定义版本更新检查器+版本更新解析器+版本更新提示器


  • 实现 IUpdateChecker接口即可实现检查器的自定义。


  • 实现 IUpdateParser接口即可实现解析器的自定义。


  • 实现 IUpdatePrompter接口即可实现提示器的自定义。

  
  
  
  1. XUpdate.newBuild(getActivity())

  2.        .updateUrl(mUpdateUrl3)

  3.        .updateChecker(new DefaultUpdateChecker() {

  4.            @Override

  5.            public void onBeforeCheck() {

  6.                super.onBeforeCheck();

  7.                CProgressDialogUtils.showProgressDialog(getActivity(), "查询中...");

  8.            }

  9.            @Override

  10.            public void onAfterCheck() {

  11.                super.onAfterCheck();

  12.                CProgressDialogUtils.cancelProgressDialog(getActivity());

  13.            }

  14.        })

  15.        .updateParser(new CustomUpdateParser())

  16.        .updatePrompter(new CustomUpdatePrompter(getActivity()))

  17.        .update();



  18. public class CustomUpdatePrompter implements IUpdatePrompter {


  19.    private Context mContext;


  20.    public CustomUpdatePrompter(Context context) {

  21.        mContext = context;

  22.    }


  23.    @Override

  24.    public void showPrompt(@NonNull UpdateEntity updateEntity, @NonNull IUpdateProxy updateProxy, @NonNull PromptEntity promptEntity) {

  25.        showUpdatePrompt(updateEntity, updateProxy);

  26.    }


  27.    /**

  28.     * 显示自定义提示

  29.     *

  30.     * @param updateEntity

  31.     * @param updateProxy

  32.     */

  33.    private void showUpdatePrompt(final @NonNull UpdateEntity updateEntity, final @NonNull IUpdateProxy updateProxy) {

  34.        String updateInfo = UpdateUtils.getDisplayUpdateInfo(mContext, updateEntity);


  35.        new AlertDialog.Builder(mContext)

  36.                .setTitle(String.format("是否升级到%s版本?", updateEntity.getVersionName()))

  37.                .setMessage(updateInfo)

  38.                .setPositiveButton("升级", new DialogInterface.OnClickListener() {

  39.                    @Override

  40.                    public void onClick(DialogInterface dialog, int which) {

  41.                        updateProxy.startDownload(updateEntity, new OnFileDownloadListener() {

  42.                            @Override

  43.                            public void onStart() {

  44.                                HProgressDialogUtils.showHorizontalProgressDialog(mContext, "下载进度", false);

  45.                            }


  46.                            @Override

  47.                            public void onProgress(float progress, long total) {

  48.                                HProgressDialogUtils.setProgress(Math.round(progress * 100));

  49.                            }


  50.                            @Override

  51.                            public boolean onCompleted(File file) {

  52.                                HProgressDialogUtils.cancel();

  53.                                return true;

  54.                            }


  55.                            @Override

  56.                            public void onError(Throwable throwable) {

  57.                                HProgressDialogUtils.cancel();

  58.                            }

  59.                        });

  60.                    }

  61.                })

  62.                .setNegativeButton("暂不升级", null)

  63.                .setCancelable(false)

  64.                .create()

  65.                .show();

  66.    }

3.7、只使用XUpdate的下载器功能进行apk的下载

  
  
  
  1. XUpdate.newBuild(getActivity())

  2.        .apkCacheDir(PathUtils.getExtDownloadsPath()) //设置下载缓存的根目录

  3.        .build()

  4.        .download(mDownloadUrl, new OnFileDownloadListener() {   //设置下载的地址和下载的监听

  5.            @Override

  6.            public void onStart() {

  7.                HProgressDialogUtils.showHorizontalProgressDialog(getContext(), "下载进度", false);

  8.            }


  9.            @Override

  10.            public void onProgress(float progress, long total) {

  11.                HProgressDialogUtils.setProgress(Math.round(progress * 100));

  12.            }


  13.            @Override

  14.            public boolean onCompleted(File file) {

  15.                HProgressDialogUtils.cancel();

  16.                ToastUtils.toast("apk下载完毕,文件路径:" + file.getPath());

  17.                return false;

  18.            }


  19.            @Override

  20.            public void onError(Throwable throwable) {

  21.                HProgressDialogUtils.cancel();

  22.            }

  23.        });

3.8、只使用XUpdate的APK安装的功能

  
  
  
  1. _XUpdate.startInstallApk(getContext(), FileUtils.getFileByPath(PathUtils.getFilePathByUri(getContext(), data.getData()))); //填写文件所在的路径

如果你的apk安装与众不同,你可以实现自己的apk安装器。你只需要实现OnInstallListener接口,并通过 XUpdate.setOnInstallListener进行设置即可生效。

混淆配置

  
  
  
  1. -keep class com.xuexiang.xupdate.entity.** { *; }

特别感谢

https://github.com/WVector/AppUpdate

扫码关注


本文分享自微信公众号 - 我的Android开源之旅(openandroidxx)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章