android 版本更新
这一android版本更新 代码,简单易用,只有几个小点需要注意,更换成自己的相关信息就可以了。
入口类
package com.version.roy;
import java.io.IOException;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;
import com.version.roy.manager.UpdateManager;
/**
* 更新视图界面类
*
* @author Royal
*
*/
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
[color=red]if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}[/color] // [color=green]这段代码必须添加[/color]
// 版本更新检查
UpdateManager um = new UpdateManager(MainActivity.this);
try {
um.checkUpdate(this.getString(R.string.version_url)); //[color=red]这里只需在string.xml文件 指定对应 相应的软件版本信息就可以[/color] } catch (IOException e) {
e.printStackTrace();
}
}
}
1 版本信息类
package com.version.roy.model;
/**
* 软件版本信息对象
*
* @author Royal
*
*/
public class VersionInfo {
// 版本描述字符串
private String version;
// 版本更新时间
private String updateTime;
// 新版本更新下载地址
private String downloadURL;
// 更新描述信息
private String displayMessage;
// 版本号
private int versionCode;
// apk名称
private String apkName;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getUpdateTime() {
return updateTime;
}
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
public String getDownloadURL() {
return downloadURL;
}
public void setDownloadURL(String downloadURL) {
this.downloadURL = downloadURL;
}
public String getDisplayMessage() {
return displayMessage;
}
public void setDisplayMessage(String displayMessage) {
this.displayMessage = displayMessage;
}
public int getVersionCode() {
return versionCode;
}
public void setVersionCode(int versionCode) {
this.versionCode = versionCode;
}
public String getApkName() {
return apkName;
}
public void setApkName(String apkName) {
this.apkName = apkName;
}
}
2 解析版本信息类
package com.version.roy.util;
import java.io.IOException;
import java.io.InputStream;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import com.version.roy.model.VersionInfo;
/**
* XML文档解析工具类
*
* @author Royal
*
*/
public class XMLParserUtil {
/**
* 获取版本更新信息
*
* @param is
* 读取连接服务version.xml文档的输入流
* @return
*/
public static VersionInfo getUpdateInfo(InputStream is) {
VersionInfo info = new VersionInfo();
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = factory.newPullParser();
parser.setInput(is, "UTF-8");
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
if ("version".equals(parser.getName())) {
info.setVersion(parser.nextText());
} else if ("updateTime".equals(parser.getName())) {
info.setUpdateTime(parser.nextText());
} else if ("updateTime".equals(parser.getName())) {
info.setUpdateTime(parser.nextText());
} else if ("downloadURL".equals(parser.getName())) {
info.setDownloadURL(parser.nextText());
} else if ("displayMessage".equals(parser.getName())) {
info.setDisplayMessage(parseTxtFormat(parser.nextText(), "##"));
} else if ("apkName".equals(parser.getName())) {
info.setApkName(parser.nextText());
} else if ("versionCode".equals(parser.getName())) {
info.setVersionCode(Integer.parseInt(parser.nextText()));
}
break;
case XmlPullParser.END_TAG:
break;
}
eventType = parser.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return info;
}
/**
* 根据指定字符格式化字符串(换行)
*
* @param data
* 需要格式化的字符串
* @param formatChar
* 指定格式化字符
* @return
*/
public static String parseTxtFormat(String data, String formatChar) {
StringBuffer backData = new StringBuffer();
String[] txts = data.split(formatChar);
for (int i = 0; i < txts.length; i++) {
backData.append(txts[i]);
backData.append("\n");
}
return backData.toString();
}
}
3 更新管理类
package com.version.roy.manager;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import com.version.roy.R;
import com.version.roy.model.VersionInfo;
import com.version.roy.util.XMLParserUtil;
/**
* APK更新管理类
*
* @author Royal
*
*/
public class UpdateManager {
// 上下文对象
private Context mContext;
//更新版本信息对象
private VersionInfo info = null;
// 下载进度条
private ProgressBar progressBar;
// 是否终止下载
private boolean isInterceptDownload = false;
//进度条显示数值
private int progress = 0;
private static final String savePath = "/sdcard/updateApk/";
private static final String saveFileName = savePath + "3GDHW_AppUpdate.apk";
//下载地址
private String downloadURL = null;
/**
* 参数为Context(上下文activity)的构造函数
*
* @param context
*/
public UpdateManager(Context context) {
this.mContext = context;
}
public void checkUpdate(String version_url) throws IOException {
// 从服务端获取版本信息
info = getVersionInfoFromServer(version_url);
if (info != null) {
downloadURL = info.getDownloadURL();
try {
// 获取当前软件包信息
PackageInfo pi = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), PackageManager.GET_CONFIGURATIONS);
// 当前软件版本号
int versionCode = pi.versionCode;
if (versionCode != info.getVersionCode()) {
// 如果当前版本号不等于服务端版本号,则弹出提示更新对话框
showUpdateDialog();
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}else{
showErrorDialog();
}
}
/**
* 从服务端获取版本信息
*
* @return
* @throws IOException
*/
private VersionInfo getVersionInfoFromServer(String version_url) throws IOException {
VersionInfo info = null;
URL url = null;
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
url = new URL(version_url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
if (url != null) {
try {
// 使用HttpURLConnection打开连接
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
inputStream = urlConnection.getInputStream();
if(inputStream == null){
// 服务器 和 本地 版本信息文件不一致
return null;
}
// 读取服务端version.xml的内容(流)
info = XMLParserUtil.getUpdateInfo(inputStream);
urlConnection.disconnect();
inputStream.close();
} catch (IOException e) {
urlConnection.disconnect();
if(inputStream != null)
inputStream.close();
return null;
}
}
return info;
}
public void showErrorDialog(){
Builder builder = new Builder(mContext);
builder.setTitle("提示");
builder.setMessage("网络或软件版本信息有错误,数据无法下载,请到网页下载最新版本软件");
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
}
/**
* 提示更新对话框
*
* @param info
* 版本信息对象
*/
private void showUpdateDialog() {
Builder builder = new Builder(mContext);
builder.setTitle("版本更新");
builder.setMessage(info.getDisplayMessage());
builder.setPositiveButton("下载", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
// 弹出下载框
showDownloadDialog();
}
});
builder.setNegativeButton("以后再说", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
/**
* 弹出下载框
*/
private void showDownloadDialog() {
Builder builder = new Builder(mContext);
builder.setTitle("版本更新中...");
final LayoutInflater inflater = LayoutInflater.from(mContext);
View v = inflater.inflate(R.layout.update_progress, null);
progressBar = (ProgressBar) v.findViewById(R.id.pb_update_progress);
builder.setView(v);
builder.setNegativeButton("取消", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
//终止下载
isInterceptDownload = true;
}
});
builder.create().show();
//下载apk
downloadApk();
}
/**
* 下载apk
*/
private void downloadApk(){
//开启另一线程下载
Thread downLoadThread = new Thread(downApkRunnable);
downLoadThread.start();
}
/**
* 从服务器下载新版apk的线程
*/
private Runnable downApkRunnable = new Runnable(){
@Override
public void run() {
String path = android.os.Environment.getExternalStorageState();
System.out.println(path);
if (!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
//如果没有SD卡
Builder builder = new Builder(mContext);
builder.setTitle("提示");
builder.setMessage("当前设备无SD卡,数据无法下载");
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
return;
}else if(downloadURL != null){
try {
//服务器上新版apk地址
URL url = new URL(downloadURL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.connect();
int length = conn.getContentLength();
InputStream is = conn.getInputStream();
File file = new File(savePath);
if (!file.exists()) {
file.mkdirs();
}
String apkFile = saveFileName;
File ApkFile = new File(apkFile);
FileOutputStream fos = new FileOutputStream(ApkFile);
int count = 0;
byte buf[] = new byte[1024];
do{
int numRead = is.read(buf);
count += numRead;
//更新进度条
progress = (int) (((float) count / length) * 100);
handler.sendEmptyMessage(1);
if(numRead <= 0){
//下载完成通知安装
handler.sendEmptyMessage(0);
isInterceptDownload = true;
break;
}
fos.write(buf,0,numRead);
//当点击取消时,则停止下载
}while(!isInterceptDownload);
fos.close();
is.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}else{
Builder builder = new Builder(mContext);
builder.setTitle("提示");
builder.setMessage("获取服务器版本信息错误,数据无法下载");
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
}
}
};
/**
* 声明一个handler来跟进进度条
*/
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
// 更新进度情况
progressBar.setProgress(progress);
break;
case 0:
progressBar.setVisibility(View.INVISIBLE);
// 安装apk文件
installApk();
break;
default:
break;
}
};
};
/**
* 安装apk
*/
private void installApk() {
File apkfile = new File(saveFileName);
if (!apkfile.exists()) {
return;
}
Intent i = new Intent(Intent.ACTION_VIEW);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.parse("file://" + apkfile.toString()),
"application/vnd.android.package-archive");
mContext.startActivity(i);
// callback.OnBackResult("finish");
}
}
软件版本信息 version.xml
<?xml version="1.0" encoding="UTF-8"?>
<update>
<version>2.0_20120530</version>
<versionCode>2</versionCode>
<updateTime>2015-05-30</updateTime>
<apkName>dhw_android_new.apk</apkName>
<downloadURL>http://192.168.0.75:8081/mobile-web/dhw_android_new.apk</downloadURL>
<displayMessage>新版本发布,赶紧下载吧 ## 1.新增A功能 ## 2.新增B功能## 3.新增C功能 ## 4.没有新增</displayMessage>
</update>
需要注意的地方很简单
1 注意权限 。 在模拟器可以下载,在手机上不行,就是因为权限。
2 整个流程是 。 打开软件,软件去服务器地址获取version.xml文件信息 ,与本地软件版本号比较,如果相同则不提示,不同则提示更新。用户允许更新,则从version.xml文件获取的新版本软件下载地址去服务器端下载。下载完成 提示用户安装。
完整代码下载
http://download.csdn.net/detail/annan211/8699949