您的位置:首页 > 移动开发 > Android开发

[置顶] Android应用开发之版本更新你莫愁

2013-07-25 10:38 113 查看
传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229
今天我们学习如何实现Android应用的自动更新版本功能,这是在各种语言编写的应用中都会经常遇到的情景。当我们的应用检测到网络上有新版本发布时,系统会提示是否下载新版本应用,当新版本应用下载完毕后,系统会自动安装下载的新版本应用(或跳转到相关安装页面询问)。我们将下载的应用存放在sdcard中,由于整个流程涉及对sdcard的读写操作,所以要赋给我们应用读写外存的权限。下面给出该场景的案例:

一、案例技术要点

1.程序清单文件中需要配置如下权限:

访问网络

[html] view plaincopyprint?

<uses-permission android:name="android.permission.INTERNET"/>

读取sdcard

[html] view plaincopyprint?

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

写入sdcard

[html] view plaincopyprint?

<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

[html] view plaincopyprint?

<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

[html] view plaincopyprint?

<resources>

<string name="app_name">Android实现应用自动更新</string>

</resources>

main.xml

[html] view plaincopyprint?

<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

[html] view plaincopyprint?

<?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

[java] view plaincopyprint?

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

[java] view plaincopyprint?

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相关存放目录如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: