Android课程-App更新策略

@(Android)

第一节 课程介绍

概述

App更新是应用当中很常见的一个功能,基本上联网的app都应该具备这样的功能,对于更新迭代比较快速的产品,应用更新升级能让用户以最快的速度体验到最新功能和特性,对提高拉新留存率有不错的效果。本次课程来教会大家如何去实现这样的一个功能,分析具体的应用场景和技术,来让开发者满足产品的需求。

课程目标

学会如何通过AsyncHttp这样的框架来完成API网络请求

学会如何创建并绑定一个service

学会如何通过HttpURLConnection来下载文件

学会如何通过Handler来更新进度 5. 学会如何操作Notification

完整实现一个app更新需求

课程大纲

第一节:课程介绍

第二节:检查更新实现

第三节:定义Service&绑定后台服务

第四节:实现进度更新

第五节:实现通知栏提醒&进度更新

第六节:测试&总结

最后

本次课程面向初学者,主要目的是想让他们了解App中更新功能模块是如何实现的,通过本次课程实现的Demo方便童鞋们后面去扩展,主要还是针对使用场景来进行调整,如果想观看视频课程,后续公众号会送上,课程再录制当中,谢谢。

第二节 检查更新实现

这节课来正式讲解App更新策略的第一部分,检查更新实现,本节课来教大家如何集成android-async-http这个比较优秀的网络库,由于Android6.0已经抛弃使用HttpClient这个类,所以集成这个网络库的时候一定要选择最新的版本,这里是1.4.9,如果大家以后想换成其他网络库,比如Volley,Okhttp再或者是retrofit这样比较流行的Http网络请求库,只要针对相应的方法替换成新的网络库的方法就行了。

我们来看如何实现检查更新,说白了就是通过调用服务端给我们提供的API接口,我们通过网络库发送HTTP GET的请求,返回服务端的接口数据,并对它进行解析,这里一般是JSON格式的数据。

定义接口地址常量

// 这里替换你的服务器域名

public static final String DOMAIN = "http://www.infzm.com/";

// url, 检查更新API

public static final String CHECK_UPDATE = DOMAIN

+ "mobilesource/goal/app.config.php";

定义请求方法

/**

* 检查更新

*

* @param params

* @param responseHandler

*/

public RequestHandle checkUpdate(RequestParams params,

AsyncHttpResponseHandler responseHandler) {

LogUtils.e("checkUpdate", URLHelper.CHECK_UPDATE + "?" + params);

return client.get(URLHelper.CHECK_UPDATE, params, responseHandler);

定义回调方法

package com.devilwwj.updateapkdemo.update;

import android.app.ProgressDialog;

import android.content.Context;

import android.util.Log;

import android.widget.Toast;

import com.devilwwj.updateapkdemo.GlobalSettings;

import com.devilwwj.updateapkdemo.R;

import com.devilwwj.updateapkdemo.utils.Utils;

import com.loopj.android.http.JsonHttpResponseHandler;

import org.apache.http.Header;

import org.json.JSONException;

import org.json.JSONObject;

import java.util.Map;

/**

* 检查更新的句柄

* @author wwj_748

*

*/

public class CheckUpdateAsyncHandler extends JsonHttpResponseHandler{

private Context mContext;

private ProgressDialog progressDialog;

OnCheckUpdateListener checkUpdateListener;

interface OnCheckUpdateListener {

void onSuccess(UpdateInfo updateInfo);

void onFailure();

}

public CheckUpdateAsyncHandler(Context context, OnCheckUpdateListener onCheckUpdateListener) {

this.mContext = context;

this.checkUpdateListener = onCheckUpdateListener;

progressDialog = new ProgressDialog(mContext);

progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);

progressDialog.setMessage(mContext.getString(R.string.tip_requesting));

progressDialog.setCancelable(true);

}

@Override

public void onStart() {

super.onStart();

progressDialog.show();

}

@Override

public void onFailure(int statusCode, Header[] headers,

Throwable throwable, JSONObject errorResponse) {

super.onFailure(statusCode, headers, throwable, errorResponse);

Map versionInfoMap = GlobalSettings

.getNewVersionInfo(mContext);

boolean canUpdate = (Boolean) versionInfoMap.get("updatable");

if (canUpdate) {

progressDialog.dismiss();

Toast.makeText(mContext, "连接失败,请稍后重试",

Toast.LENGTH_SHORT).show();

} else {

progressDialog.dismiss();

}

checkUpdateListener.onFailure();

}

@Override

public void onSuccess(int statusCode, Header[] headers, JSONObject response) {

super.onSuccess(statusCode, headers, response);

Log.d("updateInfo", response.toString());

try {

JSONObject firstObject = (JSONObject) response.get("android_ireader");

// 最新版本号

String versionName = firstObject.optString("app_version");

// 版本号

int versionCode = firstObject.optInt("version_code");

versionCode = 47;

// 更新内容

String features = firstObject.getString("features");

// sdk版本

String sdkVersion = firstObject.optString("sdk_version");

// 系统版本

String osVersion = firstObject.optString("os_version");

// 获取当前版本号

int currentVersionCode = Utils.getAppVersionCode(mContext);

// apk下载地址

String url = firstObject.optString("update_url");

boolean isCanUpdate;

// 获取上次强制更新的版本——last_force_update

int last_force_update_version = firstObject.optInt("last_force_update_version");

if (currentVersionCode < last_force_update_version) {

isCanUpdate = true;

} else {

if (versionCode <= currentVersionCode) {

isCanUpdate = false;

} else {

isCanUpdate = true;

}

}

// 保存更新信息到sharedPerences

GlobalSettings.saveNewVersionInfo(mContext, versionName, url, features, isCanUpdate);

UpdateInfo updateInfo = new UpdateInfo();

updateInfo.setVersionName(versionName);

updateInfo.setVersionCode(versionCode);

updateInfo.setFeatures(features);

updateInfo.setSdkVersion(sdkVersion);

updateInfo.setOsVersion(osVersion);

updateInfo.setUpdateUrl(url);

updateInfo.setLastForceUpdate(last_force_update_version);

checkUpdateListener.onSuccess(updateInfo);

} catch(JSONException e) {

e.printStackTrace();

}

}

@Override

public void onFinish() {

super.onFinish();

progressDialog.dismiss();

}

@Override

public void onCancel() {

super.onCancel();

progressDialog.cancel();

}

}

定义更新管理类

package com.devilwwj.update.http;

import android.content.Context;

/**

* com.devilwwj.update.http

* Created by devilwwj on 16/4/5.

*/

public class AppUpdateManager {

private Context mContext;

private static AppUpdateManager instance;

public static AppUpdateManager getInstance(Context context) {

if (instance == null) {

synchronized (AppUpdateManager.class) {

instance = new AppUpdateManager(context);

}

}

return instance;

}

public AppUpdateManager(Context context) {

this.mContext = context;

}

public void checkUpdate() {

HttpRequestHelper.getInstance().checkUpdate(null, new CheckUpdateAsyncHandler(mContext))

}

}

调用检查更新方法

public class MainActivity extends AppCompatActivity {

private Button btnCheckUpdate;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

btnCheckUpdate = (Button) findViewById(R.id.btn_checkupdate);

btnCheckUpdate.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// 这里去检查更新

AppUpdateManager.getInstance(MainActivity.this).checkUpdate();

}

});

}

}

最后

本节课的内容基本上就这么多啦,代码大家可以http://git.oschina.net/devilwwj/AndroidUpdateDemo去下载,去下载,每一节课的代码都会上传到这个地方,代码会随着开发会有点变化,大家一定要跟上节奏哦。

第三节 定义更新Service

上节课给大家讲了,如何实现检查更新,通过Android-async-http这个网络库进行Http请求服务器API,响应返回更新信息。这节课来将如何通过绑定一个Service来启动一个服务,并通过它来下载我们的Apk文件。

首先我们创建一个后台服务跟我们的Activity相关联,这里取名AppUpdateService,因为我们是需要跟Activity绑定在一起,所以需要通过bindService的方式来启动服务,启动服务成功之后,则开启一个线程来下载apk,在下载的过程中,我们可以通过handler来更新提示我们下载的进度,这是本节课要实现的主要功能。

第四节 实现进度更新

前面的课程已经实现了通过Http请求API检查更新,定义了后台下载服务实现了apk下载,如果没有看过前面的课程可以看以下博文:

配套视频地址:

本节课主要是接着上面的课程继续完善App更新功能,这次主要是在后台根据下载进度,通过handler来发送消息的方式来更新进度条,具体的效果如下图所示:

我们要实现的效果就跟上面一样,点击更新之后,就弹出更新对话框不停的更新进度,进度达到100的时候,提示下载成功并消除对话框。

代码片段:

第五节 实现通知栏进度更新

上节课给大家介绍了如何实现下载进度更新,本节课将会给大家介绍如何实现通知栏消息提醒和通知栏的下载进度更新,如果还没有学习前面的课程的同学可以先学习前面内容:

先来看一下我们本节课要实现的效果:

上一节我们实现了在前台时进度条更新,现在我们考虑一个场景:

用户按了Home键回到后台,这个时候用户是看不到更新进度的,因为当前Activity已经不可见了,但是更新下载还在后台服务进行着,那么我们就应该在通知栏显示我们的进度更新,让用户感知到我们的更新是正在进行的。

当用户想回到前台,则可以通过点击通知栏消息跳转回前台界面,继续完成更新进度。

上面是我们初步的需求,下面来看具体实现:

代码位置:AppUpdateService.java

获取系统通知服务

构建Notification

通过NotificationCompat.Builder创建一个builder对象来构建Notification,设置标题、icon、是否自动cancel、自定义通知栏视图、设置PendingIntent。

更新通知栏进度

在代码上可以看到这样的逻辑,如果当前activity在后台时,在消息通知栏显示下载进度,通过获取Notification的contentVew来设置相应的内容,并通过NotificationManager来显示通知。

基本在通知栏显示的逻辑就这样,我们下载成功之后还有显示结果消息通知:

代码位置:AppUpdateManager.java

这里通过不同的flag在通知栏显示不同的消息,具体实现这里就不再截图,大家可以去看看代码:

本节课的内容就这么多,如果有任何疑问可以直接留言,欢迎拍砖。

第六节 测试&总结

App更新策略课程一共有六节,本节是最后一节,将会给大家总结一下我们App更新的时候有那些常见场景,并依据这些场景简单编写一下测试用例,还将会和大家探讨一下app更新模块还可以继续扩展什么功能。如果没有看过前面的课程的同学可以先学习前面的课程:

测试用例

这里我只是简单写了一下应用更新是最常出现的场景的测试用例,测试人员在测试这样的功能模块的时候,可能会考虑到更多的测试场景,这就需要我们不停的去优化测试流程去尽量满足真实的用户场景,比如考虑更多操作失败时的场景,例如网络切换时是否提醒用户网络已经被切换了、网络连接失败时是否提示用户、下载失败之后的提示,避免重复提醒用户更新等等。

本次课程只提供一个初步的解决方案,让没有这方面经验的同学能明白app更新策略是如何实现的,并没有做到完全适用于用户的各种应用场景,这需要同学们自己在实际开发中根据需求去优化这个解决方案。

效果图

总结

梳理流程图

这个是最简单的更新流程图,更新的流程大致都是类似的,我们首先会去请求服务端获取更新信息,这个是检查更新的过程。

一般情况我们会拿到相应的json数据,举个例子:

我们通过这样的json数据,拿到具体的更新信息,这里我们关注一下version_code,我们通过比对本地的versionCode跟服务端返回的versionCode,如果前者大,则无更新内容,如果后者大,则提示用户更新下载;

检查到有更新之后,就给用户弹窗通知用户下载,点击『取消』就不更新,点击『确定』则启动后台服务异步下载apk,下载成功之后如果在前台,我们可以直接跳转到安装界面完成安装;如果在后台,下载成功之后会在通知栏显示下载结果,点击通知栏消息也可以跳转到安装界面。具体的操作流程可以根据你们的需求来调整,不一定要按照我这里的操作流程。

完成安装之后,我们整个的app更新策略就完成了。那么我们还可以做些什么功能?如果只是简单的实现更新,还不算特别复杂,就怕我们伟大的产品经理提出伟(keng)大(die)的想法,比如要求app具备以下功能:

强制更新(流氓行为,用户可能会骂街)

断点续传(操作流程又会复杂很多)

增量更新(百度一下是啥吧)

这绝对有可能有这样的需求,这里留给同学们自己私下去实现,本课程就不继续讲解这方面的内容。

好啦,关于App更新策略课程已经完结,大家可以看到只是简单的一个更新模块,就需要我们考虑很多问题,如果让你自己去实现你会怎么做,希望本套课程能给同学们带来一定的帮助,毕竟更新升级是每个应用最基本的模块之一,最后谢谢同学们的耐心观看。

android 强制更新流程图,AndroidUpdateDemo相关推荐

  1. android app 自动更新,app升级项目,新增强制更新(可静默),支持热更新(wgt),可支持高版本安卓系统...

    pure-updater 一个可以用的自动更新方案 经测试可支持 Android 9.0 已支持热更新 已支持静默的强制更新 如果您觉得还可以的话那就点个五星吧!谢谢! 已测试 android 8.0 ...

  2. Android 应用强制更新策略

    Android应用强制更新的用途十分广泛,特别上刚上线的应用肯定会存在或多或少的bug,特别是涉及移动支付这一块的内容,如果出错了会造成比较大的损失,所以强制更新显得尤为重要. 一般来说,强制更新的策 ...

  3. Android版本强制更新

    目前的项目之中基本上都会存在版本更新的功能,分为强制更新和推荐更新,其实功能点都是一样的,推荐更新只是增加一个按钮让更新的弹框隐藏掉而已,这里仅记录强制更新的功能首先需要跟接口约定,需要判断是否弹出更 ...

  4. maven 强制更新_Android App内部更新Library的方法

    超详细!安卓巴士开发者大会嘉宾及主题介绍 AutoUpdateProject 最新版本及说明请关注GitHub,欢迎Star. 有什么意见与建议欢迎交流! github地址: https://gith ...

  5. android应用更新升级

    正常app的升级流程: 1.网络请求,根据返回结果判断是否需要更新应用 2.如果需要更新,会弹框显示版本说明,以及是否需要强制更新(有些大版本升级可能对原本的支持不够,此时为了避免不可控因素需要强制升 ...

  6. Android热更新技术的研究与实现Sophix

    所以阿里爸爸一直在进步着呢,知道技术存在问题就要去解决问题,这不,从Dexposed-->AndFix-->HotFix-->Sophix,技术是越来越成熟了. Android热更新 ...

  7. Android安装更新 apk,适用于android6.0及以上安卓版本。

    Android应用中apk下载更新,适用于android 9及以下安卓版本. 直接上代码: 一.在主配置文件中写权限. <uses-permission android:name="a ...

  8. 强制更新客html页面,强制更新

    强制更新 1. 什么是强制更新 当某个qp包希望用户快速下载到时,可以使用强制更新. 强制更新是为了解决出了故障或者希望某个版本(业务做活动)的QP 包能快速被更新到而设计的功能,使用起来也相当简单, ...

  9. Android增量更新框架

    Android增量更新框架 框架介绍 功能简介 简易效果图 增量更新配置 快速使用 Api详解 项目地址 框架介绍 功能简介 Android App更新框架,包含增量更新.多线程下载等功能.一句代码链 ...

最新文章

  1. Uboot启动过程详解
  2. 那个双非本科,还想转算法岗的姑娘,最后怎么了?
  3. SAP S/4HANA Customer Vendor Integration-CVI锁机制的实现
  4. 友声电子秤设置软件_友声电子秤说明书/操作指南?(一)
  5. 启发式搜索 A*算法的OC 实现
  6. 苹果mac pdf编辑器:Acrobat Pro DC
  7. iOS 柱状图的定制
  8. bin文件无法生成,Error: Q0147E: Failed to create Directory ./Flora_GD32.bin\ER$$.ARM.__AT_0x000000C0: File
  9. imx6ul之LCD驱动移植
  10. 【原】小软件开发心得(二)——推广、测试
  11. VINS-Mono 代码解析六、边缘化(3)
  12. 微信小程序,Python爬虫抓包采集实战,采集某成考题库小程序
  13. 红米k30pro工程测试代码_红米手机如何进行硬件测试
  14. css朗逸保险丝盒机舱,【朗逸保险盒】朗逸保险盒位置图解、拆卸方法_车主指南...
  15. 玩转Linux的下Ip计算器(图文)
  16. 佐治亚理工计算机科学录取,佐治亚理工大学计算机科学硕士申请条件及案例分享...
  17. python怎么消除警告_Python-警告处理
  18. Python——几个常用的数学函数
  19. Reaveal + iPhone(越狱)分析第三方app的UI视图结构
  20. 成为管理者---对组织的贡献

热门文章

  1. 相比手机操作、语音助手,智能传感器有什么优点?
  2. python创建数据库并对表结构备份_Python 数据库表操作之多表结构的创建与分析...
  3. git常见问题解决方法总结
  4. linux mangos创建账号,魔兽mangos系统用户数据自动备份Linux脚本
  5. SitePoint播客#20:YouTube六分类浏览器IE 6
  6. NLP笔记:中文分词工具简介
  7. 量化交易初学者5本必备书籍
  8. 模仿input闪烁光标
  9. 内网与外网文件传输工具
  10. 分组背包(每组背包选一个物品)