android自动更新代码实现------------安卓开发第一步:让APP学会自动更新

时间:2022-12-01 05:58:55


        我们在做项目开发的过程中,总有需求变更,不论是在web项目还是现在大多人都在做而且做的很火的App项目,所以我们需要在客户不断修改需求、用户不断反馈的过程中一步步的去优化我们的软件,但是我们的版本已经上线,该如何在用户不需再次人工下载的情况下去提示用户实时更新到我们的最新版本做更好的用户体验呢?这里我们就需要我们在在线更新功能,下面我们来一步步去实现我们的【自动检测跟新功能】

①软件自动更新的的原理实现:我们对于软件版本更新的实现首先需要一个服务器端和我们本地手机客户端,我们在服务器端将有一个接口提供实时信息和一个“最新”版本的apk文件;首先我们打开软件的时候会通过接口获取到最新的实时消息,其中包括【versionCode】【downAdd】【updateContent】【XXX.apk】;然后将获取的本地应用apk的版本号【localVersionCode】;将【versionCode】和本地I的【localVersionCode】做比较如果【versionCode】>【localVersionCode】则做更新操作,反之不做任何提示;大致流程看下图:android自动更新代码实现------------安卓开发第一步:让APP学会自动更新

②在上面的流程中我们了解到了【软件自动检测更新】的基本流程,下面我们来看看服务器端的数据,下面以一个json字符串解析为例:

{"content":"①软件性能更加稳定,用户体验更佳;\\n②修复上下和左右滑动时,页面有时无法滑动的问题;\\n③修复上下和左右滑动时,页面有时无法滑动的问题;","result":1,"download_address":"http://p.ewoho.com/DownLoad/DownLoadHurryTime/","version":"7"}

在上面的json字符串中我们做json的解析获取到 【versionCode】【downAdd】【updateContent】

然后我们就需要获取到我们本地的apk的版本号,或许有人会问我们是如何获取我们手机apk中的版本号的呢?下面我们就来进一步的讲解这部分的完成:

我们在android的项目中会有一个【AndroidManifest.xml】在这个xml文件中我们是存在【versionCode】【versionName】两个参数,其中【versionCode】就是我们用于做版本更新的检测参数(整形),【versionName】用于给用户提示的版本信息;

android自动更新代码实现------------安卓开发第一步:让APP学会自动更新

下面我们来实现对版本号【versionCode】的获取代码实现:

// 获取软件版本号,对应AndroidManifest.xml下android:versionCode
			versionCode = context.getPackageManager().getPackageInfo(
					"com.xxx.Hurry", 0).versionCode;

在这里的VersionCode就是我们获取到到的本地版本号【localVersionCode】,当我们的服务器端【versionCode】>【localVersionCode】我们进行一下的版本跟新:

a.获取服务器端的apk文件并保存到本地文件中

b.卸载之前的版本文件,安装最新的下载到的文件

下面我们来采用代码实现上述中的a、b两步骤:

/**
 * @author cuiyongzhi
 * @date 2014-05-30
 * 
 * 
 *  */
public class UpdateManager {
	/* 下载�? */
	private static final int DOWNLOAD = 1;
	/* 下载结束 */
	private static final int DOWNLOAD_FINISH = 2;
	/* 下载保存路径 */
	private String mSavePath;
	/* 记录进度条数�? */
	private int progress;
	/* 是否取消更新 */
	private boolean cancelUpdate = false;

	private Context mContext;
	/* 更新进度�? */
	private ProgressBar mProgress;
	private Dialog mDownloadDialog;

	public static int Version_result = 0;
	public static String down_address = null;
	public static int Version_code = 0;
	public static String Update_Content = null;

	public static String TAG = "UpdateManager";

	private Handler mHandler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			// 正在下载
			case DOWNLOAD:
				// 设置进度条位
				mProgress.setProgress(progress);
				break;
			case DOWNLOAD_FINISH:
				// 安装文件
				installApk();
				break;
			default:
				break;
			}
		};
	};

	public UpdateManager(Context context) {
		this.mContext = context;
	}

	public void checkUpdate() {
		if (isUpdate()) {
			// 显示提示对话
			showNoticeDialog();
		} else {
			// Toast.makeText(mContext, R.string.soft_update_no,
			// Toast.LENGTH_LONG)
			// .show();
		}
	}

	/**
	 * 
	 * 
	 * @return
	 */
	private boolean isUpdate() {
		// 获取当前软件版本
		int LocalversionCode = getVersionCode(mContext);
		Log.i(TAG, " " + LocalversionCode);
		Log.i(TAG, Version_code + "=Version_code");
		if (Version_code > LocalversionCode) {
			return true;
		}

		return false;
	}

	/**
	 * 获取软件版本�?
	 * 
	 * @param context
	 * @return
	 */
	private int getVersionCode(Context context) {
		int versionCode = 0;
		try {
			// 获取软件版本号,对应AndroidManifest.xml下android:versionCode
			versionCode = context.getPackageManager().getPackageInfo(
					"com.iflyun.Hurry", 0).versionCode;
		} catch (NameNotFoundException e) {
			e.printStackTrace();

		}
		return versionCode;
	}

	/**
	 * 显示软件更新对话
	 */
	private void showNoticeDialog() {
		//
		AlertDialog.Builder builder = new Builder(mContext);
		builder.setTitle(R.string.soft_update_title);
		builder.setIcon(R.drawable.ic_launcher);
		builder.setMessage("版本更新:\n" + Update_Content.replace("\\n", "\n"));
		// 更新
		builder.setPositiveButton(R.string.soft_update_updatebtn,
				new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
						// 显示下载对话�?
						showDownloadDialog();
					}
				});
		// 稍后更新
		builder.setNegativeButton(R.string.soft_update_later,
				new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
						Intent intent = new Intent(mContext, MainActivity.class);
						intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
								| Intent.FLAG_ACTIVITY_NEW_TASK); // 清空前栈,开启新栈存放activity
						mContext.startActivity(intent);
					}
				});
		Dialog noticeDialog = builder.create();
		noticeDialog.show();
	}

	/**
	 * 显示软件下载对话�?
	 */
	private void showDownloadDialog() {
		// 构�?软件下载对话�?
		AlertDialog.Builder builder = new Builder(mContext);
		builder.setTitle(R.string.soft_updating);
		builder.setIcon(R.drawable.ic_launcher);
		// 给下载对话框增加进度�?
		final LayoutInflater inflater = LayoutInflater.from(mContext);
		View v = inflater.inflate(R.layout.softupdate_progress, null);
		mProgress = (ProgressBar) v.findViewById(R.id.update_progress);
		builder.setView(v);
		// 取消更新
		builder.setNegativeButton(R.string.soft_update_cancel,
				new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
						// 设置取消状
						cancelUpdate = true;
					}
				});
		mDownloadDialog = builder.create();
		mDownloadDialog.show();
		// 下载文件
		downloadApk();
	}

	/**
	 * 下载apk文件
	 */
	private void downloadApk() {
		// 启动新线程下载软�?
		new downloadApkThread().start();
	}

	/**
	 * 下载文件线程
	 * 
	 * @author cuiyongzhi
	 * @date 2014-04-28
	 * 
	 */
	private class downloadApkThread extends Thread {
		@Override
		public void run() {
			try {
				// 判断SD卡是否存在,并且是否具有读写权限
				if (Environment.getExternalStorageState().equals(
						Environment.MEDIA_MOUNTED)) {
					// 获得存储卡的路径
					String sdpath = Environment.getExternalStorageDirectory()
							+ "/";
					mSavePath = sdpath + "Hurrydownload";
					URL url = new URL(down_address);
					// 创建连接
					HttpURLConnection conn = (HttpURLConnection) url
							.openConnection();
					conn.connect();
					// 获取文件大小
					int length = conn.getContentLength();
					// 创建输入�?
					InputStream is = conn.getInputStream();

					File file = new File(mSavePath);
					// 判断文件目录是否存在
					if (!file.exists()) {
						file.mkdir();
					}
					File apkFile = new File(mSavePath, "GoTime.apk");
					FileOutputStream fos = new FileOutputStream(apkFile);
					int count = 0;
					// 缓存
					byte buf[] = new byte[1024];
					// 写入到文件中
					do {
						int numread = is.read(buf);
						count += numread;
						// 计算进度条位�?
						progress = (int) (((float) count / length) * 100);
						// 更新进度
						mHandler.sendEmptyMessage(DOWNLOAD);
						if (numread <= 0) {
							// 下载完成
							mHandler.sendEmptyMessage(DOWNLOAD_FINISH);
							break;
						}
						// 写入文件
						fos.write(buf, 0, numread);
					} while (!cancelUpdate);// 点击取消就停止下�?
					fos.close();
					is.close();
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			// 取消下载对话框显�?
			mDownloadDialog.dismiss();
		}
	};

	/**
	 * 安装APK文件
	 */
	private void installApk() {
		File apkfile = new File(mSavePath, "GoTime.apk");
		if (!apkfile.exists()) {
			return;
		}
		// 通过Intent安装APK文件
		Intent intent = new Intent();

		intent.setAction(android.content.Intent.ACTION_VIEW);
		intent.setDataAndType(Uri.parse("file://" + apkfile.toString()),
				"application/vnd.android.package-archive");
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		mContext.startActivity(intent);

	}
}

上述代码片段是版本跟新的主要代码实现,在其中的大部分代码都是有详细说明的,不懂的可以留言询问,需要源码的也可以留下邮箱;

其中我主要想讲述的是在【installApk】中的(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);)在4.0版本之前可以不加这就代码就能实现功能,但是在4.0以后的版本中如果不加入上面的那句话将会是在自动安装之后不出现任何的提示,所以建议在所有的更新文件中都加入以便解决意外;

这是关于app开发流程中的第一篇:版本检测更新;后续将继续推出一步步的实现整个项目完成的流程代码实现,还请多指教,欢迎访问个人博客(http://cuiyongzhi.com)!