背景
最近小组里需要替换升级模块,自己在GitHub上找到了一个挺不错的开源第三方库,AppUpdate感觉写得挺不错的,使用文档也说得挺详细,下面就对这个框架进行一下调用分析。
接口设计
检查是否有新版本接口
- 接口URL
mCheckUpdateUrl = mHostUrl + "/app/checkUpdate.do";
- 发送的数据
{
"appKey" :
// appKey是预先写在App的AndroidMenifest.xml文件中的
// 在发送请求的时候,后台进行这个appKey的判断,如果值不对,就不返回下载的信息了。
// 这个值事先需要跟后台协商好。
"ab55ce55Ac4bcP408cPb8c1Aaeac179c5f6f",
"version" : "1.0.2732"
}
- 返回的数据
{
"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\n3,区分自定义消费,一个小时不限制。\r\n4,添加放弃任务接口,小时内不生成。\r\n5,消费任务手动生成。",
"target_size": "5M",
"new_md5":"295687E756F569C7159974DD493489A5",
"constraint": false
}
后台数据库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 '是否启动更新,返回给客户端的时候,转成true',
`new_version` varchar(35) DEFAULT NULL COMMENT '最新版本号',
`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 '是否强制更新,0-false;1-true',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
调用方法
首先,导入基础框架的update-app
库,
使用方法很简单,在AndroidBase项目的LoginActivity页面,调用检查App的更新方法。
/**
* 检查是否需要更新
*/
private void checkUpdate() {
new UpdateAppManager.Builder().setActivity(this)
// 将versionName发送给后台,后台进行版本升级判断
.setUpdateUrl(AppContext.getInstance().getHostConfig().getmCheckUpdateUrl())
.setHttpManager(new OkGoUpdateHttpUtil())
.build()
// 设置升级方式
.silenceUpdate();
}
调用方法分析
构建UpdateAppManager作为Update-app库的入口,
通过使用UpdateAppManager的内部类Builder,完成参数的配置,最后构建出UpdateManager对象,调用更新方法。
配置参数
因为需要配置的参数比较多,UpdateAppManager使用了构造者模式,在UpdateAppManager有一个静态的内部类Builder
public static class Builder {
//必须有
private Activity mActivity;
//必须有
private HttpManager mHttpManager;
//必须有
private String mUpdateUrl;
//1,设置按钮,进度条的颜色
private int mThemeColor = 0;
//2,顶部的图片
private
@DrawableRes
int mTopPic = 0;
//3,唯一的appkey
private String mAppKey;
//4,apk的下载路径
private String mTargetPath;
//5,是否是post请求,默认是get
private boolean isPost;
//6,自定义参数
private Map<String, String> params;
//7,是否隐藏对话框下载进度条
private boolean mHideDialog;
private boolean mShowIgnoreVersion;
private boolean dismissNotificationProgress;
private boolean mOnlyWifi;
}
必须要设置的参数有三个Activity、HttpManager、UpdateUrl,当三个参数赋值完成后,调用Builder.build()的方法,创建UpdateAppManager对象。
HttpManager
这里有必要说一下HttpManager
,这是一个自己定义的接口
定义了发送的请求,下载回调,网络请求回调的规范。
由OkGoUpdateHttpUtil
实现
生成UpdateAppManager对象
/**
* @return 生成app管理器
*/
public UpdateAppManager build() {
//校验
if (getActivity() == null || getHttpManager() == null || TextUtils.isEmpty(getUpdateUrl())) {
throw new NullPointerException("必要参数不能为空");
}
if (TextUtils.isEmpty(getTargetPath())) {
// 设置下载路径
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
setTargetPath(path);
}
// 在AndroidMenifest.xml文件中添加的AppKey,可以给后台留作验证
// 增加了接口的安全性,可以让后台进行AppKey的校验,如果Key不对的话,就不进行下载
// 并不是必须的
// 如果在build的时候设置了自定义请求参数,这么这里添加的AppKey就不会传递给后台了。
// 除非在自定义请求参数中,将这个AppKey添加进去。
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);
}
调用更新方法
UpdateAppManager里的的silenceUpdate()
和update()
两个方法都是调用更新的方法,一个是静默更新,一个是最简单的更新方法,下面就来看看这两个方法的区别。
/**
* 静默更新
*/
public void silenceUpdate() {
checkNewApp(new SilenceUpdateCallback());
}
/**
* 最简方式
*/
public void update() {
checkNewApp(new UpdateCallback());
}
调用了build()
方法后,直接调用的更新方法
new UpdateAppManager.Builder().setActivity(this)
// 将versionName发送给后台,后台进行版本升级判断
.setUpdateUrl(AppContext.getInstance().getHostConfig().getmCheckUpdateUrl())
.setHttpManager(new OkGoUpdateHttpUtil())
.build()
// 调用更新方法
.silenceUpdate();
silenceUpdate()
和update()
方法都调用了checkNewApp(UpdateCallBack callBack)
方法,我们继续分析
这里传入的是一个实现了UpdateCallBack
的SilenceUpdateCallback
对象
/**
* 检测是否有新版本
*
* @param callback 更新回调
*/
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;
}
//拼接参数
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);
//添加自定义参数,其实可以实现HttManager中添加
if (mParams != null && !mParams.isEmpty()) {
//清空默认传递的参数,使用自定参数
params.clear();
params.putAll(mParams);
}
//网络请求
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 {
// 默认情况下使用的是get请求方式
mHttpManager.asyncGet(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();
}
});
}
}
-
parseData(String reulst, UpdateCallback callback)
解析
private void processData(String result, @NonNull UpdateCallback callback) {
try {
// 解析json数据
mUpdateApp = callback.parseJson(result);
if (mUpdateApp.isUpdate()) {
callback.hasNewApp(mUpdateApp, this);
//假如是静默下载,可能需要判断,
//是否wifi,
//是否已经下载,如果已经下载直接提示安装
//没有则进行下载,监听下载完成,弹出安装对话框
} else {
callback.noNewApp();
}
} catch (Exception ignored) {
ignored.printStackTrace();
callback.noNewApp();
}
}
展示框FragmentDialog
如果有新版本的话,会在登录页面上新建一个FragmentDialog
,用来展示本次更新的内容,以及调用APP的更新或者忽略本次版本。
protected void hasNewApp(UpdateAppBean updateApp, UpdateAppManager updateAppManager) {
updateAppManager.showDialogFragment();
}