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源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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