zoukankan      html  css  js  c++  java
  • Android检测版本更新

    一、准备

          1.检测当前版本的信息AndroidManifest.xml-->manifest-->android:versionName。

          2.从服务器获取版本号(版本号存在于xml文件中)并与当前检测到的版本进行匹配,如果不匹配,提示用户进行升级,如果匹配则进入程序主界面。

          3.当提示用户进行版本升级时,如果用户点击了确定,系统将自动从服务器上下载并进行自动升级,如果点击取消将进入程序主界面。

    二、效果图

                           1234

    三、必要说明

          服务器端存储apk文件,同时有version.xml文件便于比对更新。

    <?xml version="1.0" encoding="utf-8"?>
    
    <info>
    
    	<version>2.0</version>
    
    	<url>http://192.168.1.187:8080/mobilesafe.apk</url>
    
    	<description>检测到最新版本,请及时更新!</description>
    
    	<url_server>http://192.168.1.99/version.xml</url_server>
    
    </info>

          通过一个实体类获取上述信息。   

    package com.android;
    
    
    
    public class UpdataInfo {
    
    	private String version;
    
    	private String url;
    
    	private String description;
    
    	private String url_server;
    
    	
    
    	public String getUrl_server() {
    
    		return url_server;
    
    	}
    
    	public void setUrl_server(String url_server) {
    
    		this.url_server = url_server;
    
    	}
    
    	public String getVersion() {
    
    		return version;
    
    	}
    
    	public void setVersion(String version) {
    
    		this.version = version;
    
    	}
    
    	public String getUrl() {
    
    		return url;
    
    	}
    
    	public void setUrl(String url) {
    
    		this.url = url;
    
    	}
    
    	public String getDescription() {
    
    		return description;
    
    	}
    
    	public void setDescription(String description) {
    
    		this.description = description;
    
    	}
    
    }

          apk和版本信息地址都放在服务器端的version.xml里比较方便,当然如果服务器端不变动,apk地址可以放在strings.xml里,不过版本号信息是新的,必须放在服务器端,xml地址放在strings.xml。

    <?xml version="1.0" encoding="utf-8"?>
    
    <resources>
    
    
    
        <string name="hello">Hello World, VersionActivity!</string>
    
        <string name="app_name">Version</string>
    
        <string name="url_server">http://192.168.1.99/version.xml</string>
    
    
    
    </resources>

          不知道读者发现没有,笔者犯了个错误,那就是url_server地址必须放在本地,否则怎么读取version.xml,所以url_server不必在实体类和version里添加,毕竟是现需要version地址也就是url_server,才能够读取version。

    三、代码实现

    <?xml version="1.0" encoding="utf-8"?>
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    
        android:layout_width="fill_parent"
    
        android:layout_height="fill_parent"
    
        android:orientation="vertical" >
    
    	<Button 
    
    	    android:id="@+id/btn_getVersion"
    
    	    android:text="检查更新"
    
    	    android:layout_width="wrap_content"
    
    	    android:layout_height="wrap_content"/>
    
    </LinearLayout>

    package com.android;
    
    
    
    import java.io.InputStream;
    
    
    
    import org.xmlpull.v1.XmlPullParser;
    
    
    
    import android.util.Xml;
    
    
    
    public class UpdataInfoParser {
    
    
    
    	public static UpdataInfo getUpdataInfo(InputStream is) throws Exception{
    
    		XmlPullParser  parser = Xml.newPullParser();  
    
    		parser.setInput(is, "utf-8");
    
    		int type = parser.getEventType();
    
    		UpdataInfo info = new UpdataInfo();
    
    		while(type != XmlPullParser.END_DOCUMENT ){
    
    			switch (type) {
    
    			case XmlPullParser.START_TAG:
    
    				if("version".equals(parser.getName())){
    
    					info.setVersion(parser.nextText());	
    
    				}else if ("url".equals(parser.getName())){
    
    					info.setUrl(parser.nextText());	
    
    				}else if ("description".equals(parser.getName())){
    
    					info.setDescription(parser.nextText());	
    
    				}
    
    				break;
    
    			}
    
    			type = parser.next();
    
    		}
    
    		return info;
    
    	}
    
    }
    

    package com.android;
    
    
    import java.io.File;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    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.Intent;
    import android.content.pm.PackageInfo;
    import android.content.pm.PackageManager;
    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.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    
    public class VersionActivity extends Activity {
    
    
    	private final String TAG = this.getClass().getName();
    
    
    	private final int UPDATA_NONEED = 0;
    	private final int UPDATA_CLIENT = 1;
    	private final int GET_UNDATAINFO_ERROR = 2;
    	private final int SDCARD_NOMOUNTED = 3;
    	private final int DOWN_ERROR = 4;
    	private Button getVersion;
    
    
    	private UpdataInfo info;
    	private String localVersion;
    
    
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
    		getVersion = (Button) findViewById(R.id.btn_getVersion);
    		getVersion.setOnClickListener(new OnClickListener() {
    
    
    			@Override
    			public void onClick(View v) {
    				try {
    					localVersion = getVersionName();
    
    
    					CheckVersionTask cv = new CheckVersionTask();
    					new Thread(cv).start();
    
    
    				} catch (Exception e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		});
    	}
    
    
    	private String getVersionName() throws Exception {
    		//getPackageName()是你当前类的包名,0代表是获取版本信息  
    		PackageManager packageManager = getPackageManager();
    		PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(),
    				0);
    		return packInfo.versionName;
    	}
    
    
    	public class CheckVersionTask implements Runnable {
    		InputStream is;
    		public void run() {
    			try {
    				String path = getResources().getString(R.string.url_server);
    				URL url = new URL(path);
    				HttpURLConnection conn = (HttpURLConnection) url
    						.openConnection();
    				conn.setConnectTimeout(5000);
    				conn.setRequestMethod("GET"); 
                    int responseCode = conn.getResponseCode(); 
                    if (responseCode == 200) { 
                        // 从服务器获得一个输入流 
                    	is = conn.getInputStream(); 
                    } 
    				info = UpdataInfoParser.getUpdataInfo(is);
    				if (info.getVersion().equals(localVersion)) {
    					Log.i(TAG, "版本号相同");
    					Message msg = new Message();
    					msg.what = UPDATA_NONEED;
    					handler.sendMessage(msg);
    					// LoginMain();
    				} else {
    					Log.i(TAG, "版本号不相同 ");
    					Message msg = new Message();
    					msg.what = UPDATA_CLIENT;
    					handler.sendMessage(msg);
    				}
    			} catch (Exception e) {
    				Message msg = new Message();
    				msg.what = GET_UNDATAINFO_ERROR;
    				handler.sendMessage(msg);
    				e.printStackTrace();
    			}
    		}
    	}
    
    
    	Handler handler = new Handler() {
    
    
    		@Override
    		public void handleMessage(Message msg) {
    			// TODO Auto-generated method stub
    			super.handleMessage(msg);
    			switch (msg.what) {
    			case UPDATA_NONEED:
    				Toast.makeText(getApplicationContext(), "不需要更新",
    						Toast.LENGTH_SHORT).show();
    			case UPDATA_CLIENT:
    				 //对话框通知用户升级程序   
    				showUpdataDialog();
    				break;
    			case GET_UNDATAINFO_ERROR:
    				//服务器超时   
    	            Toast.makeText(getApplicationContext(), "获取服务器更新信息失败", 1).show(); 
    				break;
    			case DOWN_ERROR:
    				//下载apk失败  
    	            Toast.makeText(getApplicationContext(), "下载新版本失败", 1).show(); 
    				break;
    			}
    		}
    	};
    
    
    	/* 
    	 *  
    	 * 弹出对话框通知用户更新程序  
    	 *  
    	 * 弹出对话框的步骤: 
    	 *  1.创建alertDialog的builder.   
    	 *  2.要给builder设置属性, 对话框的内容,样式,按钮 
    	 *  3.通过builder 创建一个对话框 
    	 *  4.对话框show()出来   
    	 */  
    	protected void showUpdataDialog() {
    		AlertDialog.Builder builer = new Builder(this);
    		builer.setTitle("版本升级");
    		builer.setMessage(info.getDescription());
    		 //当点确定按钮时从服务器上下载 新的apk 然后安装   װ
    		builer.setPositiveButton("确定", new DialogInterface.OnClickListener() {
    			public void onClick(DialogInterface dialog, int which) {
    				Log.i(TAG, "下载apk,更新");
    				downLoadApk();
    			}
    		});
    		builer.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    			public void onClick(DialogInterface dialog, int which) {
    				// TODO Auto-generated method stub
    				//do sth
    			}
    		});
    		AlertDialog dialog = builer.create();
    		dialog.show();
    	}
    
    
    	/* 
    	 * 从服务器中下载APK 
    	 */  
    	protected void downLoadApk() {  
    	    final ProgressDialog pd;    //进度条对话框  
    	    pd = new  ProgressDialog(this);  
    	    pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);  
    	    pd.setMessage("正在下载更新");  
    	    pd.show();  
    	    new Thread(){  
    	        @Override  
    	        public void run() {  
    	            try {  
    	                File file = DownLoadManager.getFileFromServer(info.getUrl(), pd);  
    	                sleep(3000);  
    	                installApk(file);  
    	                pd.dismiss(); //结束掉进度条对话框  
    	            } catch (Exception e) {  
    	                Message msg = new Message();  
    	                msg.what = DOWN_ERROR;  
    	                handler.sendMessage(msg);  
    	                e.printStackTrace();  
    	            }  
    	        }}.start();  
    	}  
    	  
    	//安装apk   
    	protected void installApk(File file) {  
    	    Intent intent = new Intent();  
    	    //执行动作  
    	    intent.setAction(Intent.ACTION_VIEW);  
    	    //执行的数据类型  
    	    intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");  
    	    startActivity(intent);  
    	}  
    }

    package com.android;
    
    
    
    import java.io.BufferedInputStream;
    
    import java.io.File;
    
    import java.io.FileOutputStream;
    
    import java.io.InputStream;
    
    import java.net.HttpURLConnection;
    
    import java.net.URL;
    
    
    
    import android.app.ProgressDialog;
    
    import android.os.Environment;
    
    
    
    public class DownLoadManager {
    
    	public static File getFileFromServer(String path, ProgressDialog pd) throws Exception{
    
    		//如果相等的话表示当前的sdcard挂载在手机上并且是可用的
    
    		if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
    
    			URL url = new URL(path);
    
    			HttpURLConnection conn =  (HttpURLConnection) url.openConnection();
    
    			conn.setConnectTimeout(5000);
    
    			//获取到文件的大小 
    
    			pd.setMax(conn.getContentLength());
    
    			InputStream is = conn.getInputStream();
    
    			File file = new File(Environment.getExternalStorageDirectory(), "updata.apk");
    
    			FileOutputStream fos = new FileOutputStream(file);
    
    			BufferedInputStream bis = new BufferedInputStream(is);
    
    			byte[] buffer = new byte[1024];
    
    			int len ;
    
    			int total=0;
    
    			while((len =bis.read(buffer))!=-1){
    
    				fos.write(buffer, 0, len);
    
    				total+= len;
    
    				//获取当前下载量
    
    				pd.setProgress(total);
    
    			}
    
    			fos.close();
    
    			bis.close();
    
    			is.close();
    
    			return file;
    
    		}
    
    		else{
    
    			return null;
    
    		}
    
    	}
    
    
    
    }
    

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

    四、参考文献

                    http://blog.csdn.net/furongkang/article/details/6886526

  • 相关阅读:
    VS Code C++ 代码格式化方法(clang-format)
    linux函数深入探索——open函数打开文件是否将文件内容加载到内存空间
    总结一下数据库的 一对多、多对一、一对一、多对多 关系
    netstat -st输出解析(二)
    Connection reset by peer的常见原因及解决办法
    Linux errno详解
    Linux之清理linux内存cache
    十大经典排序算法(动图演示)
    android studio导出apk
    多线程还是多进程的选择及区别
  • 原文地址:https://www.cnblogs.com/youlechang123/p/5716933.html
Copyright © 2011-2022 走看看