背景
最近小組里需要替換升級(jí)模塊奈惑,自己在GitHub上找到了一個(gè)挺不錯(cuò)的開源第三方庫,AppUpdate感覺寫得挺不錯(cuò)的,使用文檔也說得挺詳細(xì)柬焕,下面就對(duì)這個(gè)框架進(jìn)行一下調(diào)用分析璧坟。
接口設(shè)計(jì)
檢查是否有新版本接口
- 接口URL
mCheckUpdateUrl = mHostUrl + "/app/checkUpdate.do";
- 發(fā)送的數(shù)據(jù)
{
"appKey" :
// appKey是預(yù)先寫在App的AndroidMenifest.xml文件中的
// 在發(fā)送請(qǐng)求的時(shí)候,后臺(tái)進(jìn)行這個(gè)appKey的判斷,如果值不對(duì)掸读,就不返回下載的信息了留搔。
// 這個(gè)值事先需要跟后臺(tái)協(xié)商好。
"ab55ce55Ac4bcP408cPb8c1Aaeac179c5f6f",
"version" : "1.0.2732"
}
- 返回的數(shù)據(jù)
{
"update": "Yes",
"new_version": "0.8.3",
"apk_file_url": "https://raw.githubusercontent.com/WVector/AppUpdateDemo/master/apk/app-debug.apk",
"update_log": "1萌业,添加刪除信用卡接口档叔。\r\n2,添加vip認(rèn)證。\r\n3雾消,區(qū)分自定義消費(fèi),一個(gè)小時(shí)不限制巨缘。\r\n4仲器,添加放棄任務(wù)接口昼捍,小時(shí)內(nèi)不生成。\r\n5,消費(fèi)任務(wù)手動(dòng)生成怀挠。",
"target_size": "5M",
"new_md5":"295687E756F569C7159974DD493489A5",
"constraint": false
}
后臺(tái)數(shù)據(jù)庫sql腳本
-- ----------------------------
-- Table structure for `app_update`
-- ----------------------------
DROP TABLE IF EXISTS `app_update`;
CREATE TABLE `app_update` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`update` int(11) DEFAULT '1' COMMENT '是否啟動(dòng)更新裁赠,返回給客戶端的時(shí)候,轉(zhuǎn)成true',
`new_version` varchar(35) DEFAULT NULL COMMENT '最新版本號(hào)',
`apk_file_url` varchar(500) DEFAULT NULL COMMENT 'apk的下載路徑',
`update_log` varchar(500) DEFAULT NULL COMMENT '更新信息',
`target_size` varchar(10) DEFAULT NULL COMMENT 'apk安裝包大小',
`new_md5` varchar(255) DEFAULT NULL COMMENT '新apk的MD5碼',
`constraint` int(11) DEFAULT '0' COMMENT '是否強(qiáng)制更新,0-false;1-true',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
調(diào)用方法
首先荷科,導(dǎo)入基礎(chǔ)框架的update-app
庫,
使用方法很簡(jiǎn)單氧枣,在AndroidBase項(xiàng)目的LoginActivity頁面,調(diào)用檢查App的更新方法。
/**
* 檢查是否需要更新
*/
private void checkUpdate() {
new UpdateAppManager.Builder().setActivity(this)
// 將versionName發(fā)送給后臺(tái)钳吟,后臺(tái)進(jìn)行版本升級(jí)判斷
.setUpdateUrl(AppContext.getInstance().getHostConfig().getmCheckUpdateUrl())
.setHttpManager(new OkGoUpdateHttpUtil())
.build()
// 設(shè)置升級(jí)方式
.silenceUpdate();
}
調(diào)用方法分析
構(gòu)建UpdateAppManager作為Update-app庫的入口壁酬,
通過使用UpdateAppManager的內(nèi)部類Builder斜纪,完成參數(shù)的配置,最后構(gòu)建出UpdateManager對(duì)象芋酌,調(diào)用更新方法疚顷。
配置參數(shù)
因?yàn)樾枰渲玫膮?shù)比較多浸船,UpdateAppManager使用了構(gòu)造者模式李命,在UpdateAppManager有一個(gè)靜態(tài)的內(nèi)部類Builder
public static class Builder {
//必須有
private Activity mActivity;
//必須有
private HttpManager mHttpManager;
//必須有
private String mUpdateUrl;
//1阔籽,設(shè)置按鈕笆制,進(jìn)度條的顏色
private int mThemeColor = 0;
//2,頂部的圖片
private
@DrawableRes
int mTopPic = 0;
//3,唯一的appkey
private String mAppKey;
//4,apk的下載路徑
private String mTargetPath;
//5,是否是post請(qǐng)求完残,默認(rèn)是get
private boolean isPost;
//6,自定義參數(shù)
private Map<String, String> params;
//7,是否隱藏對(duì)話框下載進(jìn)度條
private boolean mHideDialog;
private boolean mShowIgnoreVersion;
private boolean dismissNotificationProgress;
private boolean mOnlyWifi;
}
必須要設(shè)置的參數(shù)有三個(gè)Activity、HttpManager、UpdateUrl钠龙,當(dāng)三個(gè)參數(shù)賦值完成后,調(diào)用Builder.build()的方法御铃,創(chuàng)建UpdateAppManager對(duì)象碴里。
HttpManager
這里有必要說一下HttpManager
,這是一個(gè)自己定義的接口
定義了發(fā)送的請(qǐng)求上真,下載回調(diào)咬腋,網(wǎng)絡(luò)請(qǐng)求回調(diào)的規(guī)范。
由OkGoUpdateHttpUtil
實(shí)現(xiàn)
生成UpdateAppManager對(duì)象
/**
* @return 生成app管理器
*/
public UpdateAppManager build() {
//校驗(yàn)
if (getActivity() == null || getHttpManager() == null || TextUtils.isEmpty(getUpdateUrl())) {
throw new NullPointerException("必要參數(shù)不能為空");
}
if (TextUtils.isEmpty(getTargetPath())) {
// 設(shè)置下載路徑
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
setTargetPath(path);
}
// 在AndroidMenifest.xml文件中添加的AppKey谷羞,可以給后臺(tái)留作驗(yàn)證
// 增加了接口的安全性帝火,可以讓后臺(tái)進(jìn)行AppKey的校驗(yàn),如果Key不對(duì)的話湃缎,就不進(jìn)行下載
// 并不是必須的
// 如果在build的時(shí)候設(shè)置了自定義請(qǐng)求參數(shù)犀填,這么這里添加的AppKey就不會(huì)傳遞給后臺(tái)了。
// 除非在自定義請(qǐng)求參數(shù)中嗓违,將這個(gè)AppKey添加進(jìn)去九巡。
if (TextUtils.isEmpty(getAppKey())) {
String appKey = AppUpdateUtils.getManifestString(getActivity(), UPDATE_APP_KEY);
if (TextUtils.isEmpty(appKey)) {
} else {
setAppKey(appKey);
}
}
// 這里的this就指的是Builder
return new UpdateAppManager(this);
}
調(diào)用更新方法
UpdateAppManager里的的silenceUpdate()
和update()
兩個(gè)方法都是調(diào)用更新的方法,一個(gè)是靜默更新蹂季,一個(gè)是最簡(jiǎn)單的更新方法冕广,下面就來看看這兩個(gè)方法的區(qū)別。
/**
* 靜默更新
*/
public void silenceUpdate() {
checkNewApp(new SilenceUpdateCallback());
}
/**
* 最簡(jiǎn)方式
*/
public void update() {
checkNewApp(new UpdateCallback());
}
調(diào)用了build()
方法后偿洁,直接調(diào)用的更新方法
new UpdateAppManager.Builder().setActivity(this)
// 將versionName發(fā)送給后臺(tái)撒汉,后臺(tái)進(jìn)行版本升級(jí)判斷
.setUpdateUrl(AppContext.getInstance().getHostConfig().getmCheckUpdateUrl())
.setHttpManager(new OkGoUpdateHttpUtil())
.build()
// 調(diào)用更新方法
.silenceUpdate();
silenceUpdate()
和update()
方法都調(diào)用了checkNewApp(UpdateCallBack callBack)
方法,我們繼續(xù)分析
這里傳入的是一個(gè)實(shí)現(xiàn)了UpdateCallBack
的SilenceUpdateCallback
對(duì)象
/**
* 檢測(cè)是否有新版本
*
* @param callback 更新回調(diào)
*/
public void checkNewApp(final UpdateCallback callback) {
if (callback == null) {
return;
}
callback.onBefore();
if (DownloadService.isRunning || UpdateDialogFragment.isShow) {
callback.onAfter();
Toast.makeText(mActivity, "app正在更新", Toast.LENGTH_SHORT).show();
return;
}
//拼接參數(shù)
Map<String, String> params = new HashMap<String, String>();
params.put("appKey", mAppKey);
String versionName = AppUpdateUtils.getVersionName(mActivity);
if (versionName.endsWith("-debug")) {
versionName = versionName.substring(0, versionName.lastIndexOf('-'));
}
params.put("version", versionName);
//添加自定義參數(shù)涕滋,其實(shí)可以實(shí)現(xiàn)HttManager中添加
if (mParams != null && !mParams.isEmpty()) {
//清空默認(rèn)傳遞的參數(shù)睬辐,使用自定參數(shù)
params.clear();
params.putAll(mParams);
}
//網(wǎng)絡(luò)請(qǐng)求
if (isPost) {
mHttpManager.asyncPost(mUpdateUrl, params, new HttpManager.Callback() {
@Override
public void onResponse(String result) {
callback.onAfter();
if (result != null) {
processData(result, callback);
}
}
@Override
public void onError(String error) {
callback.onAfter();
callback.noNewApp();
}
});
} else {
// 默認(rèn)情況下使用的是get請(qǐng)求方式
mHttpManager.asyncGet(mUpdateUrl, params, new HttpManager.Callback() {
@Override
public void onResponse(String result) {
callback.onAfter();
if (result != null) {
// 解析服務(wù)器返回的數(shù)據(jù)
processData(result, callback);
}
}
@Override
public void onError(String error) {
callback.onAfter();
callback.noNewApp();
}
});
}
}
-
parseData(String reulst, UpdateCallback callback)
解析
private void processData(String result, @NonNull UpdateCallback callback) {
try {
// 解析json數(shù)據(jù)
mUpdateApp = callback.parseJson(result);
if (mUpdateApp.isUpdate()) {
callback.hasNewApp(mUpdateApp, this);
//假如是靜默下載,可能需要判斷,
//是否wifi,
//是否已經(jīng)下載溯饵,如果已經(jīng)下載直接提示安裝
//沒有則進(jìn)行下載侵俗,監(jiān)聽下載完成,彈出安裝對(duì)話框
} else {
callback.noNewApp();
}
} catch (Exception ignored) {
ignored.printStackTrace();
callback.noNewApp();
}
}
展示框FragmentDialog
如果有新版本的話丰刊,會(huì)在登錄頁面上新建一個(gè)FragmentDialog
隘谣,用來展示本次更新的內(nèi)容,以及調(diào)用APP的更新或者忽略本次版本啄巧。
protected void hasNewApp(UpdateAppBean updateApp, UpdateAppManager updateAppManager) {
updateAppManager.showDialogFragment();
}