几种检查更新并下载新版本的实现

android 专栏收录该内容
7 篇文章 0 订阅

1.首先是获取当前程序的版本号

private String getVersion() {
	try {
		PackageManager packageManager = getPackageManager();
		PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
		return packageInfo.versionName;
	} catch (NameNotFoundException e) {
		e.printStackTrace();
		return "版本号未知";
	}
}
2. 访问服务器检查是否更新

private boolean isNeedUpdate(String version) {
		UpdateInfoService updateInfoService = new UpdateInfoService(this);
		try {
			info = updateInfoService.getUpdateInfo(R.string.serverUrl);
			String v = info.getVersion();
			if(v.equals(version)) {
				Log.i(TAG, "当前版本:" + version);
				Log.i(TAG, "最新版本:" + v);
				loadMainUI();
				return false;
			} else {
				Log.i(TAG, "需要更新");
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
			Toast.makeText(this, "获取更新信息异常,请稍后再试", Toast.LENGTH_SHORT).show();
			loadMainUI();
		}
		return false;
	}
R.string.serverUrl是服务器放置更新信息的地址,使用一个类去查询更新信息

public class UpdateInfoService {
	
	private Context context;

	public UpdateInfoService(Context context) {
		this.context = context;
	}

	public UpdateInfo getUpdateInfo(int urlId) throws Exception {
		String path = context.getResources().getString(urlId);拿到config.xml里面存放的地址
		URL url = new URL(path);
		HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();//开启一个http链接
		httpURLConnection.setConnectTimeout(10000);//设置链接的超时时间,现在为5秒
		httpURLConnection.setRequestMethod("GET");//设置请求的方式
		InputStream is = httpURLConnection.getInputStream();//拿到一个输入流。里面包含了update.xml的信息
		return UpdateInfoParser.getUpdateInfo(is);//解析xml
	}
}
其中用到了一个解析xml文件的类

public class UpdateInfoParser {
	
	public static UpdateInfo getUpdateInfo(InputStream is) throws Exception {
		UpdateInfo info = new UpdateInfo();
		XmlPullParser xmlPullParser = Xml.newPullParser();
		xmlPullParser.setInput(is, "utf-8");
		int type = xmlPullParser.getEventType();
		
		while(type != XmlPullParser.END_DOCUMENT) {
			switch(type) {
			case XmlPullParser.START_TAG :
				
				if(xmlPullParser.getName().equals("version")) {
					info.setVersion(xmlPullParser.nextText());
				} else if (xmlPullParser.getName().equals("description")) {
					info.setDescription(xmlPullParser.nextText());
				} else if (xmlPullParser.getName().equals("apkurl")) {
					info.setUrl(xmlPullParser.nextText());
				}
				break;
			default :
				break;
			}
			type = xmlPullParser.next();
		}
		return info;
	}
}
3.下面调用isNeedUpdate(getVersion())检查是否需要更新

这里需要注意,由于UpdateInfoService类的getUpdateInfo方法中访问服务器不是异步的,如果直接在Activity的onCreate()中直接调用isNeedUpdate(getVersion())获取不到更新信息,需要将isNeedUpdate(getVersion())放入到子线程中。

class UpdateHandler implements Runnable {
		@Override
		public void run() {
			Looper.prepare();
			if(isNeedUpdate(getVersion())) {
				showUpdateDialog();
			}
			Looper.loop();
		}
	}
然后在onCreate方法中启动线程

Runnable r = new UpdateHandler();
Thread thread = new Thread(r);
thread.start();
然后是显示对话框

private void showUpdateDialog() {
		
		AlertDialog.Builder builder = new AlertDialog.Builder(SplashActivity.this);
		builder.setIcon(android.R.drawable.ic_dialog_info);
		builder.setCancelable(false);

		builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
					File dir = new File(Environment.getExternalStorageDirectory(), "/chaoshibang/update");
					if(!dir.exists()) {
						dir.mkdirs();
					}
					String apkPath = Environment.getExternalStorageDirectory() + "/chaoshibang/update/new.apk";
					//这里启动DownloadFileTask任务
					new DownloadFileTask().execute(info.getUrl(), apkPath);
					progressDialog.show();

				} else {
					Toast.makeText(SplashActivity.this, "SD卡不可用,请插入SD卡", Toast.LENGTH_SHORT).show();
					loadMainUI();
				}
			}
		});
		builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				loadMainUI();
			}

		});
		builder.create().show();
	}
在对话框的确定按钮的响应事件中下载APK文件

4.一种方式使用AsyncTask来下载apk文件

private class DownloadFileTask extends AsyncTask<String, Integer, File> {

		public DownloadFileTask() {
			super();
		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			progressDialog.show();
		}

		@Override
		protected void onPostExecute(File file) {
			super.onPostExecute(file);
			progressDialog.dismiss();
			loadMainUI();
			Intent intent = new Intent();
			intent.setAction(Intent.ACTION_VIEW);
			intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
			startActivity(intent);
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);
			progressDialog.setMax(values[1]);
			progressDialog.setProgress(values[0]);
		}

		@Override
		protected File doInBackground(String... params) {
			try {
				URL url = new URL(params[0]);
				HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
				httpURLConnection.setConnectTimeout(2000);
				httpURLConnection.setRequestMethod("GET");
				if(httpURLConnection.getResponseCode() == 200) {
					int total = httpURLConnection.getContentLength();

					InputStream is = httpURLConnection.getInputStream();
					File file = new File(params[1]);
					FileOutputStream fos = new FileOutputStream(file);
					byte[] buffer = new byte[1024];
					int len;
					int process = 0;
					while((len = is.read(buffer)) != -1) {
						fos.write(buffer, 0, len);
						process += len;
						publishProgress(process, total);
					}
					fos.flush();
					fos.close();
					is.close();
					return file;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}
	}
doInbackground()在子线程中下载apk文件,在其它三个方法中操作progressDialog的显示、进度


5.另一种方式使用Service,参照http://blog.csdn.net/xiaanming/article/details/9750689

public class DownloadFileService extends Service {

    private String urlPath="";
    //文件存储
    private File updateFile = null;
    private OnProgressListener onProgressListener;

    private Intent mIntent = new Intent("com.yifeng.chaoshibang.broadcast.UPDATE_APK");

    public DownloadFileService() {
    }

    public void setOnProgressListener(OnProgressListener onProgressListener) {
        this.onProgressListener = onProgressListener;
    }

    /**
     * 返回一个Binder对象
     */
    @Override
    public IBinder onBind(Intent intent) {
        super.onBind(intent);
        return new DownloadBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        urlPath = intent.getStringExtra("url");
        //创建文件
        if(FileUtil.haveSDCard()) {
            updateFile = FileUtil.getFile(Config.sd_folder_name, Config.sd_apk_name);
        }
        //开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞
        new Thread(new DownloadRunnable()).start();
        return super.onStartCommand(intent, flags, startId);
    }

    class DownloadRunnable implements Runnable {
        @Override
        public void run() {
            HttpURLConnection httpURLConnection = null;
            InputStream input = null;
            FileOutputStream fos = null;
            try {
                URL url = new URL(urlPath);
                httpURLConnection = (HttpURLConnection) url.openConnection();
                httpURLConnection.setConnectTimeout(2000);
                httpURLConnection.setRequestMethod("GET");
                if(httpURLConnection.getResponseCode() == 200) {
                    int total = httpURLConnection.getContentLength();
                    if(onProgressListener != null) {
                        onProgressListener.onProgressInitialize(total);
                    }
                    input = httpURLConnection.getInputStream();
                    fos = new FileOutputStream(updateFile);
                    byte[] buffer = new byte[1024];
                    int len;
                    int progress = 0;
                    while((len = input.read(buffer)) != -1) {
                        fos.write(buffer, 0, len);
                        progress += len;
                        //进度发生变化通知调用方
                        if(onProgressListener != null){
                            onProgressListener.onProgressUpdate(progress);
                        }
                    }
                    fos.flush();
                    if(onProgressListener != null){
                        onProgressListener.onProgressComplete(updateFile);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if(fos != null) {
                        fos.close();
                    }
                    if(input != null) {
                        input.close();
                    }
                    if(httpURLConnection != null) {
                        httpURLConnection.disconnect();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public class DownloadBinder extends Binder {
        /**
         * 获取当前Service的实例
         */
        public DownloadFileService getService() {
            return DownloadFileService.this;
        }
    }
}

为了能使DownloadFileService中进度变化信息通知给调用方,首先定义一个接口

public interface OnProgressListener {
    void onProgressInitialize(int total);
    void onProgressUpdate(int progress);
    void onProgressComplete(File file);
}

然后在Activity中绑定Service

public class SplashActivity extends BaseActivity {
	private ProgressDialog progressDialog;
	private UpdateInfo info;
	private static final String TAG = "SplashActivity";
	private DownloadFileService downloadFileService;

	ServiceConnection conn = new ServiceConnection() {
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			//返回一个DownloadFileService对象
			downloadFileService = ((DownloadFileService.DownloadBinder)service).getService();
			//注册回调接口来接收下载进度的变化
			downloadFileService.setOnProgressListener(new OnProgressListener() {
				@Override
				public void onProgressInitialize(int total) {
					progressDialog.setMax(total);
				}
				@Override
				public void onProgressUpdate(int progress) {
					progressDialog.setProgress(progress);
				}
				@Override
				public void onProgressComplete(File file) {
					progressDialog.dismiss();
					Intent intent = new Intent(SplashActivity.this, DownloadFileService.class);
					unbindService(conn);
					stopService(intent);
					//安装下载的文件
					install(file);
				}
			});
		}
		@Override
		public void onServiceDisconnected(ComponentName name) {
		}
	};


在ServiceConnection的onServiceConnected回调中为service设置了回调监听器。当在DownloadFileService中调用时就会执行这里的回调,更新progressDialog

然后在对话框的确定按钮的响应事件中启动Service

将new DownloadFileTask().execute(info.getUrl(), apkPath); 替换为

//绑定DownloadFileService
//Intent intent = new Intent("com.yifeng.chaoshibang.service.DOWNLOAD_APK_ACTION");
Intent intent = new Intent(SplashActivity.this, DownloadFileService.class);
intent.putExtra("url", info.getUrl());
startService(intent);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
progressDialog.show();

这里需要注意,在DownloadFileService中是在onStartCommand()方法中启动线程去下载文件。根据Service的生命周期,bindService()方法不会调用onStartCommand(),所以还需使用startService()启动Service。

6.Service和BroadcastReceiver实现

public class DownloadFileService extends BaseService {

    private String urlPath="";
    //文件存储
    private File updateFile = null;

    private Intent mIntent = new Intent("com.yifeng.chaoshibang.broadcast.UPDATE_APK");

    public DownloadFileService() {
    }

    /**
     * 返回一个Binder对象
     */
    @Override
    public IBinder onBind(Intent intent) {
        super.onBind(intent);
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        urlPath = intent.getStringExtra("url");
        //创建文件
        if(FileUtil.haveSDCard()) {
            updateFile = FileUtil.getFile(Config.sd_folder_name, Config.sd_apk_name);
        }
        //开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞
        new Thread(new DownloadRunnable()).start();
        return super.onStartCommand(intent, flags, startId);
    }

    class DownloadRunnable implements Runnable {
        @Override
        public void run() {
            HttpURLConnection httpURLConnection = null;
            InputStream input = null;
            FileOutputStream fos = null;
            try {
                URL url = new URL(urlPath);
                httpURLConnection = (HttpURLConnection) url.openConnection();
                httpURLConnection.setConnectTimeout(2000);
                httpURLConnection.setRequestMethod("GET");
                if(httpURLConnection.getResponseCode() == 200) {
                    int total = httpURLConnection.getContentLength();
                    input = httpURLConnection.getInputStream();
                    fos = new FileOutputStream(updateFile);
                    byte[] buffer = new byte[1024];
                    int len;
                    int progress = 0;
                    while((len = input.read(buffer)) != -1) {
                        fos.write(buffer, 0, len);
                        progress += len;

                        mIntent.putExtra("progress", progress);
                        mIntent.putExtra("total", total);
                        sendBroadcast(mIntent);
                    }
                    fos.flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if(fos != null) {
                        fos.close();
                    }
                    if(input != null) {
                        input.close();
                    }
                    if(httpURLConnection != null) {
                        httpURLConnection.disconnect();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
onCreate()方法中注册广播接收器

//动态注册广播接收器
updateReceiver = new UpdateProgressReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.yifeng.chaoshibang.broadcast.UPDATE_APK");
 registerReceiver(updateReceiver, intentFilter);

protected void onDestroy() {
		Intent intent = new Intent(SplashActivity.this, DownloadFileService.class);
		//停止服务
		stopService(intent);
		//注销广播
		unregisterReceiver(updateReceiver);
		super.onDestroy();
	}

然后在确定下载按钮的监听事件响应中启动service

private void showUpdateDialog() {
		
		AlertDialog.Builder builder = new AlertDialog.Builder(SplashActivity.this);
		builder.setIcon(android.R.drawable.ic_dialog_info);
		builder.setCancelable(false);

		builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
					File dir = new File(Environment.getExternalStorageDirectory(), "/chaoshibang/update");
					if(!dir.exists()) {
						dir.mkdirs();
					}
					String apkPath = Environment.getExternalStorageDirectory() + "/chaoshibang/update/new.apk";
					//启动服务
					Intent mIntent = new Intent(SplashActivity.this, DownloadFileService.class);
					mIntent.putExtra("url", info.getUrl());
					startService(mIntent);
					progressDialog.show();

				} else {
					Toast.makeText(SplashActivity.this, "SD卡不可用,请插入SD卡", Toast.LENGTH_SHORT).show();
					loadMainUI();
				}
			}
		});
		builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				loadMainUI();
			}

		});
		builder.create().show();
	}




  • 1
    点赞
  • 0
    评论
  • 3
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

jxindong

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值