[置顶] Android应用开发之版本更新你莫愁
传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229
今天我们学习如何实现Android应用的自动更新版本功能,这是在各种语言编写的应用中都会经常遇到的情景。当我们的应用检测到网络上有新版本发布时,系统会提示是否下载新版本应用,当新版本应用下载完毕后,系统会自动安装下载的新版本应用(或跳转到相关安装页面询问)。我们将下载的应用存放在sdcard中,由于整个流程涉及对sdcard的读写操作,所以要赋给我们应用读写外存的权限。下面给出该场景的案例:
一、案例技术要点
1.程序清单文件中需要配置如下权限:
访问网络
- <uses-permission android:name="android.permission.INTERNET"/>
读取sdcard
- <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
写入sdcard
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2.创建一个HttpURLConnection连接,从网络下载新版本应用到本地
3.创建一个ProgressBar下载进度条,实时显示下载应用的进度
4.应用下载完毕后,构建Intent跳转至其安装页面,该Intent的配置如下:
Action:Intent.ACTION_VIEW
DataAndType:Uri.parse("file://" + appFile.toString()),"application/vnd.android.package-archive"
二、案例代码陈列
AndroidManifest.xml
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="cn.lynn.autoupdate"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="15" />
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity
- android:name=".AutoUpdateMainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
strings.xml
- <resources>
- <string name="app_name">Android实现应用自动更新</string>
- </resources>
main.xml
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- </LinearLayout>
下载进度条布局文件:progressBar.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <ProgressBar
- android:id="@+id/progressBar"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- </LinearLayout>
AutoUpdateMainActivity.java
- package cn.lynn.autoupdate;
- import android.app.Activity;
- import android.os.Bundle;
- public class AutoUpdateMainActivity extends Activity {
- private UpdateAppManager updateManager;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- updateManager = new UpdateAppManager(this);
- updateManager.checkUpdateInfo();
- }
- }
UpdateAppManager.java
- package cn.lynn.autoupdate;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import android.app.AlertDialog;
- import android.app.Dialog;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.content.DialogInterface.OnClickListener;
- import android.content.Intent;
- import android.net.Uri;
- import android.os.Environment;
- import android.os.Handler;
- import android.os.Message;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.widget.ProgressBar;
- public class UpdateAppManager {
- // 文件分隔符
- private static final String FILE_SEPARATOR = "/";
- // 外存sdcard存放路径
- private static final String FILE_PATH = Environment.getExternalStorageDirectory() + FILE_SEPARATOR +"autoupdate" + FILE_SEPARATOR;
- // 下载应用存放全路径
- private static final String FILE_NAME = FILE_PATH + "autoupdate.apk";
- // 更新应用版本标记
- private static final int UPDARE_TOKEN = 0x29;
- // 准备安装新版本应用标记
- private static final int INSTALL_TOKEN = 0x31;
- private Context context;
- private String message = "检测到本程序有新版本发布,建议您更新!";
- // 以华为天天聊hotalk.apk为例
- private String spec = "http://222.42.1.209:81/1Q2W3E4R5T6Y7U8I9O0P1Z2X3C4V5B/mt.hotalk.com:8080/release/hotalk1.9.17.0088.apk";
- // 下载应用的对话框
- private Dialog dialog;
- // 下载应用的进度条
- private ProgressBar progressBar;
- // 进度条的当前刻度值
- private int curProgress;
- // 用户是否取消下载
- private boolean isCancel;
- public UpdateAppManager(Context context) {
- this.context = context;
- }
- private final Handler handler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case UPDARE_TOKEN:
- progressBar.setProgress(curProgress);
- break;
- case INSTALL_TOKEN:
- installApp();
- break;
- }
- }
- };
- /**
- * 检测应用更新信息
- */
- public void checkUpdateInfo() {
- showNoticeDialog();
- }
- /**
- * 显示提示更新对话框
- */
- private void showNoticeDialog() {
- new AlertDialog.Builder(context)
- .setTitle("软件版本更新")
- .setMessage(message)
- .setPositiveButton("下载", new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- showDownloadDialog();
- }
- }).setNegativeButton("以后再说", new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- }).create().show();
- }
- /**
- * 显示下载进度对话框
- */
- private void showDownloadDialog() {
- View view = LayoutInflater.from(context).inflate(R.layout.progressbar, null);
- progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle("软件版本更新");
- builder.setView(view);
- builder.setNegativeButton("取消", new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- isCancel = true;
- }
- });
- dialog = builder.create();
- dialog.show();
- downloadApp();
- }
- /**
- * 下载新版本应用
- */
- private void downloadApp() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- URL url = null;
- InputStream in = null;
- FileOutputStream out = null;
- HttpURLConnection conn = null;
- try {
- url = new URL(spec);
- conn = (HttpURLConnection) url.openConnection();
- conn.connect();
- long fileLength = conn.getContentLength();
- in = conn.getInputStream();
- File filePath = new File(FILE_PATH);
- if(!filePath.exists()) {
- filePath.mkdir();
- }
- out = new FileOutputStream(new File(FILE_NAME));
- byte[] buffer = new byte[1024];
- int len = 0;
- long readedLength = 0l;
- while((len = in.read(buffer)) != -1) {
- // 用户点击“取消”按钮,下载中断
- if(isCancel) {
- break;
- }
- out.write(buffer, 0, len);
- readedLength += len;
- curProgress = (int) (((float) readedLength / fileLength) * 100);
- handler.sendEmptyMessage(UPDARE_TOKEN);
- if(readedLength >= fileLength) {
- dialog.dismiss();
- // 下载完毕,通知安装
- handler.sendEmptyMessage(INSTALL_TOKEN);
- break;
- }
- }
- out.flush();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if(out != null) {
- try {
- out.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if(in != null) {
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if(conn != null) {
- conn.disconnect();
- }
- }
- }
- }).start();
- }
- /**
- * 安装新版本应用
- */
- private void installApp() {
- File appFile = new File(FILE_NAME);
- if(!appFile.exists()) {
- return;
- }
- // 跳转到新版本应用安装页面
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.parse("file://" + appFile.toString()), "application/vnd.android.package-archive");
- context.startActivity(intent);
- }
- }
三、案例效果展示
新版本应用下载后,sdcard相关存放目录如下:
[置顶] Android应用开发之版本更新你莫愁的更多相关文章
- [置顶] Android 高级开发 源码 UI 缓存 网络
1.Android 源码剖析 性能优化 开源代码 2.Android UI效果源码 3.http://mzh3344258.blog.51cto.com/1823534/d-3 4.微信公众平台开发 ...
- [置顶] Android开发笔记(成长轨迹)
分类: 开发学习笔记2013-06-21 09:44 26043人阅读 评论(5) 收藏 Android开发笔记 1.控制台输出:called unimplemented OpenGL ES API ...
- [置顶]
android ListView包含Checkbox滑动时状态改变
题外话: 在xamarin android的开发中基本上所有人都会遇到这个小小的坎,的确有点麻烦,当时我也折腾了好一半天,如果你能看到这篇博客,说明你和我当初也是一样的焦灼,如果你想解决掉这个小小的坎 ...
- [置顶] Android开发实战记录(三)---HelloWorld
1.新建Android项目,选择Android Project,然后Next 2.填写项目名称HelloWorld然后next,这里注意下,Java开发的命名规范 3.选择Android SDK版本, ...
- [置顶]
Android开发百科全书
友情提示根据目录 快速查找问题 %1$s %1$d Android string 1.整型,比如"我今年23岁了",这个23是整型的.在string.xml中可以这样写,<s ...
- [置顶] android开发之来电自动拒接并自动回复短信_上课模式app
上课的时候老师说总是错过电话,对方打来没人接还一遍遍的打,觉得可以有个app在上课期间自动拒接电话,并自动回复短信过去. 当然了,需要权限的. 尝试做了个雏形出来. 界面如下: 主要代码如下: pac ...
- 【转】 [置顶] Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)
在Android的应用层中,涉及到很多应用框架,例如:Service框架,Activity管理机制,Broadcast机制,对话框框架,标题栏框架,状态栏框架,通知机制,ActionBar框架等等. ...
- [置顶]
Android 适配真要命?
原始尺寸场景 相信大家对上面也有所有耳闻另外就是如何计算屏幕的密度一般都是按照勾股定理例如中等屏幕密度 480^2+800^2开根号 然后除以当前屏幕尺寸3.5-4.2之间尺寸. 对于刚出来的那些An ...
- [置顶] Android 2016新技术
版权声明:分享技术,传播快乐.如果本博客对你有帮助,请在我的博客首页为我打赏吧! 2016你需要了解Android有以下新兴的技术与框架,有些也许还不成熟,但是你应该去了解下,也许就是未来的方向. K ...
随机推荐
- Java学习笔记(二一)——Java 泛型
[前面的话] 最近脸好干,掉皮,需要买点化妆品了. Java泛型好好学习一下. [定义] 一.泛型的定义主要有以下两种: 在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个 ...
- jdbc基础 (三) 大文本、二进制数据处理
LOB (Large Objects) 分为:CLOB和BLOB,即大文本和大二进制数据 CLOB:用于存储大文本 BLOB:用于存储二进制数据,例如图像.声音.二进制文件 在mysql中,只有B ...
- PDA设备小知识--(IP)工业防护等级含义
IP(INTERNATIONAL PROTECTION)防护等级是专门的工业防护等级,,它将电器依其防尘.防湿气之特性加以分级.IP防护等级是由两个数字所组成,第1个数字表示电器离尘.防止外物侵入的等 ...
- VMware打卡虚拟机提示“此虚拟机可能已被复制或移动”
使用VMware打开虚拟机时出现下图的页面,我来解释一下这三个选项按钮的区别与作用. "我已移动虚拟机" //表示打开后的虚拟的网卡的mac地址不变,如果复制本地的,同时开 ...
- [c#基础]DataTable的Select方法
引言 可以说DataTable存放数据的一个离线数据库,将数据一下加载到内存,而DataReader是在线查询,而且只进形式的查询,如果后退一步,就不可能了,DataTable操作非常方便,但也有缺点 ...
- 第十二章:window对象
第十一章介绍了window对象及其客户端javascript所扮演的核心角色:它是客户端javascript程序的全局对象.本章介绍window对象的属性和方法,这些属性定义了不同的API,但是只有一 ...
- “耐撕”团队记账本 剧透
β发布之后,我们团队开始fork"OneZero"团队的记账本程序.我们在原来的基础上添加了以下功能: 下面是我们团队记账本程序演示的视频:http://v.youku.com/v ...
- Eclipse字体大小设置
打开Eclipse,在主界面下Window->Preferences->General->Appearance->Colors and Fonts, 然后在右边展开框Basic ...
- WebService学习过程中的心得和问题
1.发布一个WebService 2.调用第三方提供的WebService服务
- VS中两个常用辅助工具
一. 首当推荐的是DPack 下载地址:http://www.usysware.com/dpack/ 快捷键:以下都是个人常用的热键.其他还有,我都用得比较少了,3个已经完全够了 Alt+U 查找 ...