Android--APK更新总结

以下内容部分来自网络资源,这里做了个小小的总结。

目前Android开发中一般采用的是CS模式,对于Apk的升级就需要有Server端支持。基本思路:我们将升级版本以及一个记录升级版本的配置文件(一般采用json array/Xml格式)放在服务器端,当客户端Client初始化时,如果检测到Server服务器端有更新的版本,也就是配置文件中的版本信息不同,那么就将在Server端的升级版本以Http方式连接,将其下载下来,然后调用android api接口进行升级。

这里我们以Xml为例:

客户端与服务端约定如下:

1,版本信息记录在服务器端的version.xml文件中;

2,客户端每次运行时,先从服务器获取version.xml文件,然后对比该文件中的版本信息version与当前客户端的version是否一致,如果不一致,弹出更新选择框,由用户决定是否更新,如果更新,则启动更新程序;

3,更新程序:客户端从制定的URL中获取APK下载到本地,更新进度,如果下载完毕,启动APK安装程序,同时,允许用户中途取消下载,取消安装。

基于上述约定即可编写程序。

下面介绍一下具体过程:

1,定义version.xml文件

	<?xml version="1.0" encoding="UTF-8"?>  
	<update>  
	     <version>2.0_20141230</version>  
	     <versionCode>2</versionCode>  
	     <updateTime>2014-12-30</updateTime>  
	     <apkName>Updatedemo.apk</apkName>  
	     <downloadURL>http://localhost:8080/UpdateDemo.apk</downloadURL>  
	     <updateinformation>Update to the new version</updateinformation>  
	 </update>

2,定义version实体类VersionInformation.java

package com.client.update;

public class VersionInformation {
	
	     //Discription of version
	     private String mVersion;  
	     //Update time
	     private String mUpdateTime;  
	     //Update url  
	     private String mDownloadURL;  
	     //Update information 
	     private String mUpdateInformation;  
	     //Version number
	     private int mVersionCode;  
	     //Name of android application 
	     private String mApkName;  
	     
	     public String getVersion() {  
	         return mVersion;  
	     }  
	   
	     public void setVersion(String version) {  
	         this.mVersion = version;  
	     }  
	   
	     public String getUpdateTime() {  
	         return mUpdateTime;  
	     }  
	   
	     public void setUpdateTime(String updateTime) {  
	         this.mUpdateTime = updateTime;  
	     }  
	   
	     public String getDownloadURL() {  
	         return mDownloadURL;  
	     }  
	   
	     public void setDownloadURL(String downloadURL) {  
	         this.mDownloadURL = downloadURL;  
	     }  
	   
	     public String getUpdateInfomation() {  
	         return mUpdateInformation;  
	     }  
	   
	     public void setUpdateInfomation(String updateInfo) {  
	         this.mUpdateInformation = updateInfo;  
	     }  
	   
	     public int getVersionCode() {  
	         return mVersionCode;  
	     }  
	   
	     public void setVersionCode(int versionCode) {  
	         this.mVersionCode = versionCode;  
	     }  
	   
	     public String getApkName() {  
	         return mApkName;  
	     }  
	   
	     public void setApkName(String apkName) {  
	         this.mApkName = apkName;  
	     }  

}

3,定义version.xml解析类XMLParserUtils.java

package com.client.update;

import java.io.IOException;
import java.io.InputStream;

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

public class XMLParserUtils {
 
	//get VersionInformation entry from version.xml
    public static VersionInformation getUpdateInformation(InputStream is) {  
   	 VersionInformation info = new VersionInformation();  
        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 ("updateinformation".equals(parser.getName())) {  
                        info.setUpdateInfomation(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;  
    }  

    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();  
    }  

}

4,定义APK更新类UpdateManager.java

package com.client.update;

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;
import android.app.Dialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
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.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.tutor.update.R;

public class UpdateManager {
	
	//Context
    private Context mContext;
	//Description of update
	private String mUpdateInfo = null;
	//description of application
	private static String TAG = "UpdateAPKDemo";
	//Update url of application
	private String mApkUrl = null;//"http://softfile.3g.qq.com:8080/msoft/179/24659/43549/qq_hd_mini_1.4.apk";
	//url address of version.xml
	private URL mDownloadUrl = null;
	//new version number 
	private int mNewVersion = 0;
	//description of update dialog
	private Dialog mNoticeDialog;
	//description of download dialog
	private Dialog mDownloadDialog;
	//saving path for updated apk
    private static final String savePath = "/sdcard/"+TAG+"/";
    //saving name for updated apk 
    private static final String saveFileName = savePath + "UpdateAPKDemo.apk";
    //display current process of loading
    private ProgressBar mProgressBar;
    //message for process updating
    private static final int DOWN_UPDATE = 1;
    //message for download completed
    private static final int DOWN_OVER = 2;
    //value of loading process
    private int mProgress;
    //thread for download
    private Thread downLoadThread;
    //switch for download
    private boolean mInteruptDownload = false;
    
    private Handler mHandler = new Handler(){
    	public void handleMessage(Message msg) {
    		switch (msg.what) {
			case DOWN_UPDATE:
				mProgressBar.setProgress(mProgress);
				break;
			case DOWN_OVER:				
				installApk();
				break;
			default:
				break;
			}
    	};
    };
    
	public UpdateManager(Context context) {
		this.mContext = context;
	}
   
	public void checkUpdateInfo(){
		if(updateInfo())
		    showNoticeDialog();
		else
			Toast.makeText(mContext, "No update information", Toast.LENGTH_SHORT).show();
	}
	public boolean updateInfo()
	{
		VersionInformation info = getVersionInfoFromServer();
		if(info!=null)
		{
			mApkUrl =  info.getDownloadURL();
			mUpdateInfo = info.getUpdateInfomation();
			mNewVersion = info.getVersionCode();
		}
		else
		{
            Log.e("Error","Version information is null.");
			return false;
		}
		try {
			int oldversion = (mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), PackageManager.GET_CONFIGURATIONS)).versionCode;
			if(oldversion < mNewVersion)
				return true;
			else
				return false;
		} catch (NameNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		} 
	}

	private VersionInformation getVersionInfoFromServer() {
		VersionInformation info = null;
		try {
			//set url address of version.xml
			mDownloadUrl = new URL("http://10.0.2.2:8080/updateApkServer/version.xml");//just for test
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		if (mDownloadUrl != null) {
			try {
				HttpURLConnection urlConn = (HttpURLConnection) mDownloadUrl
						.openConnection();
				info = XMLParserUtils.getUpdateInformation(urlConn
						.getInputStream());
				urlConn.disconnect();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return info;
	} 

	private void showNoticeDialog(){
		AlertDialog.Builder builder = new Builder(mContext);
		builder.setTitle("ChoseUpdate");
		builder.setMessage(mUpdateInfo);
		builder.setPositiveButton("Download", new OnClickListener() {			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
				showDownloadDialog();			
			}
		});
		builder.setNegativeButton("Later", new OnClickListener() {			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();				
			}
		});
		mNoticeDialog = builder.create();
		mNoticeDialog.show();
	}
	
	private void showDownloadDialog(){
		AlertDialog.Builder builder = new Builder(mContext);
		builder.setTitle("Update");	
		final LayoutInflater inflater = LayoutInflater.from(mContext);
		View v = inflater.inflate(R.layout.progress, null);
		mProgressBar = (ProgressBar)v.findViewById(R.id.progress);	
		builder.setView(v);
		builder.setNegativeButton("Cancel", new OnClickListener() {	
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
				mInteruptDownload = true;
			}
		});
		mDownloadDialog = builder.create();
		mDownloadDialog.show();		
		downloadApk();
	}
	
	private Runnable mdownApkRunnable = new Runnable() {
		@Override
		public void run() {
			if (!android.os.Environment.getExternalStorageState().equals(
					android.os.Environment.MEDIA_MOUNTED)) {
				Builder builder = new Builder(mContext);
				builder.setTitle("Warning");
				builder.setMessage("SD card isn't exist!");
				builder.setPositiveButton("OK", new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				});
				builder.show();
				return;
			} else {
				try {
					URL url = new URL(mApkUrl);
					HttpURLConnection conn = (HttpURLConnection) url
							.openConnection();
					conn.connect();
					int length = conn.getContentLength();
					InputStream is = conn.getInputStream();
					File file = new File(savePath);
					if (!file.exists()) {
						file.mkdir();
					}
					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;
						mProgress = (int) (((float) count / length) * 100);
						// update current process value
						mHandler.sendEmptyMessage(DOWN_UPDATE);
						if (numread <= 0) {
							mHandler.sendEmptyMessage(DOWN_OVER);
							break;
						}
						fos.write(buf, 0, numread);
					} while (!mInteruptDownload);// cancel download operation if you want
					fos.close();
					is.close();
				} catch (MalformedURLException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	};
	
    //download apk
	private void downloadApk(){
		downLoadThread = new Thread(mdownApkRunnable);
		downLoadThread.start();
	}
    //install apk
	private void installApk(){
		File apkfile = new File(saveFileName);
        if (!apkfile.exists()) {
            return;
        }    
        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive"); 
        mContext.startActivity(i);
	
	}
}

5,在每次启动APK时,在MainActivity中调用

package com.tutor.update;

import com.client.update.UpdateManager;

import android.app.Activity;
import android.os.Bundle;

public class MainAcitivity extends Activity {
    

	private UpdateManager mUpdateManager;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        //check update
        mUpdateManager = new UpdateManager(this);
        mUpdateManager.checkUpdateInfo();
        //do other things
    }     
}

以上5个步骤就是具体的实现过程了,这里的代码需要你设定正确的version.xml 地址和apk地址,否则无法正常运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Trent1985

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值