美文网首页程序员
灵活的版本更新库封装

灵活的版本更新库封装

作者: 289346a467da | 来源:发表于2018-03-08 19:13 被阅读65次

PrimUpdate

灵活的版本更新库

客户端处理版本更新流程分析

1. 获取APP的相关信息,向服务器发送版本更新请求
2. 如果没有更新 --> 做对应的操作
3. 如果有更新 --> 是强制更新,还是非强制更新
4. 如果是强制更新 --> 用户必须进行更新操作(更新可能包括 全量更新或增量更新)
5. 如果是非强制更新 --> 用户选择进行更新操作 (更新可能包括 全量更新或增量更新)
6. 如果是非强制更新 --> 用户不选择更新操作 --> 是否静默后台下载安装包操作
7. 有安装包提示用户安装

版本更新封装流程分析

  • UpdateManager版本更新的管理者:决定事情的方向,管理者只需要知道任务的执行度和完成情况.
  • 具体如何实现交给总管去分配和督查所有任务{@link UpdateExplorer} 将任务情况报告给管理者
    UpdateExplorer版本更新的总管,分配和督查所有任务:
  • 以下为任务步骤
  • 任务开始 -- 总管得到管理者的决策后开始分配任务
  • 任务步骤1 - 检测版本更新 --> 具体实现者:{@link IUpdateChecker}
  • 任务步骤2 - 解析json转换为bean --> 具体实现者:{@link IUpdateConverter}
  • 任务步骤3 - 对bean进行分析采取方案 --> 具体实现者:{@link IUpdatePlan}
  • 任务步骤4 - 版本更新UI提示 --> 具体实现者:{@link IUpdatePrompter}
  • 任务步骤5 - 下载apk --> 具体实现者:{@link IUpdateDownloader}
  • 任务步骤6 - 下载过程中的UI显示 --> 具体实现者:{@link OnDownloadListener}
  • 任务步骤7 - 安装apk --> 具体实现者:{@link IUpdateFile}
  • 任务步骤8 - 记录-过程穿插整个任务过程--> 具体实现者:{@link IUpdateLogger}
  • 任务完成 -- 由总管向管理者汇报任务情况,并把任务记录传给管理者
  • 中间可以插入扩展任务,具体实现看业务需求

灵活

其中每一个任务步骤都可以进行重写、插入、根据业务需求扩展

可扩展的地方:

UpdateConverter 转换数据类,将json字符串转换成bean

public class UpdateConverter implements IUpdateConverter {

    /**
     * 重要的事情说三遍
     * 请自行修改,不同的项目服务器和客户端约定一个数表示成功
     * 请自行修改,不同的项目服务器会和客户端约定一个数表示成功
     * 请自行修改,不同的项目服务器会和客户端约定一个数表示成功
     */
    private String SUCCESS = "0";

    private static final String TAG = "UpdateConverter";

    @Override
    public UpdateInfo convertJson(String info, IUpdateExplorer explorer) throws Throwable {
        UpdateState.setState(StateType.CONVERTER);
        try {
            // 重要的事情说三遍
            // json bean 自行修改
            // json bean 自行修改
            // json bean 自行修改
            LzyResponse lzy = GsonUtill.getObejctFromJSON(info, LzyResponse.class);
            if (lzy.result.errorCode.equals(SUCCESS)) {
                // 重要的事情说三遍
                // 如果bean 不一样请注意更换为UpdateInfo bean
                // 如果bean 不一样请注意更换为UpdateInfo bean
                // 如果bean 不一样请注意更换为UpdateInfo bean
                return lzy.data;
            } else {
                explorer.stop();
                return null;
            }
        } catch (Exception e) {
            explorer.stop();
            return null;
        }
    }
}

UpdatePlaner 对解析到的bean 判断采取对应的方案

public class UpdatePlaner implements IUpdatePlan {
    private static final String TAG = "UpdatePlaner";

    @Override
    public void plan(UpdateInfo info, IUpdateExplorer explorer) {
        Log.e(TAG, "plan: " + info);
        UpdateState.setState(StateType.PLAN);
        if (info == null) {
            explorer.stop();
            return;
        }
        if (info.isNoUpdate()) {//不需要更新,终止任务
            explorer.stop();
        } else {//需要更新
            //判断用户是否忽略了更新 如果用户忽略了更新不再提示该版本 任务终止
            if (SPUtils.getInstance("ignore").getBoolean(info.getVersion_name(), false)) {
                if (explorer.getBuilder().isIgnorable) {
                    explorer.stop();
                    explorer.showToast("已忽略该版本:" + info.getVersion_name());
                    return;
                } else {
                    SPUtils.getInstance("ignore").clear();
                }
            }
            //如果用户没有忽略更新
            //1 先判断最新的apk包是否存在
            //2 存储第一次更新UI提示时间
            //3 获取服务器返回的提示周期或者是一天内的提示次数,具体规则根据业务需求定制
            if (explorer.isApkCompleteExits()) {// 最新apk存在
                 /* 用户是否设置了强制重新下载 */
                if (explorer.getBuilder().isDownloadAgain) {
                    FileUtils.deleteFile(explorer.getDownloadPath());
                    explorer.doPrompter(UpdateExplorer.PrompterType.update);//更新提示
                } else {
                    explorer.doPrompter(UpdateExplorer.PrompterType.install);//安装UI提示
                }
            } else if (explorer.isAutoDownload()) {// 发现新版本自动下载apk
                explorer.doDownload();// 不需要任何UI提示
            } else {
                serverUpdateTime(info, explorer);
            }
        }
    }

    /** 根据更新UI提示的时间 */
    private void serverUpdateTime(UpdateInfo info, IUpdateExplorer explorer) {
        if (!explorer.getBuilder().isCycleUpdatePrompter) {//没有开启周期UI提示
            explorer.doPrompter(UpdateExplorer.PrompterType.update);//更新UI提示
            SPUtils.getInstance("Update").clear();
            return;
        }
        String logUpdateTime = SPUtils.getInstance("Update").getString(info.getVersion_name());
        if (TextUtils.isEmpty(logUpdateTime)) {// 第一次提示
            explorer.doPrompter(UpdateExplorer.PrompterType.update);//更新UI提示
            //记录当前提示的时间
            SPUtils.getInstance("Update").put(info.getVersion_name(), String.valueOf(System.currentTimeMillis()));
        } else {// 第二次提示
            if (explorer.getBuilder().prompterPriority) {//true 手动设置的优先级高 以手动设置的时间为准
                if (explorer.getBuilder().prompterTime == -1) {//若没有设置手动时间以服务器时间为准
                    checkTime(info, explorer, logUpdateTime, info.getTime());
                } else {//如果设置了手动时间
                    checkTime(info, explorer, logUpdateTime, explorer.getBuilder().prompterTime);
                }
            } else {
                checkTime(info, explorer, logUpdateTime, info.getTime());
            }

        }
    }

    /** 检查时间 */
    private void checkTime(UpdateInfo info, IUpdateExplorer explorer, String logUpdateTime, int time) {
        if (Utils.getUpdateTime(logUpdateTime, time)) {//已超过设定的提示时间
            explorer.doPrompter(UpdateExplorer.PrompterType.update);//更新UI提示
            //记录当前提示的时间
            SPUtils.getInstance("Update").put(info.getVersion_name(), String.valueOf(System.currentTimeMillis()));
        } else {
            explorer.showToast("没有超过设定的提示周期:" + time + "天");
            explorer.stop();
        }
    }

}

UI提示的修改:更新提示弹窗、下载提示弹窗等

TODO

继续优化的点:
支持patch更新

代码地址:https://github.com/JakePrim/VersionUpdate

相关文章

网友评论

    本文标题:灵活的版本更新库封装

    本文链接:https://www.haomeiwen.com/subject/mxayfftx.html