AppUpdate分析

背景

最近小组里需要替换升级模块,自己在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)方法,我们继续分析

这里传入的是一个实现了UpdateCallBackSilenceUpdateCallback对象

/**
 * 检测是否有新版本
 *
 * @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();
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,445评论 25 707
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,863评论 6 13
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,573评论 18 399
  • 一个大三学生的反思 今天早上古代文学课,一个学音乐的和我们一届的学生给我们讲了一节关于宋词词牌名的课,对,...
    蓝色叉烧包阅读 556评论 0 0