首页 > 代码库 > Android应用检查更新总结

Android应用检查更新总结

每一个应用在进入主界面之间应该有一个界面用来显示公司或者团队的信息,介绍软件,并检查更新,及时提醒用户更新最新版本,获得更多更好的用户体验。本文将对该实现进行总结,以后用到就不要到处找自己写的项目了。

习惯上我们把实现该功能的类定义为splashActivity。

进入该界面就应该初始化一些数据,比如复制文件到系统目录,复制打包的数据库到系统目录,检查软件版本是否进行更新等。

1、复制文件到系统目录已经写成工具类,所以只要获得文件的源地址和目标地址即可完成复制。如下在android平台下 获取SD卡的文件目录代码如下:


/**
	 * 获得文件路径和状态信息
	 * 
	 * @return
	 */
	private List<MyFileInfo> getFiles() {
		File path = null;
		List<MyFileInfo> infos = new ArrayList<MyFileInfo>();

		MyFileInfo info = null;
		// 判断SD卡是否存在可用
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			path = Environment.getExternalStorageDirectory();

			File[] files = path.listFiles();
			for (File file : files) {
				// 把路径如入集合中

				if (file.getPath() != null) {
					info = new MyFileInfo();
					info.setPath(file.getPath());
					infos.add(info);
					info = null;
				}

			}
		} else {

			Toast.makeText(FileSearchActivity.this, "SD卡不可用!", 300).show();
		}

		return infos;

	}
复制文件方法:

/**
	 * @warning The name of file must be end with .xls
	 * @param res The resource file
	 * @param des The destination
	 * @return 
	 * @throws FileNotFoundException 
	 */
	public static boolean toCopy(String res,String des){
		boolean flag=false;
		
		//输入源文件
		File file = new File(res) ;
		FileInputStream fr=null;
		//复制目标文件
		File desFile = new File(des);
		FileOutputStream bw=null;
		try {
			fr = new FileInputStream(file);
			bw = new FileOutputStream(desFile);
			
			//buffer
			byte[] b = new byte[512];
			while(fr.read(b)!=-1){
				bw.write(b);
			}
			bw.flush();
			flag=true;
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			if(fr != null)
				try {
					fr.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			if(bw != null){
				try {
					bw.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return flag;
	}

获取android应用系统目录的方法:

File file = new File(getFilesDir(), "xxx.xls");即在android里面data/data/包名/files目录下。
通过以上方法即可完成将SD卡的文件复制到应用系统目录中。
2、复制数据库到系统目录
<p>(1)获得系统文件目录:</p><p><span style="color:rgb(127, 0, 85);">final</span> File file = <span style="color:rgb(127, 0, 85);">new</span> File(getFilesDir(), <span style="color:rgb(42, 0, 255);">"xxx.db"</span>);</p><p>(2)获得位于资产目录的文件的输入流</p><p>InputStream is = getAssets().open(<span style="color:rgb(42, 0, 255);">"xxx.db"</span>);</p><p>getResources()</p><p>*<span style="font-family:宋体;">读取文件资源:</span><span style="font-family:Times New Roman;">1.</span><span style="font-family:宋体;">读取</span><span style="font-family:Times New Roman;">res/raw</span><span style="font-family:宋体;">下的文件资源,通过以下方式获取输入流来进行写操作</span>·        <span style="font-family:Times New Roman;">InputStream is =getResources().openRawResource(R.id.filename); </span>2.<span style="font-family:宋体;">读取</span><span style="font-family:Times New Roman;">assets</span><span style="font-family:宋体;">下的文件资源,通过以下方式获取输入流来进行写操作</span>·        <span style="font-family:Times New Roman;">AssetManager am = null; </span>·        <span style="font-family:Times New Roman;">am = getAssets(); </span>·        <span style="font-family:Times New Roman;">InputStream is = am.open("filename"); </span></p><p> </p><p> </p><p>2<span style="font-family:宋体;">、读取拷贝到系统的数据库,并获得数据库引用。然后就可以操作数据库了。</span></p><p>SQLiteDatabase db = SQLiteDatabase.openDatabase(<span style="color:rgb(0,0,192);">path</span>, <span style="color:rgb(127,0,85);">null</span>,</p><p>				SQLiteDatabase.<span style="color:rgb(0,0,192);">OPEN_READONLY</span>);</p><p> </p><p><span style="background:rgb(255,255,0);">注:拷贝到系统的数据库文件的路径为:</span><span style="color:rgb(127, 0, 85);">public</span> <span style="color:rgb(127, 0, 85);">static</span> <span style="color:rgb(127, 0, 85);">final</span> String <span style="color:rgb(0, 0, 192);">path</span> = <span style="color:rgb(42, 0, 255);">"/data/data/</span><span style="color:rgb(42, 0, 255);">应用包名</span><span style="color:rgb(42, 0, 255);">/files/</span><span style="color:rgb(42, 0, 255);">数据库文件</span><span style="color:rgb(42, 0, 255);">"</span>;</p><p>自己建立的数据库是databases<span style="font-family:宋体;">文件夹下。</span></p><p> </p>
工具类如下:
<pre name="code" class="java">public class CopyFileToSystem {

	public CopyFileToSystem() {
		// TODO Auto-generated constructor stub
	}
	/**
	 * 把文件拷贝到系统文件夹
	 * @param in
	 * @param destPath
	 */
	public static void copyFile(InputStream in,String destPath){
		//目标文件
		File file=new File(destPath);
		FileOutputStream fos=null;
		try {
			fos=new FileOutputStream(file);
			int len=0;
			byte[] buffer=new byte[1024];
			while((len=in.read(buffer))!=-1){
				fos.write(buffer,0,len);
				
			}
			fos.flush();
			fos.close();
			in.close();
			
		} catch (Exception e) {
			
		}
		 
		
		
		
	}

}


3、检查更新
(1)首先获得应用的版本号
<pre name="code" class="java">/**
	 * 获得应用的版本信息
	 * @return 应用的版本号
	 */
	private String getAppVersion(){
		PackageManager pm=getPackageManager();
		PackageInfo info=null;
		try {
			info=pm.getPackageInfo(getPackageName(),0);
			if(info!=null){
				 return info.versionName;
			}
		} catch (NameNotFoundException e) {
			
			e.printStackTrace();
			
		}
		return "";
	}

(2)同时连接网络解析服务器的配置文件获得应用最新的版本号,如下:
<span style="white-space:pre">	</span>1)服务器端的xml文件如下
<?xml version="1.0" encoding="utf-8"?><info><version>2.0</version><description>空降新版本,请下载,体验更多新特性!!!</description><apkurl>http://192.168.253.1:8080/TouristManager.apk</apkurl></info>
<span style="white-space:pre">	</span>2)连接服务器获得输入流解析xml文件
<span style="white-space:pre">	</span><pre name="code" class="java">public class UpdateInfoParser {
	
	/**
	 * 解析服务器返回的更新信息
	 * @param is 服务器返回的流
	 * @return 如果发生异常 返回null;
	 */
	public static UpdateInfo getUpdateInfo(InputStream is) {
		try {
			XmlPullParser parser = Xml.newPullParser();
			parser.setInput(is, "utf-8");
			int type = parser.getEventType();
			UpdateInfo info = null;
			while(type!=XmlPullParser.END_DOCUMENT){
				switch (type) {
				case XmlPullParser.START_TAG:
					if("info".equals(parser.getName())){
						info = new UpdateInfo();
					}else if("version".equals(parser.getName())){
						info.setVersion(parser.nextText());
					}else if("description".equals(parser.getName())){
						info.setDescription(parser.nextText());
					}else if("apkurl".equals(parser.getName())){
						info.setApkurl(parser.nextText());
					}
					break;
				}
				type = parser.next();
			}
			return info;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		
	}
	
}

整个splash源代码如下:
<pre name="code" class="html">package com.example.ehrmanager;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources.NotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.animation.AlphaAnimation;
import android.widget.TextView;
import android.widget.Toast;

import com.example.ehrmanager.domain.UpdateInfo;
import com.example.ehrmanager.utils.DownLoadUtil;
import com.example.ehrmanager.utils.UpdateInfoParser;

public class SplashActivity extends Activity {
	private TextView mTVversion;//显示应用的版本
	private String mVersion;//应用的版本
	public static final int PARSE_XML_ERROR = 10;
	public static final int PARSE_XML_SUCCESS = 11;
	public static final int SERVER_ERROR = 12;
	public static final int URL_ERROR = 13;
	public static final int NETWORK_ERROR = 14;
	private static final int DOWNLOAD_SUCCESS = 15;
	private static final int DOWNLOAD_ERROR = 16;
	protected static final String TAG = "SplashActivity";
	private static final int COPYDATA_ERROR = 17;
	private UpdateInfo updateInfo;

	private ProgressDialog pd;// 下载进度的对话框
	
	
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case PARSE_XML_ERROR:
				Toast.makeText(getApplicationContext(), "解析xml失败", 0).show();
				// 进入程序主界面
				loadMainUI();
				break;
			case SERVER_ERROR:
				Toast.makeText(getApplicationContext(), "服务器异常", 0).show();
				// 进入程序主界面
				loadMainUI();
				break;
			case URL_ERROR:
				Toast.makeText(getApplicationContext(), "服务器地址异常", 0).show();
				// 进入程序主界面
				loadMainUI();
				break;
			case NETWORK_ERROR:
				Toast.makeText(getApplicationContext(), "网络异常", 0).show();
				// 进入程序主界面
				loadMainUI();
				break;
			case PARSE_XML_SUCCESS:
				if (getAppVersion().equals(updateInfo.getVersion())) {
					// 进入程序主界面
					Log.i(TAG, "版本号相同,进入主界面");
					loadMainUI();
				} else {
					Log.i(TAG, "版本号不相同,弹出来升级提示对话框");
					showUpdateDialog();
				}
				break;
			case DOWNLOAD_ERROR:
				Toast.makeText(getApplicationContext(), "下载失败", 0).show();
				// 进入程序主界面
				loadMainUI();
				break;
			case DOWNLOAD_SUCCESS:
				File file = (File) msg.obj;
				Log.i(TAG, "安装apk" + file.getAbsolutePath());
				// 安装apk
				installApk(file);
				finish();
				break;
			case COPYDATA_ERROR:
				Toast.makeText(getApplicationContext(), "加载数据库失败", 0).show();
				break;
			}
		};
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		intiViews();
		
		
	}
	
	/**
	 * 初始化组件
	 */
	private void intiViews() {
		setContentView(R.layout.activity_splash);
		mTVversion=(TextView)this.findViewById(R.id.app_version);
		mVersion=getAppVersion();//获得应用的版本
		mTVversion.setText(mVersion);
		// 连接服务器 检查版本更新.
				new Thread(new CheckVersionTask()).start();

				AlphaAnimation aa = new AlphaAnimation(0.2f, 1.0f);
				aa.setDuration(2000);
				findViewById(R.id.rl_splash).startAnimation(aa);
		
	}
	/**
	 * 获得应用的版本信息
	 * @return 应用的版本号
	 */
	private String getAppVersion(){
		PackageManager pm=getPackageManager();
		PackageInfo info=null;
		try {
			info=pm.getPackageInfo(getPackageName(),0);
			if(info!=null){
				 return info.versionName;
			}
		} catch (NameNotFoundException e) {
			
			e.printStackTrace();
			
		}
		return "";
	}
	/**
	 * 进入主界面
	 */
	private void  loadMainUI(){
		Intent intent=new Intent(SplashActivity.this,HomeActivity.class);
		startActivity(intent);
		this.finish();
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.splash, menu);
		return true;
	}
	
	
	

	
	
	
	/**
	 * 自动升级的提示对话框
	 */
	protected void showUpdateDialog() {

		AlertDialog.Builder builder = new Builder(this);
		builder.setTitle("升级提醒");
		builder.setMessage(updateInfo.getDescription());
		builder.setPositiveButton("确定", new OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				String apkurl = updateInfo.getApkurl();
				pd = new ProgressDialog(SplashActivity.this);
				pd.setTitle("升级操作");
				pd.setMessage("正在下载...");
				pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
				pd.show();
				Log.i(TAG, "下载后安装:" + apkurl);
				final File file = new File(Environment
						.getExternalStorageDirectory(), DownLoadUtil
						.getFileName(apkurl));
				// 判断sd卡是否可用,只有可用状态.
				if (Environment.getExternalStorageState().equals(
						Environment.MEDIA_MOUNTED)) {
					new Thread() {
						public void run() {
							File savedFile = DownLoadUtil.download(
									updateInfo.getApkurl(),
									file.getAbsolutePath(), pd);
							Message msg = Message.obtain();
							if (savedFile != null) {
								// 下载成功
								msg.what = DOWNLOAD_SUCCESS;
								msg.obj = savedFile;
							} else {
								// 下载失败
								msg.what = DOWNLOAD_ERROR;

							}
							handler.sendMessage(msg);
							pd.dismiss();
						};
					}.start();
				} else {
					Toast.makeText(getApplicationContext(), "sd卡不可用", 0).show();
					loadMainUI();
				}

			}
		});
		builder.setNegativeButton("取消", new OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				loadMainUI();
			}
		});
		builder.create().show();

		// builder.show();
	}

	
	private class CheckVersionTask implements Runnable {
		@Override
		public void run() {
			SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE);
			boolean isupdate = sp.getBoolean("update", true);
			if (!isupdate) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				loadMainUI();
				return;
			}
			long startTime = System.currentTimeMillis();
			Message msg = Message.obtain();
			try {
				URL url = new URL(getResources().getString(R.string.serverurl));
				HttpURLConnection conn = (HttpURLConnection) url
						.openConnection();
				conn.setRequestMethod("GET");
				conn.setConnectTimeout(1500);
				int code = conn.getResponseCode();
				if (code == 200) {
					InputStream is = conn.getInputStream();
					updateInfo = UpdateInfoParser.getUpdateInfo(is);
					if (updateInfo == null) {
						// TODO:解析xml失败
						msg.what = PARSE_XML_ERROR;
					} else {
						// 解析成功
						msg.what = PARSE_XML_SUCCESS;
					}
				} else {
					// TODO:服务器内部错误.
					msg.what = SERVER_ERROR;
				}
			} catch (MalformedURLException e) {
				msg.what = URL_ERROR; // http://
				e.printStackTrace();
			} catch (NotFoundException e) {
				msg.what = URL_ERROR; //
				e.printStackTrace();
			} catch (IOException e) {
				msg.what = NETWORK_ERROR;
				e.printStackTrace();
			} finally {
				long endTime = System.currentTimeMillis();
				long dTime = endTime - startTime;
				if (dTime < 2000) {
					try {
						Thread.sleep(2000 - dTime);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				handler.sendMessage(msg);
			}

		}
	}
	
	
	
	
	
	/**
	 * 安装一个apk文件
	 * 
	 * @param file
	 */
	protected void installApk(File file) {
	
		Intent intent = new Intent();
		intent.setAction("android.intent.action.VIEW");
		intent.addCategory("android.intent.category.DEFAULT");
		intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
		startActivity(intent);
	}
	

}
工具类源代码:
下载新版APK
<pre name="code" class="java">package com.example.ehrmanager.utils;



import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.ProgressDialog;

public class DownLoadUtil {

	/**
	 * 下载文件操作
	 * 
	 * @param serverPath
	 *            服务器文件的路径
	 * @param savedPath
	 *            本地保存的路径
	 * @param pd 进度条对话框
	 * @return 下载成功 返回文件对象 下载失败 返回null
	 */
	public static File download(String serverPath, String savedPath, ProgressDialog pd) {
		try {
			URL url = new URL(serverPath);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(5000);
			conn.setRequestMethod("GET");
			int code = conn.getResponseCode();
			if (code == 200) {
				pd.setMax(conn.getContentLength());
				InputStream is = conn.getInputStream();
				File file = new File(savedPath);
				FileOutputStream fos = new FileOutputStream(file);
				byte[] buffer = new byte[1024];
				int len = 0;
				int total = 0;
				while ((len = is.read(buffer)) != -1) {
					fos.write(buffer, 0, len);
					total +=len;
					pd.setProgress(total);
					Thread.sleep(20);
				}
				fos.flush();
				fos.close();
				is.close();
				return file;
			} else {
				return null;
			}

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	/**
	 * 获取服务器文件的名称
	 * @param serverPath
	 * @return
	 */
	public static String getFileName(String serverPath){
		return serverPath.substring(serverPath.lastIndexOf("/")+1);
	}
}







Android应用检查更新总结