`
ck19860613
  • 浏览: 87404 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

带更新内容提示的自动更新的一种实现

阅读更多

思路如下:

1.实现一个只有程序安装后第一次打开时才会执行的方法,这样方便在配置文件PreferenceManager.getDefaultSharedPreferences(Context)中保存程序的一些信息,比如apk安装时间,这个值之后会和服务器上的apk修改时间做比较来判断是否要更新,如我这个例子里的showOnFirstLaunch(),程序入口活动JumpActivity onCreate时获取程序包信息中的versionCode版本代码号,如果与配置中保存的版本号不一致,表示安装新版后第一次打开程序,则执行之后的代代码片段,如保存当前版本号,设置新版已安装的值为true,多设了这个值的目的是,我们自动更新时虽然下载了新版本,但是没有对其安装,则打开旧版本时提示下载的更新没有被安装,给用户一个安装的选择。

 

JumpActivity.class

private void showOnFirstLaunch() {
	  setContentView(R.layout.splash);
    try {
      PackageInfo info = getPackageManager().getPackageInfo(PACKAGE_NAME, 0);
      int currentVersion = info.versionCode;
      prefs = PreferenceManager.getDefaultSharedPreferences(this);
      int lastVersion = prefs.getInt(PreferencesActivity.KEY_HELP_VERSION_SHOWN, 0);
      if (currentVersion != lastVersion) {//安装好后第一次启动
    	  //设置版本号
        prefs.edit().putInt(PreferencesActivity.KEY_HELP_VERSION_SHOWN, currentVersion).commit(); 
        prefs.edit().putBoolean(PreferencesActivity.KEY_LATEST_VERSION_INSTALL, true).commit();
        File apk = new File(apkFile);
		if(apk.exists())apk.delete();
		//显示关于对话框
		Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                intent.setClassName(this, HelpActivity.class.getName());
                startActivity(intent);
                finish();
         }else {//不是第一次启动
  		  //是否完成上次下载的更新的安装
  		 if(!prefs.getBoolean(PreferencesActivity.KEY_LATEST_VERSION_INSTALL, true)){
  		    new AlertDialog.Builder(JumpActivity.this)
  		    .setTitle(R.string.app_update_title)
	  	    .setCancelable(false)
	  	    .setMessage(R.string.app_update_not_install)
	  	    .setPositiveButton(R.string.button_update_ok,new DialogInterface.OnClickListener() {   
				public void onClick(DialogInterface dialog, int which) {
					File apk = new File(apkFile);
			    		if(apk.exists())install();//下载的文件存在则安装
			    		else {//不存在则提示重新下载
			    			Intent update = new Intent(JumpActivity.this,UpdateService.class);
			    			startService(update);
			    		}
				}
		      })
		     .setNegativeButton(R.string.button_update_no,new DialogInterface.OnClickListener() {   
				public void onClick(DialogInterface dialog, int which) {
					//如果放弃本次更新,将不再进行提示
	prefs.edit().putBoolean(PreferencesActivity.KEY_LATEST_VERSION_INSTALL, true).commit();
					Log.v(TAG, "129");
					launchActivity();
					}
			     })
	  			.show();
  		   return;
  	     }
  		launchActivity();
  		
      }
    } catch (PackageManager.NameNotFoundException e) {
      Log.w(TAG, e);
    }
  }
 

 

 

private void install() {    
	   	Intent i = new Intent();
	   	i.setAction(Intent.ACTION_VIEW);    
	   	i.setDataAndType(Uri.fromFile(new File(apkFile)),    
               "application/vnd.android.package-archive");    
	   	startActivity(i);  
   }

 这个例子做了一个简单的跳转功能,通过Integer.parseInt(Build.VERSION.SDK) >= 5来分别启动适合不同系统版本的活动,使程序可以兼容跟多的手机。

 

private void launchActivity(){
	  if (Integer.parseInt(Build.VERSION.SDK) >= CameraManager.VERSION_CODES_LEVEL) {
			intent = new Intent(this,BJFILE.class);
		}else {
			intent = new Intent(this,EarlyBJFILE.class);
		}
	  startActivity(intent);
	  finish();
  }
 

2.在BJFILE或EarlyBJFILE活动中重我们使用一个Service来检查首否需要更新应用,当服务器上的apk文件的最后修改时间与程序配置文件中的最后修改时间不同,则表示发现新更新。

 

UpdateService.class

 

@Override
	public void onStart(Intent intent, int startId) {
		super.onStart(intent, startId);
		Log.v(TAG, "onStart");
		new Thread(){
			public void run(){
				if(checkUpdate()){//如果有更新,则显示更新界面UpdateActivity,类似一个对话框
				       Intent update = new Intent(UpdateService.this,UpdateActivity.class);
				       update.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				       update.putExtra(VERSITON, newVersion);
				      startActivity(update);
	  		  }else stopSelf();
			}
		}.start();
		
	}


         //可能是不存在该请求对象,返回的向应头中没有设置last-modified域,则取到的值为0
	private long getLastModified() {
		try {
			URL url = new URL(UpdateActivity.updateURL);
			URLConnection con = (URLConnection) url.openConnection();
			Log.v(TAG, "con.getLastModified()"+con.getLastModified());
			return  con.getLastModified();
		} catch (MalformedURLException e) {
			e.printStackTrace();
			Log.v(TAG, "MalformedURLException");
			return  1;
		} catch (IOException e) {
			e.printStackTrace();
			Log.v(TAG, "IOException");
			return  2;
		}
	}
	
	//判断是否需要更新
	private boolean checkUpdate(){
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
		long latest = prefs.getLong(PreferencesActivity.KEY_LATEST_VERSION, 0);
		newVersion = getLastModified();
		Log.v(TAG, "latest=" + latest);
		Log.v(TAG, "newVersion=" + newVersion);
		if(newVersion>latest)return true;
		else return false;
	}

 3.UpdateActivity的样式为

 

<style name="BackgroundOnly">
		<item name="android:windowBackground">@null</item>
		<item name="android:windowContentOverlay">@null</item>
		<item name="android:windowAnimationStyle">@null</item>
		<item name="android:windowNoTitle">true</item>
		<item name="android:windowNoDisplay">true</item>
		<item name="android:windowIsFloating">true</item>
</style>

 源代码

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;

public class UpdateActivity extends Activity{
	private static String TAG = "UpdateActivity";
	public static String updateURL = "http://www.bjnote.com/down4/bjnote.apk";//更新程序位置
	private static String updateContentURL="http://www.bjnote.com/down4/bjnote.txt";//更新内容
	private StringBuffer sb =null;
	private ProgressDialog download;
	private Handler mHandler;
	protected static final int GUI_STOP_NOTIFIER = 0x108;
	protected static final int GUI_THREADING_NOTIFIER = 0x109;
	protected static final int GUI_ERROR_NOTIFIER = 0x110;
	protected static final int GUI_IO_NOTIFIER = 0x111;
	protected static final int GUI_INTERRUPTED_NOTIFIER = 0x112;
	protected static final int GUI_PROGRESS_NOTIFIER = 0x113;//开始进度条的进度值显示
	protected static final int GUI_UPDATE_CONTENT_NOTIFIER = 0x114;//有更新文本
	private int count = 0;
	private long total;
	private DownThread downThread;
	private UpdateContent updateContent;
	private SharedPreferences prefs;
	private long newVersion;
	private String apkFile = Environment.getExternalStorageDirectory()+"/bjfile.apk";
	
	    class DownThread extends Thread{
	    	
	    	private boolean cancel=false;
	    	private  File file;
	    	
            public void run() {  
                HttpClient client = new DefaultHttpClient();  
                HttpGet get = new HttpGet(updateURL);  
                HttpResponse response = null; 
                FileOutputStream fileOutputStream = null;  
                InputStream is=null;
                try {  
                	response = client.execute(get);
                	if(response.getStatusLine().getStatusCode()!=200)
					throw new IOException("StatusCode!=200");
                    HttpEntity entity = response.getEntity();  
                    total = entity.getContentLength();
                    mHandler.sendEmptyMessage(GUI_PROGRESS_NOTIFIER);
                    is = entity.getContent(); 
                    if (is != null) {  
  
                        file = new File(apkFile);  
                        fileOutputStream = new FileOutputStream(file);  
                          
                        byte[] buf = new byte[1024];  
                        int ch = -1;
                        while ((ch = is.read(buf)) != -1) {
                        	if(cancel)throw new InterruptedException();
                        	count+=ch;
                            fileOutputStream.write(buf, 0, ch);
                            mHandler.sendEmptyMessage(GUI_THREADING_NOTIFIER);
                        } 
                        if(count==total)mHandler.sendEmptyMessage(GUI_STOP_NOTIFIER);
                        fileOutputStream.flush();
                        if(fileOutputStream!=null)fileOutputStream.close();
                    } 
                } catch (ClientProtocolException e) {   
                    e.printStackTrace();
                    mHandler.sendEmptyMessage(GUI_ERROR_NOTIFIER);
                    if(file.exists())file.delete(); 
        
                } catch (IOException e) {
                	if(file.exists())file.delete();   
                    e.printStackTrace();  
                    mHandler.sendEmptyMessage(GUI_IO_NOTIFIER);
                } catch (InterruptedException e) {
					e.printStackTrace();
					if(file.exists())file.delete(); 
					mHandler.sendEmptyMessage(GUI_INTERRUPTED_NOTIFIER);
				} finally{
					try {
						is.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
            }  
            
            private void setCancel(boolean isCancel){
            	cancel = isCancel;
            }
  
        }
	    
	    
    //读取更新内容
	    class UpdateContent extends Thread{
	    
            public void run() {  
                HttpClient client = new DefaultHttpClient();  
                HttpGet get = new HttpGet(updateContentURL);  
                HttpResponse response = null; 
                BufferedReader bis = null; 
                try {  
                	response = client.execute(get);
                	//添加更新提示
                	sb.append(UpdateActivity.this.getString(R.string.app_update_tip));
                	if(response.getStatusLine().getStatusCode()!=200){
                		throw new IOException("StatusCode!=200");
                	}
                    HttpEntity entity = response.getEntity();
                    //XXX 可能需要改成其他的编码,Apple默认是gb2312
                    bis = new BufferedReader(new InputStreamReader(entity.getContent(),"gb2312"));
                    String s=null;
                    if (bis != null) {  
                    	s=bis.readLine();
                        while (s!=null) {
                        	sb.append("\n"+s);
                        	s=bis.readLine();
                        } 
                        mHandler.sendEmptyMessage(GUI_UPDATE_CONTENT_NOTIFIER);
                        bis.close();
                    } 
                } catch (ClientProtocolException e) {   
                    e.printStackTrace();
                    stopService();
        
                } catch (IOException e) {
                    e.printStackTrace();  
                    stopService();
                }
            }  
            
        }
	    
	@Override
	public void onCreate(Bundle bundle) {
		super.onCreate(bundle);
		Log.v(TAG, "onCreate");
		mHandler = new Handler() {
			public void handleMessage(Message msg) {
				switch(msg.what) {
				case GUI_THREADING_NOTIFIER:
					download.setProgress(count);
					break;
				case GUI_STOP_NOTIFIER:
					 download.dismiss();
	 prefs.edit().putLong(PreferencesActivity.KEY_LATEST_VERSION, newVersion).commit();
					 //表示已下载但还未安装
	 prefs.edit().putBoolean(PreferencesActivity.KEY_LATEST_VERSION_INSTALL, false).commit();
					
					new AlertDialog.Builder(UpdateActivity.this)
		  			.setCancelable(false)
		  			.setTitle(R.string.app_update_title)
		  			.setMessage(R.string.button_update_finish)
		  		.setPositiveButton(R.string.button_ok,new DialogInterface.OnClickListener() {   
	  					public void onClick(DialogInterface dialog, int which) {
	  						install();
	  					}
	  			     })
		  		.setNegativeButton(R.string.button_exit, new DialogInterface.OnClickListener() {
		  					public void onClick(DialogInterface dialog, int which) {
		  						stopService();
		  					}
		  			 })
		  			.show();
					break;
				case GUI_IO_NOTIFIER:
				case GUI_ERROR_NOTIFIER:
					if(download!=null)download.dismiss();
					new AlertDialog.Builder(UpdateActivity.this)
		  			.setCancelable(false)
		  			.setMessage(R.string.app_update_error)
		  		.setPositiveButton(R.string.button_exit,new DialogInterface.OnClickListener() {   
	  					public void onClick(DialogInterface dialog, int which) {
	  						stopService();
	  					}
	  			     })
		  			.show();
					break;
				case GUI_INTERRUPTED_NOTIFIER:
					download.dismiss();
					new AlertDialog.Builder(UpdateActivity.this)
		  			.setCancelable(false)
		  			.setMessage(R.string.app_update_cancel)
		  		.setPositiveButton(R.string.button_exit,new DialogInterface.OnClickListener() {   
	  					public void onClick(DialogInterface dialog, int which) {
	  						stopService();
	  						//如果放弃本次更新,将不再进行提示
	  	prefs.edit().putLong(PreferencesActivity.KEY_LATEST_VERSION, newVersion).commit();
	        prefs.edit().putBoolean(PreferencesActivity.KEY_LATEST_VERSION_INSTALL, true).commit();
	  					}
	  			     })
		  			.show();
					break;
				case GUI_PROGRESS_NOTIFIER:
					 download.setMax((int) total);
					 download.setProgress(0);
					break;
				case GUI_UPDATE_CONTENT_NOTIFIER:
					download();
					break;
				}
			}
		};
		newVersion = getIntent().getLongExtra(UpdateService.VERSITON, 0);
		prefs = PreferenceManager.getDefaultSharedPreferences(this);
		sb = new StringBuffer();
		updateContent = new UpdateContent();
		updateContent.start();
	} 
   
  private void install() {    
	   	Intent i = new Intent(); 
       i.setAction(Intent.ACTION_VIEW);    
       i.setDataAndType(Uri.fromFile(new File(apkFile)),    
               "application/vnd.android.package-archive");    
       startActivity(i);
   }
  
  private void download() {
	  downThread = new DownThread();
	  
		new AlertDialog.Builder(this)
		.setTitle(R.string.app_update_title)
		.setCancelable(false)
		.setMessage(sb.toString())
		.setPositiveButton(R.string.button_update_ok,new DialogInterface.OnClickListener() {
			 public void onClick(DialogInterface dialog, int which) {
				 download = new ProgressDialog(UpdateActivity.this);
				 download.setMessage(getString(R.string.app_update_warn));
				 download.setCancelable(false);
				 download.setIndeterminate(false);
				 download.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
	download.setButton(getString(R.string.button_cancel), new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						downThread.setCancel(true);
					}
				});
				download.show();
				downThread.start();
					
				}
	     })
		 .setNegativeButton(R.string.button_update_no, new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					stopService();
	prefs.edit().putLong(PreferencesActivity.KEY_LATEST_VERSION, newVersion).commit();
	prefs.edit().putBoolean(PreferencesActivity.KEY_LATEST_VERSION_INSTALL, true).commit();
				}
		 })
		.show();
}

	/**
	 * stopSelf,服务关闭自身
	 */
	private void stopService() {
		Intent stop = new Intent(this,UpdateService.class);
		stopService(stop);
		Log.v(TAG, "stopService");
		finish();
		Log.v(TAG, "finish activity");
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		prefs=null;
		Log.v(TAG, "onDestroy");
	}
}
 
分享到:
评论
4 楼 live17909 2011-04-17  
老大,能发下源码吗?谢谢.paladin383@gmail.com
3 楼 ck19860613 2011-01-09  
自己逻辑很清楚,就是表述出来不太清楚
2 楼 yanghuaixi 2011-01-06  
我也刚刚做了一个相关的东西,有机会可以交流下
1 楼 yanghuaixi 2011-01-06  
很好很详细,多谢 

相关推荐

    C#程序自动更新 可实现自身更新

    AutoUpdater是C#中实现自动更新的一种常见工具。它可能是一个库或者框架,能够集成到你的C#应用中,帮助你轻松地添加自动更新功能。通过配置XML文件,开发者可以定义更新检查的频率、更新源、更新策略等参数,以满足...

    易语言实现程序自动更新源码

    易语言是一种专为中国人设计的编程语言,它以简体中文作为编程语法,降低了编程的门槛,使得更多非计算机专业的人也能轻松学习编程。在这个"易语言实现程序自动更新源码"的资源中,我们可以看到如何使用易语言来构建...

    易语言制作自动更新 易语言软件自动更新【模块】

    易语言是一种专为中国人设计的编程语言,它以简化的语法和中文命令词为核心,使得初学者能够更容易地进入编程世界。"易语言制作自动更新 易语言软件自动更新【模块】"是一个针对易语言开发的特定功能模块,主要用于...

    visual c++源码 自动更新(在线更新)功能

    - **Microsoft Update Agent (MSUA)**:微软提供的一种框架,允许开发者将Windows Update服务集成到自己的应用程序中,实现自动更新。 - **自定义HTTP/FTP服务器**:开发者也可以建立自己的服务器来托管更新文件,...

    android app自动更新功能的实现

    Firebase App Distribution是另一种测试阶段的更新工具,它允许开发者快速分发应用到测试者,并提供类似自动更新的功能,但主要用于内部测试和Alpha/Beta版本的迭代。 二、实现步骤 1. **集成Google Play服务**:...

    安卓app自动更新,一行代码搞定,最新开源库

    "安卓app自动更新,一行代码搞定,最新开源库"这个标题所指的,就是一种简化了自动更新流程的方法,它利用特定的开源库,使得开发者只需要一行代码就能实现在用户设备上检查并安装应用的更新。这大大提高了开发效率...

    c# FTP自动更新模块源码

    FTP(File Transfer Protocol)是一种标准网络协议,用于在Internet上进行文件传输。 C#语言提供了丰富的类库来支持FTP操作,如`System.Net.FtpWebRequest`和`System.Net.FtpWebResponse`,它们允许开发者编写代码...

    C#使用FTP实现客户端程序自动更新(调试通过)

    FTP是一种网络协议,用于在网络上进行文件传输。在C#中,我们可以使用`System.Net.FtpWebRequest`类来创建FTP请求,并使用`System.IO`命名空间中的类来处理文件读写操作。 1. **创建FTP连接** 要连接到FTP服务器,...

    易语言单文件更新提示自动更新并替换自身

    在“易语言单文件更新提示自动更新并替换自身”的主题中,我们主要讨论的是如何设计一个程序,使得该程序在检测到有新版本可用时,能够自动下载更新并替换自身的旧版本。这个功能在许多软件的自动更新机制中很常见,...

    如何使自己的程序自动更新(在线更新) c++

    在C++编程中,实现程序的自动更新功能可以让用户轻松获取到最新的软件版本,提高用户体验。这个过程通常涉及几个关键步骤:检测新版本、下载更新文件、安装更新以及重启程序。下面将详细介绍如何在C++中实现这些步骤...

    安卓消息推送通知栏相关-Android实现APP在线下载更新实现了软件自动更新功能的方法.rar

    总结来说,这个压缩包文件的内容可能涵盖了从检测新版本、推送消息、下载更新、安装更新到实现自动更新的一系列过程。对于开发者来说,这是一个很好的学习和参考资源,可以深入理解Android应用更新的机制,并根据...

    ajax实现自动提示搜索

    Ajax(Asynchronous JavaScript and XML)是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。它通过在后台与服务器进行少量数据交换,使网页实现异步更新,大大提升了用户体验。在本示例中,我们将...

    Delphi 开发的程序自动更新控件

    综上所述,Delphi的AutoUpgrader_XE6控件为开发者提供了一种便捷的方式,实现在Delphi应用中的自动更新功能。通过理解和利用这个控件的特性,开发者可以轻松地创建一个能够自我保持最新状态的应用程序,从而提高用户...

    C# WPF 实现简单的自动更新智能客户端

    在IT行业中,C# WPF(Windows Presentation Foundation)是一种用于构建桌面应用程序的强大框架,由Microsoft开发。本主题将深入探讨如何使用C# WPF来实现一个简单的自动更新功能,这对于保持智能客户端应用的最新...

    c#实现自动更新例子

    C#是一种广泛应用于Windows桌面应用、游戏开发、Web服务等领域的面向对象的编程语言,具有丰富的类库支持,使得实现自动更新变得更加便捷。 首先,我们要理解自动更新的基本流程: 1. **检测更新**:程序启动时或...

    WinForm AutoUpdate自动更新源码

    "WinForm AutoUpdate自动更新源码"提供了一种实现这一功能的解决方案。这个源码经过了全面的验证和测试,并已应用于实际项目,确保了其稳定性和可靠性。 自动更新机制通常包含以下几个关键部分: 1. **检查更新**...

    让myeclipse实现代码自动提示

    总的来说,熟练掌握MyEclipse的代码自动提示功能可以显著提升编程效率,导入EPF文件则提供了一种快速调整代码提示设置的方式。在日常开发中,我们应该根据自己的需求不断优化这些设置,使开发过程更加流畅。

    java 在线更新源码 自动更新工具

    在软件开发过程中,经常会遇到修复错误、添加新功能或者优化性能的需求,这时就需要有一种机制能够让用户无需手动下载安装新的版本,而是能够通过网络自动获取并更新程序的最新代码。Java作为广泛使用的编程语言,...

    VB自动更新,亲测

    VB(Visual Basic)是微软公司开发的一种编程语言,主要用于创建Windows桌面应用程序。"VB自动更新"指的是使用VB来实现程序的自动更新功能。在软件开发中,自动更新机制是至关重要的,它允许用户无需手动下载安装...

    一种基于浏览器的自动小票机打印实现方案(js版)

    总结起来,基于浏览器的自动小票机打印实现方案,特别是通过JavaScript实现的版本,为Web应用提供了一种高效、便捷且用户体验良好的打印方式。该方案的实施,不仅要求开发者具备前端开发技术,还需要对打印机、操作...

Global site tag (gtag.js) - Google Analytics