网上看了好多自动升级安装的例子.可能是我没配置好.做起来各种的不爽 虽然代码都大同小异 还是自己做的比较满意

先说下主要的实现逻辑:在测试服务器上放一个xml,用来说明服务器的版本,和新apk的下载地址,运行本地apk的时间.去检测服务器xml里的服务器的版本信息,本地apk的版本信息可以在AndroidManifest.xml中的versionCode拿到.代码是context.getPackageManager().getPackageInfo("com.example.updateversion", 0).0;如果他的版本号比本地的版本号高的话就下载更新服务器上的apk,完了后安装新的apk,这样就实现了自动更新apk的目的,记得发布新的apk的时候一定要修改AndroidManifest.xml中的versionCode,只能搞不能低,然的话就这次可以更新.下次再比对的时候就没法更新了

本例共有3个类文件.一个activity 一个下载的主工具类 一个解析xml的工具类  还有2个布局文件.主布局文件和一个progressbar

1.主要的业务类:注释都在代理里了

package com.example.updateversion;

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 java.util.HashMap;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
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;
import android.widget.Toast;

/**
 * 检测安装更新文件的助手类
 * 
 * @author Administrator
 * 
 */
public class UpdateVersionService {
	private static final int DOWN = 1;// 用于区分正在下载
	private static final int DOWN_FINISH = 0;// 用于区分下载完成
	private HashMap<String, String> hashMap;// 存储跟心版本的xml信息
	private String fileSavePath;// 下载新apk的厨房地点
	private String updateVersionXMLPath;// 检测更新的xml文件
	private int progress;// 获取新apk的下载数据量,更新下载滚动条
	private boolean cancelUpdate = false;// 是否取消下载
	private Context context;
	private ProgressBar progressBar;
	private Dialog downLoadDialog;
	private Handler handler = new Handler() {// 跟心ui

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			switch ((Integer) msg.obj) {
			case DOWN:
				progressBar.setProgress(progress);
				break;
			case DOWN_FINISH:
				Toast.makeText(context, "文件下载完成,正在安装更新", Toast.LENGTH_SHORT).show();
				installAPK();
				break;

			default:
				break;
			}
		}

	};

	/**
	 * 构造方法
	 * 
	 * @param updateVersionXMLPath
	 *            比较版本的xml文件地址(服务器上的)
	 * @param context
	 *            上下文
	 */
	public UpdateVersionService(String updateVersionXMLPath, Context context) {
		super();
		this.updateVersionXMLPath = updateVersionXMLPath;
		this.context = context;
	}

	/**
	 * 检测是否可更新
	 * 
	 * @return
	 */
	public void checkUpdate() {
		if (isUpdate()) {
			showUpdateVersionDialog();// 显示提示对话框
		} else {
			Toast.makeText(context, "已经是新版本", Toast.LENGTH_SHORT).show();
		}
	}

	/**
	 * 更新提示框
	 */
	private void showUpdateVersionDialog() {
		// 构造对话框
		AlertDialog.Builder builder = new Builder(context);
		builder.setTitle("软件更新");
		builder.setMessage("检测到新版本,是否下载更新");
		// 更新
		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();
			}
		});
		Dialog noticeDialog = builder.create();
		noticeDialog.show();
	}

	/**
	 * 下载的提示框
	 */
	protected void showDownloadDialog() {
		{
			// 构造软件下载对话框
			AlertDialog.Builder builder = new Builder(context);
			builder.setTitle("正在更新");
			// 给下载对话框增加进度条
			final LayoutInflater inflater = LayoutInflater.from(context);
			View v = inflater.inflate(R.layout.downloaddialog, null);
			progressBar = (ProgressBar) v.findViewById(R.id.updateProgress);
			builder.setView(v);
			// 取消更新
			builder.setNegativeButton("取消", new OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
					// 设置取消状态
					cancelUpdate = true;
				}
			});
			downLoadDialog = builder.create();
			downLoadDialog.show();
			// 现在文件
			downloadApk();
		}

	}

	/**
	 * 下载apk,不能占用主线程.所以另开的线程
	 */
	private void downloadApk() {
		new downloadApkThread().start();

	}

	/**
	 * 判断是否可更新
	 * 
	 * @return
	 */
	private boolean isUpdate() {
		int versionCode = getVersionCode(context);
		try {
			// 把version.xml放到网络上,然后获取文件信息
			URL url = new URL(updateVersionXMLPath);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setReadTimeout(5 * 1000);
			conn.setRequestMethod("GET");// 必须要大写
			InputStream inputStream = conn.getInputStream();
			// 解析XML文件。
			ParseXmlService service = new ParseXmlService();
			hashMap = service.parseXml(inputStream);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (null != hashMap) {
			int serverCode = Integer.valueOf(hashMap.get("versionCode"));
			// 版本判断
			if (serverCode > versionCode) {
				Toast.makeText(context, "新版本是: " + serverCode, Toast.LENGTH_SHORT).show();
				return true;
			}
		}
		return false;

	}

	/**
	 * 获取当前版本和服务器版本.如果服务器版本高于本地安装的版本.就更新
	 * 
	 * @param context2
	 * @return
	 */
	private int getVersionCode(Context context2) {
		int versionCode = 0;
		try {
			// 获取软件版本号,对应AndroidManifest.xml下android:versionCode
			versionCode = context.getPackageManager().getPackageInfo("com.example.updateversion", 0).versionCode;
			Toast.makeText(context, "当前版本是: " + versionCode, Toast.LENGTH_SHORT).show();
		} catch (NameNotFoundException e) {
			e.printStackTrace();
		}
		return versionCode;

	}

	/**
	 * 安装apk文件
	 */
	private void installAPK() {
		File apkfile = new File(fileSavePath, hashMap.get("fileName") + ".apk");
		if (!apkfile.exists()) {
			return;
		}
		// 通过Intent安装APK文件
		Intent i = new Intent(Intent.ACTION_VIEW);
		System.out.println("filepath=" + apkfile.toString() + "  " + apkfile.getPath());
		i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");
		context.startActivity(i);
		android.os.Process.killProcess(android.os.Process.myPid());// 如果不加上这句的话在apk安装完成之后点击单开会崩溃

	}

	/**
	 * 卸载应用程序(没有用到)
	 */
	public void uninstallAPK() {
		Uri packageURI = Uri.parse("package:com.example.updateversion");
		Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
		context.startActivity(uninstallIntent);

	}

	/**
	 * 下载apk的方法
	 * 
	 * @author rongsheng
	 * 
	 */
	public class downloadApkThread extends Thread {
		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			try {
				// 判断SD卡是否存在,并且是否具有读写权限
				if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
					// 获得存储卡的路径
					String sdpath = Environment.getExternalStorageDirectory() + "/";
					fileSavePath = sdpath + "download";
					URL url = new URL(hashMap.get("loadUrl"));
					// 创建连接
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setReadTimeout(5 * 1000);// 设置超时时间
					conn.setRequestMethod("GET");
					conn.setRequestProperty("Charser", "GBK,utf-8;q=0.7,*;q=0.3");
					// 获取文件大小
					int length = conn.getContentLength();
					// 创建输入流
					InputStream is = conn.getInputStream();

					File file = new File(fileSavePath);
					// 判断文件目录是否存在
					if (!file.exists()) {
						file.mkdir();
					}
					File apkFile = new File(fileSavePath, hashMap.get("fileName") + ".apk");
					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);
						// 更新进度
						Message message = new Message();
						message.obj = DOWN;
						handler.sendMessage(message);
						if (numread <= 0) {
							// 下载完成
							// 取消下载对话框显示
							downLoadDialog.dismiss();
							Message message2 = new Message();
							message2.obj = DOWN_FINISH;
							handler.sendMessage(message2);
							break;
						}
						// 写入文件
						fos.write(buf, 0, numread);
					} while (!cancelUpdate);// 点击取消就停止下载.
					fos.close();
					is.close();
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

	}
}

2:解析工具类,能做到自动升级的地步,xml解析就不用再注释了吧:

package com.example.updateversion;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Xml;

public class ParseXmlService {

	public HashMap<String, String> parseXml(InputStream inputStream) {
		HashMap<String, String> hashMap = null;
		boolean flag = true;
		try {
			XmlPullParser pullParser = Xml.newPullParser();
			pullParser.setInput(inputStream, "UTF-8");
			int event = pullParser.getEventType();
			while (event != XmlPullParser.END_DOCUMENT) {
				switch (event) {
				case XmlPullParser.START_DOCUMENT:
					hashMap = new HashMap<String, String>();
					break;
				case XmlPullParser.START_TAG:
					flag = true;
					String name = pullParser.getName();
					if ("VERSIONCODE".equalsIgnoreCase(name) && flag == true) {
						hashMap.put("versionCode", pullParser.nextText().trim());
					} else if ("FILENAME".equalsIgnoreCase(name) && flag == true) {
						hashMap.put("fileName", pullParser.nextText().trim());
					} else if ("LOADURL".equalsIgnoreCase(name) && flag == true) {
						hashMap.put("loadUrl", pullParser.nextText().trim());
					}
					break;
				case XmlPullParser.END_TAG:
					flag = false;
					break;
				}
				event = pullParser.next();
			}
		} catch (XmlPullParserException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		// hashMap = new HashMap<String, String>();
		// hashMap.put("versionCode", "2");
		// hashMap.put("fileName", "updateversion");
		// hashMap.put("loadUrl",
		// "http://192.168.1.30:8080/server/updateversion/updateversion.apk");
		return hashMap;
	}

}

3:activity的代码主ui:

package com.example.updateversion;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;

public class MainActivity extends Activity {
	private UpdateVersionService updateVersionService;
	private static final String UPDATEVERSIONXMLPATH = "http://192.168.1.30:8080/server/updateversion/version.xml";

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// TODO Auto-generated method stub
		new Handler().postDelayed(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				updateVersionService = new UpdateVersionService(UPDATEVERSIONXMLPATH, MainActivity.this);// 创建更新业务对象
				updateVersionService.checkUpdate();// 调用检查更新的方法,如果可以更新.就更新.不能更新就提示已经是最新的版本了
			}

		}, 2000);// 2秒之后执行

	}

	/**
	 * 更新按钮的监听事件
	 * 
	 * @param view
	 */
	public void updateVersion(View view) {
		updateVersionService = new UpdateVersionService(UPDATEVERSIONXMLPATH, this);
		updateVersionService.checkUpdate();
	}

}

4:下面是主页面的xml和progress的xml

页面:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical|center_horizontal"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/version_msg"
        android:textSize="30sp"
        tools:context=".MainActivity" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:onClick="updateVersion"
        android:text="@string/update" />

</LinearLayout>

progress:

<?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="match_parent"
    android:orientation="vertical" >

    <ProgressBar
        android:id="@+id/updateProgress"
        style="@android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

以上就是整个程序的代码了 发布新版本只需要修改AndroidManifest.xml文件中的versionCode的值,一定要比升级之前的版本高,那个versionName在本例中没有什么实际意义,主要是versioncode,如果想在ui上看的清楚一点的话 可以经string.xml中的version_msg 标明版本号.这样在ui上就能看到当前的版本了

以后能让自己清楚点再次使用这个例子 把服务器的xml格式也贴上来,新的apk和xml放一个文件夹就行

<?xml version="1.0" encoding="UTF-8"?>
<VERSION>
	<VERSIONCODE>2</VERSIONCODE>
	<FILENAME>updateversion</FILENAME>
	<LOADURL>http://192.168.1.30:8080/server/updateversion/updateversion.apk
	</LOADURL>
</VERSION>

切记:如果测试的话,不管新的还是旧的apk 都得打包成apk文件.并且用同一个签名.如果是想在debug情况下使用 可以用(win7)C:\Users\rongsheng\.android目录下的debug.keystore这个签名(两个apk签名要一样),系统自带的签名的密码都是android