博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
App开发:强制更新app
阅读量:4130 次
发布时间:2019-05-25

本文共 10247 字,大约阅读时间需要 34 分钟。

推荐第三种方式,简单快捷不卡。

第一种:jjdxm_update

GitHub地址:

效果图:

点击立即更新,程序会在后台下载,通知栏有下载进度。这个时候手机系统很卡,可能由于是下载app的原因吧。下载完成后弹出安装界面

这里写图片描述

这里写图片描述
这里写图片描述
这里写图片描述

简介:

这是大神jjdxmashl的开源项目,下载地址见上方。有版本更新、手动更新、静默更新、自动更新4种情况。应用内更新,实现类是友盟自动更新sdk的模式,用户使用前只需要配置自己的服务器更新检查接口即可(必须接口),也可以扩展加入一个接口作为在线参数配置来实现,可以实现下面的4种2更新方式和是否强制更新组合使用,支持get、post方式请求网络,默认是get请求。

4种更新检查类型

  1. 手动更新:手动检测更新(所有网络类型环境检测并提示主要用于点击检测使用)
  2. 自动更新:自动检测更新(所有网络类型环境检测并提示)
  3. 仅WiFi自动检测更新(只有WiFi网络类型环境检测并提示)
  4. 静默更新:仅WiFi自动检测下载(只有WiFi网络类型环境检测、下载完才提示)

2种强制更新方式

  1. 在更新检查返回后,直接设置update.setForce(true)
  2. 配合在线参数使用,通过在线参数返回的数据设置UpdateHelper.getInstance().setForced(true)

上述4中更新检查 结合 2种强制更新,适用于:上一个app版本有重大漏洞,修改在线 参数统一控制所有的app用户,不更新就不可以使用app。

主要原理:服务器上修改参数值,app端获取后进行判断,如果是强制更新,则在打开应用时就提示有新版本的app,更新完成后才可以使用该app;更新为完成,则提示框不消失,点击back键则退出应用。

强制更新的使用

下面演示的是强制更新的情况,

这里写图片描述

Step1:添加依赖库

在主程序的build.gradle文件的dependencies属性中添加依赖库

dependencies {    ...    compile 'com.dou361.update:jjdxm-update:1.0.5'    compile 'com.dou361.download:jjdxm-download:1.0.3'    ...}

Step2:配置更新接口参数信息,初始化参数接口和解析参数

必须配置的是在线更新接口和该接口返回数据的解析

可选的是在线参数接口和该接口返回数据的解析(一般用不到),在线参数可以随机定义零个或多个不同意义的参数来达到在线修改apk的部分特性。

Step2-1 创建一个自动更新的配置类

方法+参数 含义
setCheckUrl(checkUrl) checkUrl:更新app的接口
setCheckJsonParser(new ParseData() {return update;} 只能返回Update类型,解析可以随便解析,但要把解析到的数据赋值给update,再把update返回
public class UpdateConfig {    private static final String TAG = "UpdateConfig";    private static String checkUrl = "http://192.168.1.11:8080/cmcc/jsoninfo";    public static void init(Context context) {        UpdateHelper.init(context);        UpdateHelper.getInstance()                .setMethod(RequestType.get)// 可填:请求方式,默认为get请求                .setCheckUrl(checkUrl)// 必填:数据更新接口,方法有重载带参数的setCheckUrl(checkUrl, params)                .setDialogLayout(R.layout.custom_update_dialog)//自定义的更新dialog                .setCheckJsonParser(new ParseData() {
// 必填:用于从数据更新接口获取的数据response中。解析出Update实例。以便框架内部处理 @Override public Update parse(String response) { Log.d(TAG, "response=" + response); //解析json数据 Gson gson = new Gson(); UpDateBean upDateBean = gson.fromJson(response, UpDateBean.class); UpDateBean.DataBean data = upDateBean.getData(); Update update = new Update(); update.setForce(data.isForce()); update.setApkSize(data.getV_size()); update.setUpdateContent(data.getUpdate_content()); update.setUpdateUrl(data.getDownload_url()); update.setVersionCode(Integer.parseInt(data.getV_code())); update.setVersionName(data.getV_name()); return update;//只能返回Update类型,否则报错,所以我们要把解析的javaBean数据赋值给update,然后将update返回 } }); }}
checkUrl:是放在tomcat中的
private static String checkUrl = "http://192.168.1.11:8080/cmcc/jsoninfo";

jsoninfo:

{    "code": 0,    "data": {        "download_url": "http://192.168.1.11:8080/cmcc/demo.apk ",        "force": false,        "update_content": "测试更新接口",        "v_code": 10,        "v_name": "v1.1",        "v_sha1": "7db76e18ac92bb29ff0ef012abfe178a78477534",        "v_size": 12365909    }}

Step2-2 解析更新接口返回的数据

上面我用的是Gson.jar,所以module的build.gradle还需要添加gson

dependencies {    ...    compile 'com.dou361.update:jjdxm-update:1.0.5'    compile 'com.dou361.download:jjdxm-download:1.0.3'    compile 'com.google.code.gson:gson:2.7'    ...}

javaBean类UpDateBean,直接创建这个类,右键Generate—>GsonFormat—>将json数据复制到编辑框中—>OK—>选中这些参数,即可生成set() + get()方法。

public class UpDateBean {
/** * code : 0 * data : {"download_url":"http://115.159.45.251/software/feibei_live1.0.0.16070810_zs.apk ","force":false,"update_content":"测试更新接口","v_code":"10","v_name":"v1.0.0.16070810","v_sha1":"7db76e18ac92bb29ff0ef012abfe178a78477534","v_size":12365909} */ private int code; /** * download_url : http://115.159.45.251/software/feibei_live1.0.0.16070810_zs.apk * force : false * update_content : 测试更新接口 * v_code : 10 * v_name : v1.0.0.16070810 * v_sha1 : 7db76e18ac92bb29ff0ef012abfe178a78477534 * v_size : 12365909 */ private DataBean data; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public DataBean getData() { return data; } public void setData(DataBean data) { this.data = data; } public static class DataBean {
private String download_url; private boolean force; private String update_content; private String v_code; private String v_name; private String v_sha1; private int v_size; public String getDownload_url() { return download_url; } public void setDownload_url(String download_url) { this.download_url = download_url; } public boolean isForce() { return force; } public void setForce(boolean force) { this.force = force; } public String getUpdate_content() { return update_content; } public void setUpdate_content(String update_content) { this.update_content = update_content; } public String getV_code() { return v_code; } public void setV_code(String v_code) { this.v_code = v_code; } public String getV_name() { return v_name; } public void setV_name(String v_name) { this.v_name = v_name; } public String getV_sha1() { return v_sha1; } public void setV_sha1(String v_sha1) { this.v_sha1 = v_sha1; } public int getV_size() { return v_size; } public void setV_size(int v_size) { this.v_size = v_size; } }}

Step3:在Application中oncreate()方法中调用

UpdateConfig.init(this);

Step4:在MainActivity的onCrete()中检查更新

UpdateHelper.getInstance()        .setUpdateType(UpdateType.autoupdate)//自动检查更新        .setForceListener(new ForceListener() {
//强制更新监听,true则退出app @Override public void onUserCancel(boolean force) { if (force) { finish(); } } }) .check(MainActivity.this);

源码下载

第二种: 判断VersionCode,xUtils实现下载

根据versionCode判断是否弹出更新dialog,需要更新的话,用户点击“确定”,利用xUtils实现下载,progressDialog显示下载进度,下载完成后,弹出是否安装的dialog,是:安装app,否:退出(MainActivity.this.finish())。

效果图

这里写图片描述

Step1: 请求更新接口,根据versionCode判断是否更新

// 获取本地版本号PackageManager packageManager = getPackageManager();try {    packageInfo = packageManager.getPackageInfo(getPackageName(), 0);} catch (NameNotFoundException e) {    e.printStackTrace();} finally {    nativeVversionCode = packageInfo.versionCode;}// 获取服务器版本号HttpUtils http = new HttpUtils();String url = "http://192.168.8.101:8080/QQ/jsoninfo";http.send(HttpMethod.POST, url, new RequestCallBack
() { @Override public void onFailure(HttpException exception, String msg) { ToastUtil.showShortToast(getBaseContext(), "获取服务器版本失败,请检查网络,\n App5秒后将退出"); handler.sendEmptyMessageDelayed(123, 5000); } @Override public void onSuccess(ResponseInfo
respinseInfo) { try { JSONObject obj = new JSONObject(respinseInfo.result); remoteVersionCode = obj.getInt("versioncode"); if (remoteVersionCode > nativeVversionCode) { ToastUtil.showLongToast(getBaseContext(), "请安装最新的版本"); downLoadApp(); } } catch (JSONException e) { e.printStackTrace(); } }});private Handler handler = new Handler(){ public void handleMessage(Message msg) { if (msg.what == 123) { MainActivity.this.finish(); } };};

Step2: 下载最新版本

protected void downLoadApp() {    target = Environment.getExternalStorageDirectory().getAbsolutePath() + "/QQ.apk";    String url = "http://192.168.8.101:8080/QQ/QQ.apk";    HttpUtils http = new HttpUtils();    http.download(url, target, new RequestCallBack
() { @Override public void onFailure(HttpException exception, String msg) { ToastUtil.showShortToast(getBaseContext(), "下载失败"); } @Override public void onSuccess(ResponseInfo
responseInfo) { dialog.dismiss(); ToastUtil.showShortToast(getBaseContext(), "下载成功"); // 安装apk installApk(); } @Override public void onLoading(long total, long current, boolean isUploading) { super.onLoading(total, current, isUploading); initProgressDialog(total,current); } });}

Step3: 安装apk

protected void installApk() {    new AlertDialog.Builder(MainActivity.this)        .setTitle("版本更新")        .setMessage("最新版本正在更新中...")        .setCancelable(false)        .setPositiveButton("确定", new DialogInterface.OnClickListener() {            @Override            public void onClick(DialogInterface dialog, int which) {                //安装app                Intent intent = new Intent();                intent.setAction("android.intent.action.VIEW");                intent.addCategory("android.intent.category.DEFAULT");                Uri data = Uri.parse("file://" + target);                intent.setDataAndType(data, "application/vnd.android.package-archive");                startActivity(intent);                MainActivity.this.finish();            }        })        .setNegativeButton("退出", new DialogInterface.OnClickListener() {            @Override            public void onClick(DialogInterface dialog, int which) {                MainActivity.this.finish();            }        }).show();}

Step4: 调用系统安装界面

protected void initProgressDialog(long total, long current) {        dialog.setTitle("更新app");//设置标题        dialog.setMessage("版本号:  "+ remoteVersionCode);//设置dialog内容        dialog.setIcon(R.drawable.ic_launcher);//设置图标,与为Title左侧        dialog.setCancelable(false);//点击空白处不可取消        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 水平线进度条,STYLE_SPINNER:圆形进度条        dialog.setMax((int) total);//最大值        dialog.setProgress((int) current);        dialog.show();    }

源码:

其他升级相关

你可能感兴趣的文章
为什么说程序员是“培训班出来的”就是鄙视呢?
查看>>
码农吐糟同事:写代码低调点不行么?空格回车键与你有仇吗?
查看>>
码农:一年前亲眼目睹同事被裁细节,如今遇到裁员自己便很淡然!
查看>>
阿里p8程序员四年提交6000次代码的确有功,但一次错误让人唏嘘!
查看>>
一道技术问题引起的遐想,最后得出结论技术的本质是多么的朴实!
查看>>
码农:公司裁了我现在打电话让回,饿死也不回!网友:公司饭香!
查看>>
码农:听新来领导说桌面乱的代码也肯定不整洁,我偷偷收拾了工位
查看>>
女码农:工作几年后发现自己并不喜欢写代码!网友:我早发现了!
查看>>
码农:组长随便改我代码并且改的也不好,更关键以后还得我维护!
查看>>
没写过js与c#,微软竟能录用我去做这个?当时面试考察的是算法!
查看>>
码农一个月连续出4次技术事故!是个人能力问题还是系统太破?
查看>>
实习生:上次code review得罪了老员工,这次我一句话都不说了!
查看>>
码农吐糟:1年没请过假,1月份想请几天年假回家还被拒了,心酸!
查看>>
码农:2个月跑了4座城市,投了几百封简历还没结果,钱都花完了!
查看>>
码农:休了个年假回来,发现自己的代码被重构了!是你会咋想?
查看>>
码农:一个java开发从来没用过apache或者guava库,这正常么?
查看>>
码农:实现95%以上DBA工作自动化,无人化值守,却革了自己的命!
查看>>
同样的逻辑,两种不同的代码写法,为啥大部分码农喜欢第一种?
查看>>
为什么多数程序员对黑色的界面情有独钟?网友调侃:黑科技般的黑
查看>>
码农吐糟facebook:本来一周4天班,现在却“压榨”到一周上5天!
查看>>