Android应用程序自动更新

每次启动微信,都会时不时得看到应用更新的信息。我们在开发完成一款应用时,需要后期维护,时不时更新程序。

这段时间做一个项目,最后收尾的一个功能就是应用更新,现在这个功能已实现,在此分享下开发经验。

首先讲下大体思路:

1.判断网络可用否;

2.如果网络已连接,则比较当前应用的版本号与服务器上最新的应用版本号;

3.如果服务器上的版本号大于当前应用的版本号,则通知用户是否要更新应用;

4.用户确定更新应用,则下载应用,安装应用。(必须要注意的是:更新版本与原版本的数字签名要一致)

第一步:定义网络连接这个类,用于判断网络,如果网络连接不可用则设置网络。

public class NetWorkSetting {
    
    private Context context ;
	public NetWorkSetting(  Context con ) {
		// TODO Auto-generated constructor stub
		context = con;
	
	}

   private boolean isOpenNetwork( ) {
		 
		 if( context  == null )
		 {
			 return false;
		 }
		 ConnectivityManager connManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
		 
		 if (connManager.getActiveNetworkInfo() != null ) 
		 {
			 
		     return connManager.getActiveNetworkInfo().isAvailable();
		 }
		 return false;
    }

   /*网络可用就调用下一步需要进行的方法, 网络不可用则需设置
	 */
	public boolean  initInternet(  )
	{ // 判断网络是否可用
		 if (isOpenNetwork( ) == true) {
		 // 网络可用,则开始加载。
		     return true;
		 }
		 else
		 {
		    AlertDialog.Builder builder = new AlertDialog.Builder(context);
		    builder.setTitle("没有可用的网络").setMessage("是否对网络进行设置?");
		    builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
		     @Override
			 public void onClick(DialogInterface dialog, int which) {
			 Intent intent = null;
			 try {
					 String sdkVersion = android.os.Build.VERSION.SDK;
					 if (Integer.valueOf(sdkVersion) > 10) 
					 {
			              intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
					 }
					 else
					 {
					     intent = new Intent();
						 ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.WirelessSettings");
						 intent.setComponent(comp);
						 intent.setAction("android.intent.action.VIEW");
					  }
					    context.startActivity(intent);
					    SplashActivity  activity = new SplashActivity( );
					    UpdateSetting setting  = new UpdateSetting(context, activity.getDataFilePath( ) );//检测是否更新数据
					    setting.checkUpdate( );
					    
					 } catch (Exception e) {
					    e.printStackTrace();
					 }
				  }
			 }).setNegativeButton("否", new DialogInterface.OnClickListener() {
				 @Override
				 public void onClick(DialogInterface dialog, int which) {
				 dialog.cancel();
				 Toast.makeText(context, "网络异常,加载失败!", Toast.LENGTH_SHORT).show( );
			   }
		      }).show();
		    }
	    return false;

	 }
	
}

第二步:定义解析版本信息的类,可以使用xml文件保存版本信息,也 可以使用json保存。

在此建议大家,使用json保存数据,我开始时用xml来保存数据的,在网络状态好时,下载数据情况正常;一旦网络不好,则程序直接卡死。通常情况下,是把更新应用这个功能放在启动界面之后进入的主界面中,如果网络连接不好,就会导致连主界面都进入不的。

不过还是先介绍下解析xml文件:

首先定义一个version.xml,其中保存新版本的一些信息,如版本名称,版本号,更新的功能,以及更新的apk的地址等。

<?xml version="1.0" encoding="utf-8"?>
<update>
   <version>2</version>
   <name>*****系统</name>
   <content>版本信息:\n ******系统2.0.0新版本特性:\n 可以设置字体属性\n兼容Android版本2.3以上\n安装包大小:7.85MB</content>
   <url>http://101.69.244.66/guzhang/jackDoctor.apk</url>
</update>
然后定义ParseXml这个类,来解析xml文件:

public class ParseXmlService {

	public  HashMap<String ,String > ParseXml (  InputStream inputstream  ) 
	{
		
		HashMap <String,String >hashmap = new HashMap<String ,String >( );
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//建立DocumentFactory ,以用于取得Documentbuilder
		DocumentBuilder builder = null;
		
		try {
			builder = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		Document doc = null;
		try {
			doc = builder.parse( inputstream );
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		Element root = doc.getDocumentElement( );
		
		NodeList nl = root.getChildNodes();//查找nl的结点
		
		//得到NodeList中第一个子节点中文本节点的内容
		for( int i=0 ;i < nl.getLength();i++ )
		{
			Node childnode = ( Node )nl.item(i);//取得每一个元素
			
			if( childnode.getNodeType()==Node.ELEMENT_NODE)
			{   
				Element elementnode = (Element)childnode;
				
				if("version".equals( elementnode.getNodeName() ))
				{
					hashmap.put("version", elementnode.getFirstChild().getNodeValue());
				}	
				else if("name".equals( elementnode.getNodeName() ))
				{
					hashmap.put("name", elementnode.getFirstChild().getNodeValue());
				}
				 else if("content".equals(elementnode.getNodeName() ) )
				 {
				 	hashmap.put("content", elementnode.getFirstChild().getNodeValue());
				 }
				else if("url".equals(elementnode.getNodeName()))
				{
					hashmap.put("url", elementnode.getFirstChild().getNodeValue());
				}		
			}		
			
		}
		
		return hashmap;
	
	}
	

}

下面再来介绍下json文件保存数据,以及如何解析json数据。

首先,定义version.json。

 [{"appname":"jackDoctor","verName":"1.0.1","verCode":"2","apkurl":"http://************/guzhang/jackDoctor.apk",
    	"content":"版本信息:\n *********系统2.0.0新版本特性:\n 可以设置字体属性\n兼容Android版本2.3以上\n安装包大小:7.85MB"}]

然后再定义一个类ParseJSONService来解析json文件:

public class ParseJSONService {

	public static String parsejson( )
	{
		
		 String url = "http://**********/guzhang/version.json";//此处为服务器上version.json的地址
		 InputStream inputstream = null;

		try{

			HttpClient httpclient = new DefaultHttpClient();//取得HttpClient的实例
			HttpParams  params = httpclient.getParams();
			HttpConnectionParams.setConnectionTimeout(params, 3000);
			HttpConnectionParams.setSoTimeout(params, 5000);

			HttpResponse response = httpclient.execute( new HttpGet( url ));//连接到服务器
			HttpEntity entity = response.getEntity();
			StringBuilder  total  = new StringBuilder();
			if( entity!=null )
			{
				inputstream = entity.getContent();//取得数据对象
				BufferedReader buffer = new BufferedReader(new  InputStreamReader( inputstream,"GB2312"),8192);
				String line = "";
				
				while( (line = buffer.readLine())!=null )
				{
					 total.append(line+"\n");
				}
				buffer.close();//关闭
				
				return total.toString();
			}
	
			
		}catch( Exception e )
		{
			e.printStackTrace();
		}

		return null;

	}

}

下面才是重点:

更新应用主程序

public class UpdateSetting   {
   
	private Context context;
	private ProgressBar progressbar;
	private static int value;
	
	private static final int DOWLANDER  =1;
	private static final int  DOWLANDER_OVER =2;
	
	private HashMap<String ,String >hashmap ;
	private String DirectoryName;
	private Dialog builder ;
	private Thread mythread;
	Boolean cancelbar = false ;
	
	private int  version_num = 1 ;
	private String version_url;
	private String version_content;
	
	public UpdateSetting( Context  context,String  directoryName ) {
		// TODO Auto-generated constructor stub
		this.context = context;
		DirectoryName = directoryName;//下载文件保存目录
		
	}
	
     /*检测是否要更新,如果需要更新,且计数为1时,才更新*/
	 public void checkUpdate(   )
	 {			       
			 SharedPreferences share = context.getSharedPreferences("VersionUpdate", Activity.MODE_PRIVATE);
			 int count  = share.getInt("loadapp_count", 1); 
			 	
			 if( isupdate()&&(count==1 ) )
			 {   
				 Toast.makeText(context,"有新版本可以更新", Toast.LENGTH_LONG).show();
				 UpdateAPK( );
			 } 
			 SharedPreferences.Editor edit = share.edit();//否则不检测更新几次的话,在主界面中,可能每次都得检测是否要更新
			 edit.putInt("loadapp_count", ++count);
			 edit.clear().commit();	 	
	 }
	 
	 /*得到当前包的版本号*/
	 public int  getVersionCode( Context context  )
		{
			  int version = 0;	
			  try {
				  version = context.getPackageManager( ).getPackageInfo("com.example.mytabhostdemo", 0).versionCode;
			  } catch (NameNotFoundException e) {
					// TODO Auto-generated catch block
				e.printStackTrace();
			 }
			 return version ;
		}
		
	    /*通过解析xml文件或json文件,比较版本号,判断是否要更新应用*/
		public boolean isupdate(  ) 
		{ 
		   int  current_version = getVersionCode( context );
		   URL url = null ;
		   try{
			   //外网"http://101.69.244.66/guzhang/version.xml"
			   //内网192.168.13.101 
		    url = new URL("http://192.68.13.101/guzhang/version2.xml"); //版本信息地址
		 
		   }catch( Exception e )
		   {  
			   e.printStackTrace( );
		   }
		   
		    HttpURLConnection connection = null;
            InputStream inputstream = null;
	    	try {	
			    connection = (HttpURLConnection)url.openConnection( );
			    inputstream = connection.getInputStream( );
			    
			    ParseXmlService parsexmlservice = new ParseXmlService( );
			    hashmap = parsexmlservice.ParseXml(inputstream );//得到hashmap,后面要用到里面的version信息和content信息
  
			    if( hashmap != null )
			    {   
				   int update_version = Integer.valueOf(hashmap.get("version"));
                   if(   update_version >current_version ) 
				   {
					   return true;
				   }			      
			    }	
			  
		    } catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		    }
	        return false;
		
		}
		 
		
        
   	 public void  UpdateAPK() 
	 {   
   		  
		 Dialog dialog = new AlertDialog.Builder( context )
		                     .setIcon(R.drawable.sc_icon_label_press)
		                     .setTitle("更新软件包")
		                     .setMessage( hashmap.get("content").toString().replace("\\n", "\n") )
		                     //.setMessage( version_content.toString().replace("\\n", "\n"))
		                     .setPositiveButton("确定",
		                    		 new DialogInterface.OnClickListener() {
										
										@Override
										public void onClick(DialogInterface dialog, int which) {
											// TODO Auto-generated method stub		
											DownloadAPK();
											dialog.dismiss();
											
										}
									}).setNegativeButton("以后再说",
									  new DialogInterface.OnClickListener() {
										
										@Override
										public void onClick(DialogInterface dialog, int which) {
											// TODO Auto-generated method stub
											dialog.dismiss();
										}
									}).create(); 
		  dialog.show();
		 
	 }
	 
   	 /*下载应用程序过程中,弹出窗口并显示下载进度条*/
	 public void DownloadAPK() 
	 {
		 
		 LayoutInflater inflater = LayoutInflater.from( context );
	     View  view = inflater.inflate(R.layout.updateapp , null );
	     progressbar = (ProgressBar )view.findViewById(R.id.progressBar1);
	  
		 builder  = new AlertDialog.Builder( context )
		                     .setIcon(R.drawable.sc_icon_label_press)
		                     .setTitle("正在下载安装包,安装后需要手动重启程序")
		                     .setMessage("请稍等...")
		                     .setNegativeButton("取消",
											  new DialogInterface.OnClickListener( ) {
										
												@Override
												public void onClick(DialogInterface dialog, int which) {
													// TODO Auto-generated method stub
													dialog.dismiss( );
													cancelbar = true;
												}
											}).setView(view)
											.create(); 
		builder.show( );
		downloaderApk( );
	 }
	 
	 /*下载Apk*/
	 public void downloaderApk( )
	 {
		 mythread = new Thread(  downloadrunnable );
		 mythread.start( );	 
	 }
	 
	   /*开启线程下载apk*/
		private Handler handler = new Handler ( ){
			
					public void handleMessage( Message msg ){
						switch( msg.what ){
						case  DOWLANDER:
							  progressbar.setProgress(value);//设置进度条的进度
							 break;
						case DOWLANDER_OVER:
							 builder.dismiss();
							 setupfile( );
							 break;
						}				
					}	
				};
	    
		 private  Runnable  downloadrunnable  = new Runnable( )
		 { 
			 @Override
			 public void  run( )
			 {
				 try{
					 URL  url = new URL( hashmap.get("url") );//取得网络文件资源
				     //URL  url = new URL(version_url );
					 HttpURLConnection connection = (HttpURLConnection)url.openConnection( );//打开
					 connection.connect();
					 InputStream inputstream = connection.getInputStream( );
					 
					 int length = connection.getContentLength( );
					 
					 File directory = new File ( DirectoryName );
					 if( !directory.exists( ) )
					 {
						 directory.mkdir( );
					 }
					 
					 String  filename = DirectoryName +"jackDoctor.apk";
					 
					 File apkfile = new File( filename ); 
					 FileOutputStream filestream = new FileOutputStream(apkfile);
					 
					 int len  = 0;
			         int count = 0;
					 byte buffer [] = new byte[1024];
					 
					 while( !cancelbar )
					 {
						 len = inputstream.read( buffer );//问题在这里
						 
						 count += len;
						 value = (int )(((float)count/length)*100);
						 
						 handler.sendEmptyMessage(DOWLANDER); 
						 
						 if( len<=0 )
						 {   
							 handler.sendEmptyMessage(DOWLANDER_OVER); //下载完毕
							 break;
						 }
						 filestream.write( buffer ,0,len );//保存字节数组
					 }
					 filestream.close();//关闭文件流
					 inputstream.close();//关闭数据流
		
				 }catch( Exception e )
				 {

					e.printStackTrace( );
				 }
		  
			 }
			
      };
	 
	
	 /*安装文件*/
	 public void  setupfile( )
	 {
		 
         String  filename = DirectoryName +"jackDoctor.apk";
         
		 File directory = new File ( DirectoryName );
		 if( !directory.exists( ) )
		 {
			 directory.mkdir();
		 }
 
		 File apkfile = new File( filename ); 
		 
		 if( !apkfile.exists( ) ) 
		 {
			 return ;
		 }
		 
		 Intent intent = new Intent( Intent.ACTION_VIEW);//Uri.parse("file://"+apkfile.toString()),解析包出现问题
		 intent.setDataAndType(Uri.fromFile(apkfile),"application/vnd.android.package-archive" );//file:///sdcard
		 context.startActivity(intent);
		 
	 }

}
	

如果是需要使用json保存版本信息,则需要做些简单的修改:

public boolean isupdate(  ) 
		{ 
		
		    int  current_version = getVersionCode( context );
	    	try {	

			  ParseJSONService service = new ParseJSONService() ;
			  String jsonstring =  ParseJSONService.parsejson( );
			  JSONArray jsonArr = new JSONArray( jsonstring );
			  
			  if(jsonArr.length()>0 )
			  {
				  JSONObject  jsonObj = jsonArr.getJSONObject(0);
				  version_num = jsonObj.getInt("verCode");
				  version_url = jsonObj.getString("apkurl");
				  version_content = jsonObj.getString("content");	
	 
			  }
			  
			  if(version_num > current_version )
			  {
				  return true;
			  }
	
		    } catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		    }
	        return false;
		
		}
		
	 
		 private  Runnable  downloadrunnable  = new Runnable( )
		 { 
			 @Override
			 public void  run( )
			 {
				 try{
					 //URL  url = new URL( hashmap.get("url") );//取得网络文件资源
				     URL  url = new URL(version_url );//url修改
					 HttpURLConnection connection = (HttpURLConnection)url.openConnection( );//打开
					 connection.connect();
					 InputStream inputstream = connection.getInputStream( );
					 
					 int length = connection.getContentLength( );
					 
					 File directory = new File ( DirectoryName );
					 if( !directory.exists( ) )
					 {
						 directory.mkdir( );
					 }
					 
					 String  filename = DirectoryName +"jackDoctor.apk";
					 
					 File apkfile = new File( filename ); 
					 FileOutputStream filestream = new FileOutputStream(apkfile);
					 
					 int len  = 0;
			         int count = 0;
					 byte buffer [] = new byte[1024];
					 
					 while( !cancelbar )
					 {
						 len = inputstream.read( buffer );
						 
						 count += len;
						 value = (int )(((float)count/length)*100);
						 
						 handler.sendEmptyMessage(DOWLANDER); 
						 
						 if( len<=0 )
						 {   
							 handler.sendEmptyMessage(DOWLANDER_OVER); //下载完毕
							 break;
						 }
						 filestream.write( buffer ,0,len );//保存字节数组
					 }
					 filestream.close();//关闭文件流
					 inputstream.close();//关闭数据流
		
				 }catch( Exception e )
				 {

					e.printStackTrace( );
				 }
		  
			 }
			
        };
        
   	 public void  UpdateAPK() 
	 {   
   		  
		 Dialog dialog = new AlertDialog.Builder( context )
		                     .setIcon(R.drawable.sc_icon_label_press)
		                     .setTitle("更新软件包")
		                     //.setMessage( hashmap.get("content").toString().replace("\\n", "\n") )
		                     .setMessage( version_content.toString().replace("\\n", "\n"))//content修改
		                     .setPositiveButton("确定",
		                    		 new DialogInterface.OnClickListener() {
										
										@Override
										public void onClick(DialogInterface dialog, int which) {
											// TODO Auto-generated method stub		
											DownloadAPK();
											dialog.dismiss();
											
										}
									}).setNegativeButton("以后再说",
									  new DialogInterface.OnClickListener() {
										
										@Override
										public void onClick(DialogInterface dialog, int which) {
											// TODO Auto-generated method stub
											dialog.dismiss();
										}
									}).create(); 
		  dialog.show();
		 
	 }


其中在checkUpdate()函数中,有段SharePreferences取数据的代码段。

在启动界面的程序中,保存一个字段loadapp_count来记录启动程序次数,这样可以保证每一次启动程序都检测更新。

在启动界面需要加这段:

 SharedPreferences share = getSharedPreferences("VersionUpdate",Activity.MODE_PRIVATE);
SharedPreferences.Editor edit = share.edit( );
edit.putInt("loadapp_count", 1);
edit.clear().commit();

这样我们可以在checkUpdate()函数中,才能得到load_count.。


在AndroidMainfest.xml需要配置网络权限:

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

  本想上传图片,但考虑到其他问题,在此就不上传了。

最后,我们可以在主程序中onCreate()方法中调用:

   

  @Override
	    public void onCreate(Bundle savedInstanceState) {
	    	
	        super.onCreate(savedInstanceState);
	        requestWindowFeature( Window.FEATURE_NO_TITLE);
	        setContentView(R.layout.searchinform);
	        
	        
	  	      NetWorkSetting  networksetting = new NetWorkSetting( this );
		      if( networksetting.initInternet( ) )
		      {
			       //Toast.makeText(this, "网络连接可用,查看是否有新版本", Toast.LENGTH_LONG).show( ); 
				   SplashActivity  activity = new SplashActivity( );
			       UpdateSetting setting  = new UpdateSetting( eControlSettingTabActivity.this, activity.getDataFilePath( ) );//检测是否更新数据
			       setting.checkUpdate( );
		          
		      }
			  
}
	        









  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值