博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实现Android应用自动更新
阅读量:6653 次
发布时间:2019-06-25

本文共 6960 字,大约阅读时间需要 23 分钟。

hot3.png

一、自动更新实现流程

  1. 从服务器端获取最新应用的版本信息

  2. 从本地配置文件中读取本地应用的版本信息

  3. 比较服务端版本信息和本地版本信息,若服务器端的版本号大于本地的版本号,则转4,否则结束

  4. 弹框提示用户应用程序有更新的版本,询问是否需要下载,若是则转5,否则弹框消失,结束

  5. 从服务器端获取最新版应用程序,存于本地,并进行安装

二、自动更新实现过程

  1. 新建一个Android工程,如我的工程文件目录为:                                              211731_4oGS_2621851.png

  2. 在工程文件中新建一个activity,用于呈现自动更新提示对话框。如上图工程中的AutoUpdateActivity,该activity代码如下:

//一个用于呈现提示用于进行更新的页面public class AutoUpdateActivity extends Activity {	private static final String TAG = "AutoUpdateActivity";    //日志打印标志	private static int localVersionCode, serverVersionCode = 0;   //本地和服务器端应用版本号	private String fileName, filePath;    //应用程序保存文件名和文件路径	private Context context;	@Override	protected void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		//设置当前activity的布局文件,任意布局文件皆可		setContentView(R.layout.activity_auto_update);    		context = this;		filePath = "Star";	}	@Override	protected void onResume() {		super.onResume();		// 检查是否需要进行版本更新,该函数必须在onResume或者onStart中调用,否则可能报错		checkUpdate();	}	// 检查是否有新的版本	private void checkUpdate() {		// 获取本地应用程序版本号		try {			localVersionCode = context.getPackageManager().getPackageInfo(					context.getPackageName(), 0).versionCode;		} catch (NameNotFoundException e) {			e.printStackTrace();		}		// 比较本地版本号与服务器端版本号,判断是否需要更新		if (getServerVersionCode() > localVersionCode) {			fileName = "Star.apk";			showUpdateDialog();		}	}	// 获取服务器端应用程序版本号	private int getServerVersionCode() {		RequestParams params = new RequestParams();		StringBuilder versionCode = new StringBuilder();		versionCode.append("{\"getVersionCode\"}");		params.put("param", versionCode.toString());		AsyncHttpClient client = new AsyncHttpClient();		//向服务器请求最新版本号的URL地址		String urlString = utils.Constants.SERVER_BASE_URL				+ utils.Constants.GET_VERSION_CODE;		client.post(urlString, params, new AsyncHttpResponseHandler() {			@Override			public void onSuccess(String response) {				serverVersionCode = Integer.parseInt(JsonUtil						.getResult(response));			}			@Override			public void onFailure(Throwable error, String content) {				serverVersionCode = 0;				Log.d(TAG, content + " ");			}		});		return serverVersionCode;	}	// 显示应用程序更新对话框	private void showUpdateDialog() {	        //创建一个对话框		AlertDialog.Builder builder = new AlertDialog.Builder(context);		//设置对话框标题、显示信息等		builder.setTitle("版本更新").setMessage("Star有新版本啦,快下载体验吧~")				.setIcon(com.star.R.drawable.ic_update_dialog);		//设置对话框的响应按钮		builder.setPositiveButton("下载", new OnClickListener() {			@Override			public void onClick(DialogInterface dialog, int which) {				dialog.dismiss();				//DownTask是一个我自己写的AsyncTask类,用于下载最新版的应用程序				DownTask downTask = new DownTask(context, filePath, fileName);				downTask.execute(Constants.SERVER_BASE_URL						+ Constants.GET_NEW_VERSION);			}		});		builder.setNegativeButton("以后再说", new OnClickListener() {			@Override			public void onClick(DialogInterface dialog, int which) {				dialog.dismiss();    //对话框消失			}		});		builder.show();    //必须调用该函数,否则创建的对话框将不会显示	}}

    上面代码中的checkUpdate()函数包含了上述原理一中的1、2、3步,当if条件判断为真时,显示应用更新提示对话框,即调用showUpdateDilaog()方法,用户选择“下载”,则下载该应用程序,并进行更新(这部分为调用DownTask进行处理);

DownTask类代码如下:

//DownTask是通过一部任务进行应用下载的,也可以开启一个新的工作线程进行下载public class DownTask extends AsyncTask
 { private static final String TAG = "DownTask"; private Context mContext; private AlertDialog aDialog; private String filePath; private String fileName; /**  * 构造函数  *   * @param ctx  * @param savePath  *            :下载资源保存路径  @param fileName  *            :下载资源保存文件名  */ public DownTask(Context ctx, String savePath, String fileName) { mContext = ctx; filePath = savePath; this.fileName = fileName; } @SuppressWarnings("unused") @Override protected String doInBackground(String... params) { //FileUtils是自己写的一个文件工具 FileUtils fileUtil = new FileUtils(); String result = null; File file; try { file = new File(fileUtil.getSDPATH() + filePath + "/" + fileName); if (file.exists()) { result = "File exist!"; Log.i(TAG, result); } else { fileUtil.createSDDir(filePath); file.createNewFile(); URL url = new URL(params[0]); HttpURLConnection urlConnection = (HttpURLConnection) url .openConnection(); fileUtil.write2SDFromInput(filePath, fileName, urlConnection.getInputStream()); if (file != null) { result = "success"; } else { result = "Fail"; } } } catch (IOException e1) { e1.printStackTrace(); } Log.i(TAG, result); return result; } @Override protected void onPostExecute(String result) { Toast.makeText(mContext, "最新版Star已经下载好啦,赶快试用吧!",                  Toast.LENGTH_LONG); Log.i(TAG, "Finish download"); aDialog.dismiss(); installApk(); } // 安装apk文件 private void installApk() { File apkfile = new File(filePath + "/" + fileName); if (!apkfile.exists()) { return; } //调用安装应用程序的Intent Intent i = new Intent(Intent.ACTION_VIEW); i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive"); mContext.startActivity(i); } @Override protected void onPreExecute() { AlertDialog.Builder builder = new AlertDialog.Builder(mContext); builder.setTitle("下载Star").setMessage("新版本下载中...") .setIcon(R.drawable.ic_update_dialog).show(); aDialog = builder.create(); }}

FileUtils代码:

public class FileUtils {	private String SDPATH;	private int FILESIZE = 4 * 1024;	public String getSDPATH() {		return SDPATH;	}		public FileUtils() {		// 得到当前外部存储设备的目录( /SDCARD )		SDPATH = Environment.getExternalStorageDirectory() + "/";	}	/**	 * 在SD卡上创建文件	 * 	 * @param fileName	 * @return	 * @throws IOException	 */	public File createSDFile(String fileName) throws IOException {		File file = new File(SDPATH + fileName);		file.createNewFile();		return file;	}	/**	 * 在SD卡上创建目录	 * 	 * @param dirName	 * @return	 */	public File createSDDir(String dirName) {		File dir = new File(SDPATH + dirName);		dir.mkdir();		return dir;	}	/**	 * 判断SD卡上的文件夹是否存在	 * 	 * @param fileName	 * @return	 */	public boolean isFileExist(String fileName) {		File file = new File(SDPATH + fileName);		return file.exists();	}	/**	 * 将一个InputStream里面的数据写入到SD卡中	 * 	 * @param path	 * @param fileName	 * @param input	 * @return	 */	public File write2SDFromInput(String path, String fileName,			InputStream input) {		File file = null;		OutputStream output = null;		try {			createSDDir(path);			file = createSDFile(path + fileName);			output = new FileOutputStream(file);			byte[] buffer = new byte[FILESIZE];			int length;			while ((length = (input.read(buffer))) > 0) {				output.write(buffer, 0, length);			}			output.flush();		} catch (Exception e) {			e.printStackTrace();		} finally {			try {				output.close();			} catch (IOException e) {				e.printStackTrace();			}		}		return file;	}}

最后别忘了在manifest文件中添加相应的权限以及该activity

    
    
    
    
    
        
            
                
                
            
            

注意:Android不能在UI线程中进行比较耗时的操作,否则可能导致页面阻塞,甚至引发ANR错误(程序未响应),所以该示例中的下载操作放到一个异步任务中进行的,也可以采用工作线程的方式

转载于:https://my.oschina.net/purplesense/blog/626959

你可能感兴趣的文章
Android 编程下快捷图标的创建
查看>>
C++ GUI Qt4 自学笔记——Qt qmake命令
查看>>
烂透了与棒极了
查看>>
修改10g自动统计信息收集作业GATHER_STATS_JOB到仅仅周末执行
查看>>
Calibrate测试Exadata IO
查看>>
【C语言】15-预处理指令1-宏定义
查看>>
【C语言】19-static和extern关键字1-对函数的作用
查看>>
9、单机运行环境搭建之 --CentOS-6.4下mysqldump 备份与还原数据库
查看>>
分享:C++中头文件、源文件之间的区别与联系
查看>>
好类 笔记
查看>>
Web前端浏览器兼容初探【转】
查看>>
菜鸟开技术博啦
查看>>
关于多线程生命周期原理
查看>>
如何使用U盘安装操作系统 安装GHOST XP, xp纯净版
查看>>
POJ 1062 昂贵的聘礼
查看>>
理解Java对象序列化——Serializable接口
查看>>
一个简易的WebServer程序
查看>>
Python学习入门基础教程(learning Python)--5.3 Python写文件基础
查看>>
关于js加密解密
查看>>
JBoss7快速入门
查看>>