Android App版本自动更新
本文demo下载:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=121
1. 运行前准备
本文附带实例: 实例中会下载一个应用程序(本公司的另一个产品:优鲜派 无病毒,请安心测试), 如果用户需要体验自动下载其它的产品,请自行配置apk下载路径: 将下图中的url路径换成自己的apk路径即可, apk的路径可以到360或者应用宝的官方网站上获取

2. 本实例运行效果图:
2.1 启动应用程序

2.2 点击 更新 操作, 开始下载最新版本apk,进度条显示下载进度

2.3 apk下载完成之后,自动安装下载的apk包, 注意下图的箭头处的意思

3.代码讲解
3.1 程序启动后, 调用后台接口获取最新apk版本信息(包括版本号与版本需要升级功能信息), 将最新版本号与当前apk版本号进行比较,如果版本号不一致,则弹出提示框,提示用户新版本中包含哪些最新信息, 用户根据自动需要选择是否更新
获得当前apk版本号:
public static int getVersion(Context context) {
try {
PackageManager manager = context.getPackageManager();
PackageInfo info = manager.getPackageInfo(context.getPackageName(),
0);
String version = info.versionName;
int versioncode = info.versionCode;
return versioncode;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
由于无法模拟与后台的交互,这里将网络版本号写死,比当前apk版本号要大,模拟更新的场景
弹出对话框,提示新版本新功能
private void getVersion(final int vision) {
// {"data":{"content":"其他bug修复。","id":"2","api_key":"android",
// // "version":"2.1"},"msg":"获取成功","status":1}
String data = "";
//网络请求获取当前版本号和下载链接
//实际操作是从服务器获取
//demo写死了
String newversion = "2.1";//网络版本号
String content = "\n" +
"就不告诉你我们更新了什么-。-\n" +
"\n" +
"----------万能的分割线-----------\n" +
"\n" +
"(ㄒoㄒ) 被老板打了一顿,还是来告诉你吧:\n" +
"1.下架商品误买了?恩。。。我搞了点小动作就不会出现了\n" +
"2.侧边栏、弹框优化 —— 这个你自己去探索吧,总得留点悬念嘛-。-\n";//更新内容
double newversioncode = Double
.parseDouble(newversion);
int cc = (int) (newversioncode);
System.out.println(newversion + "v" + vision + ",,"
+ cc);
if (cc != vision) {
if (vision < cc) {
System.out.println(newversion + "v"
+ vision);
// 版本号不同
ShowDialog(vision, newversion, content, url);
}
}
}
3.2 在弹出的对话框,用户点击"更新"与"取消"操作
更新时构建进度条页面
private void ShowDialog(int vision, String newversion, String content, final String url) {
new android.app.AlertDialog.Builder(this)
.setTitle("版本更新")
.setMessage(content)
.setPositiveButton("更新", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
pBar = new CommonProgressDialog(MainActivity.this);
pBar.setCanceledOnTouchOutside(false);
pBar.setTitle("正在下载");
pBar.setCustomTitle(LayoutInflater.from(
MainActivity.this).inflate(
R.layout.title_dialog, null));
pBar.setMessage("正在下载");
pBar.setIndeterminate(true);
pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pBar.setCancelable(true);
// downFile(URLData.DOWNLOAD_URL);
final DownloadTask downloadTask = new DownloadTask(
MainActivity.this);
downloadTask.execute(url);
pBar.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
downloadTask.cancel(true);
}
});
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.show();
}
3.3 开启线程类下载应用程序,将下载进度显示到进度条上
线程启动前调用: onPreExecute
线程下载apk过程: onPostExecute
进度条更新: onProgressUpdate
下载apk完成回调: onPostExecute
class DownloadTask extends AsyncTask<String, Integer, String> {
private Context context;
private PowerManager.WakeLock mWakeLock;
public DownloadTask(Context context) {
this.context = context;
}
@Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
File file = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP "
+ connection.getResponseCode() + " "
+ connection.getResponseMessage();
}
int fileLength = connection.getContentLength();
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
file = Environment.getExternalStorageDirectory();
if (!file.exists()) {
// 判断父文件夹是否存在
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
}
file = new File(file, DOWNLOAD_NAME);
} else {
Toast.makeText(MainActivity.this, "sd卡未挂载", Toast.LENGTH_LONG).show();
}
input = connection.getInputStream();
output = new FileOutputStream(file);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
input.close();
return null;
}
total += count;
// publishing the progress....
if (fileLength > 0) // only if total length is known
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
} catch (Exception e) {
System.out.println(e.toString());
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
ignored.toString();
}
if (connection != null)
connection.disconnect();
}
return null;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// take CPU lock to prevent CPU from going off if the user
// presses the power button during download
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
getClass().getName());
mWakeLock.acquire();
pBar.show();
}
@Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
// if we get here, length is known, now set indeterminate to false
pBar.setIndeterminate(false);
pBar.setMax(100);
pBar.setProgress(progress[0]);
}
@Override
protected void onPostExecute(String result) {
mWakeLock.release();
pBar.dismiss();
if (result != null) {
// 申请多个权限。
AndPermission.with(MainActivity.this)
.requestCode(REQUEST_CODE_PERMISSION_SD)
.permission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
// rationale作用是:用户拒绝一次权限,再次申请时先征求用户同意,再打开授权对话框,避免用户勾选不再提示。
.rationale(rationaleListener
).send();
Toast.makeText(context, "您未打开SD卡权限" + result, Toast.LENGTH_LONG).show();
} else {
update(context);
}
}
}
4. 安装下载完的apk包
private void update(Context context) {
//安装应用
Log.i("lxl update->","update");
File apkFile = new File(Environment.getExternalStorageDirectory(), DOWNLOAD_NAME);
Intent intent =new Intent(Intent.ACTION_VIEW);
if (apkFile == null || context == null) {
Log.i("lxl update->","null.");
throw new NullPointerException();
}
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.N) {
Uri contentUri = FileProvider.getUriForFile(context.getApplicationContext(),
BuildConfig.APPLICATION_ID + ".fileProvider",apkFile);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(contentUri,"application/vnd.android.package-archive");
Log.i("lxl update->",">>>==Build.VERSION_CODES.N");
}else{
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
Log.i("lxl update->","<<<<< Build.VERSION_CODES.N");
}
startActivity(intent);
}
本文demo下载:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=121
Android App版本自动更新的更多相关文章
- Android(2)—Mono For Android App版本自动更新
0.前言 公司Android查询的项目已经开始,整体采用Java后台+App前台来实现,由于项目小,App这块就我一个人开发,首先需要研究的是:Android版本的更新升级问题:本人经过近一周的学习整 ...
- Android(3)—Mono For Android App版本自动更新(2)
0.前言 这篇博文是上一篇的延续,主要是修改上一个版中的BUG和优化一些待完善的项,也算是结贴,当然还有需要完善的,等日后项目中用到的时候再单独写出来吧,本篇主要写升级改进的部分: 改进1.修复[BU ...
- Android实现App版本自动更新
现在很多的App中都会有一个检查版本的功能.例如斗鱼TV App的设置界面下: 当我们点击检查更新的时候,就会向服务器发起版本检测的请求.一般的处理方式是:服务器返回的App版本与当前手机安装的版本号 ...
- 如何实现已发布app的自动更新
要实现app的自动更新,做两件事情就可以搞定 1.获取当前手机中的app版本号 我们可以通过查询mainbundle中的获取CFBundleVersion NSDictionary *infoDict ...
- C#.Net版本自动更新程序及3种策略实现
C#.Net版本自动更新程序及3种策略实现 C/S程序是基于客户端和服务器的,在客户机编译新版本后将文件发布在更新服务器上,然后建立一个XML文件,该文件列举最新程序文件的版本号及最后修改日期.如程序 ...
- 获取 Android APP 版本信息工具类(转载)
获取 Android APP 版本信息工具类 获取手机APP版本信息工具类 1.获取版本名称 2.获取版本号 3.获取App的名称 package com.mingyue.nanshuibeidiao ...
- Android 版本自动更新
截图如下: 代码实现如下: package com.update.apk; import java.io.BufferedReader; import java.io.File; import jav ...
- 【Android 应用开发】Android应用的自动更新模块
. 作者 :万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/18964835 . 软件的自动更新一般都与Splash界 ...
- 安卓程序代写 网上程序代写[原]Android应用的自动更新模块
软件的自动更新一般都与Splash界面绑定在一起, 由于需要维护的软件界面很复杂, 一个Activity中嵌入ViewPager, 并且逻辑比较复杂, 索性重新写一个Activity, 现在的软件都很 ...
随机推荐
- 利用反射操作bean的属性和方法
今天在开发中碰到这样一个场景:当请求添加项目下的目录时,传过来的是一个IndexModel,这个Model里有关于这个目录字段的详细信息,包括基础报表,实时,漏斗等信息(这些字段类型都是boolean ...
- 源生js惯性滚动与回弹效果
在写移动端的APP或者页面时,经常会遇到惯性滚动与回弹效果.用插件iscroll可以轻松解决这个问题,大多数的移动框架也能轻松解决这个问题,它们内部都封装了这个效果. 一直好奇这个效果原生JS是怎么实 ...
- 字符设备 Vs. 块设备 Character Device Vs. Block Device
字符设备是指驱动发送/接受单个字符(例如字节)的设备. 块设备是指驱动发送/接受整块数据(例如512个字节为一个块)的设备. 常见的字符设备:串口,并口,声卡. 常见的块设备:硬盘(最小读取单位为扇区 ...
- Aop介绍及几种实现方式
Aop介绍 我们先看一下wiki百科的介绍 Traditional software development focuses on decomposing systems into ...
- 【java】缓冲字符字节输入输出流:java.io.BufferedReader、java.io.BufferedWriter、java.io.BufferedInputStream、java.io.BufferedOutputStream
BufferedReader最重要,因为有个方法public String readLine() package System输入输出; import java.io.BufferedReader; ...
- (转)iOS-Runtime知识点整理
runtime简介 因为Objc是一门动态语言,所以它总是想办法把一些决定工作从编译连接推迟到运行时.也就是说只有编译器是不够的,还需要一个运行时系统 (runtime system) 来执行编译后的 ...
- 链表创建和链表遍历算法的演示_C语言
今天搞了一个多小时,头是疼的,应该是没休息好吧,学习了数据结构这一节,感觉收益良多,下面贴上代码和心得: /*24_链表创建和链表遍历算法的演示*/ # include <stdio.h> ...
- UVA 11825 Hackers' Crackdown
题目大意就是有一个图,破坏一个点同时可以破坏掉相邻点.每个点可以破坏一次,问可以完整破坏几次,点数=16. 看到16就想到状压什么的. 尝试设状态:用f[i]表示选的情况是i(一个二进制串),至少可以 ...
- 简单记录一下原生ajax
面试老忘记,代码如下 function ajax() { var xmlHttpRequest = null; //定义XMLHttp对象的容器 if(window.XMLHttpRequest) { ...
- 用node搭建简单的静态资源管理器
我们都知道,老牌的3p服务器都是自带静态资源管理器的.但是node不同,它没有web容器,它的路由地址和真实地址可以没有联系,所有node的优点,是可以把路由做得相当漂亮. 但静态资源管理器也是必不可 ...