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, 现在的软件都很 ...
随机推荐
- 自学Zabbix3.5-监控项item
itemItems是从主机里面获取的所有数据.通常情况下item为监控项,一般网络设备.服务器加入了zabbix监控,就需要监控它的cpu负载,那么实现这个方法的东西就叫item. 1. item构成 ...
- Eclipse中Spring插件的安装
java中为了方便学习使用SSH框架,框架插件的安装是非常必要的. 本博文记录了自己安装Spring插件的过程: 本机环境:win8 64bit eclipse版本:4.5.2 MARS 插件版本:S ...
- 在nginx上部署vue项目(history模式);
在nginx上部署vue项目(history模式): vue-router 默认是hash模式,使用url的hash来模拟一个完整的url,当url改变的时候,页面不会重新加载.但是如果我们不想has ...
- 《软件开发者路线图:从学徒到高手》【PDF】下载
<软件开发者路线图:从学徒到高手>[PDF]下载链接: https://u253469.ctfile.com/fs/253469-231196346 图书简介 作为一名软件开发者,你在奋力 ...
- Swift3.0 创建工程常用的类、三方、以及扩展 1.5
搭建项目常用的方法属性,欢迎追加 三方: source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' use_framew ...
- Fiori缓存与它的清除
最近在修改已有的Fiori应用,遇到了缓存上的一点问题,导致对Fiori应用的代码修改不能在前端页面生效.现将自己查到的一篇好资料翻译过来,以供参考.以下为正文. 2017.12.19更新:最近又遇到 ...
- scala写算法-用小根堆解决topK
topK问题是指从大量数据中获取最大(或最小)的k个数,比如从全校学生中寻找成绩最高的500名学生等等. 本问题可采用小根堆解决.思路是先把源数据中的前k个数放入堆中,然后构建堆,使其保持堆序(可以简 ...
- 瞎j8封装第二版之用xml文件来代理dao接口
也是重新整理了之前的那篇 模仿Mybatis用map per.xml实现Dao层接口的功能 话不多说直接上代码 首先是结构 依赖pom.xml <?xml version="1.0&q ...
- windows 下共享内存使用方法示例
windows下共享内存使用方法较 linux 而言微微复杂 示例实现的功能 有一个视频文件,一块内存区域 : 程序 A,将该视频写入该内存区域 : 程序 B,从该内存区域读取该视频 : 代码模块实现 ...
- 调用CMD命令的一个.NET工具类(MyWindowsCmd)
功能大概描述一下如果直接StandardOutput.ReadToEnd()这种方法,有很多限制 这类方式必须把命令全部执行一次写入并标记为exit,而且返回内容的获取会一直等待,如果在主线程里使用会 ...