【Android】App自动更新之通知栏下载

本文介绍了一种安卓应用的自动更新机制实现方案,包括检查新版本、下载安装包并在通知栏显示进度等功能。通过UpdateManager类进行版本检查,使用UpdateService进行后台下载并更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

版本更新说明

这里有调用UpdateService启动服务检查下载安装包等 

1. 文件下载,下完后写入到sdcard 

2. 如何在通知栏上显示下载进度

3. 下载完毕自动安装 

4. 如何判断是否有新版本

版本更新的主类

package com.wei.update;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import com.wei.util.MyApplication;


import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Handler;

/**
 * 版本更新主类,这里有调用UpdateService启动服务检查下载安装包等 1. 文件下载,下完后写入到sdcard 2. 如何在通知栏上显示下载进度
 * 3. 下载完毕自动安装 4. 如何判断是否有新版本
 * 
 * @author david
 */
public class UpdateManager {
	private static String packageName;// = "com.yipinzhe"; // 应用的包名
	private static String jsonUrl = "version.txt"; // JSON版本文件URL
	private static String xmlUrl = "version.xml"; // XML版本文件URL
	private static final String DOWNLOAD_DIR = "/"; // 应用下载后保存的子目录

	private Context mContext;
	HashMap<String, String> mHashMap;// 保存解析的XML信息
	int versionCode, isNew;

	public UpdateManager(Context context) {
		this.mContext = context;
		packageName = context.getPackageName();
		jsonUrl = MyApplication.site + jsonUrl;
		xmlUrl = MyApplication.site + xmlUrl;
		checkVersion();
	}

	Handler checkHandler = new Handler() {
		@Override
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 1) {
				// 发现新版本,提示用户更新
				StringBuffer message = new StringBuffer();
				message.append(mHashMap.get("note").replace("|", "\n"));
				AlertDialog.Builder alert = new AlertDialog.Builder(mContext);
				alert.setTitle("软件升级")
						.setMessage(message.toString())
						.setPositiveButton("更新",
								new DialogInterface.OnClickListener() {
									@Override
									public void onClick(DialogInterface dialog,
											int which) {
										// 开启更新服务UpdateService
										System.out.println("你点击了更新");
										Intent updateIntent = new Intent(
												mContext, UpdateService.class);
										/*
										 * updateIntent.putExtra("downloadDir",
										 * DOWNLOAD_DIR);
										 * updateIntent.putExtra("apkUrl",
										 * mHashMap.get("url"));
										 */
										mContext.startService(updateIntent);
									}
								})
						.setNegativeButton("取消",
								new DialogInterface.OnClickListener() {
									@Override
									public void onClick(DialogInterface dialog,
											int which) {
										dialog.dismiss();
									}
								});
				alert.create().show();
			}
		};
	};

	/** 检查是否有新版本 */
	public void checkVersion() {
		try {
			// 获取软件版本号,对应AndroidManifest.xml下android:versionCode
			versionCode = mContext.getPackageManager().getPackageInfo(
					packageName, 0).versionCode;
		} catch (NameNotFoundException e) {
			e.printStackTrace();
		}

		new Thread() {
			@Override
			public void run() {
				String result = null;
				/*
				 * try { //如果服务器端是JSON文本文件 result =
				 * MyApplication.handleGet(jsonUrl); if (result != null) {
				 * mHashMap = parseJSON(result); } } catch (Exception e1) {
				 * e1.printStackTrace(); }
				 */

				InputStream inStream = null;
				try {
					// 本机XML文件
					 inStream =  UpdateManager.class.getClassLoader().getResourceAsStream("version.xml");
					// 如果服务器端是XML文件
					inStream = new URL(xmlUrl).openConnection().getInputStream();
					if (inStream != null)
						mHashMap = parseXml(inStream);
				} catch (Exception e1) {
					e1.printStackTrace();
				}
				if (mHashMap != null) {
					int serviceCode = Integer.valueOf(mHashMap.get("version"));
					if (serviceCode > versionCode) {// 版本判断,返回true则有新版本
						isNew = 1;
					}
				}
				checkHandler.sendEmptyMessage(isNew);
			};
		}.start();
	}

	/** 解析服务器端的JSON版本文件 */
	public HashMap<String, String> parseJSON(String str) {
		HashMap<String, String> hashMap = new HashMap<String, String>();
		try {
			JSONObject obj = new JSONObject(str);
			hashMap.put("version", obj.getString("version"));
			hashMap.put("name", obj.getString("name"));
			hashMap.put("url", obj.getString("url"));
			hashMap.put("note", obj.getString("note"));
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return hashMap;
	}

	/** 解析服务器端的XML版本文件 */
	public HashMap<String, String> parseXml(InputStream inputStream) {
		HashMap<String, String> hashMap = new HashMap<String, String>();
		try {
			XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
			parser.setInput(inputStream, "GBK");//设置数据源编码
			int eventCode = parser.getEventType();//获取事件类型
			while(eventCode != XmlPullParser.END_DOCUMENT) {
				System.out.println("循环开始");
				switch (eventCode){
					case XmlPullParser.START_DOCUMENT: //开始读取XML文档  
					System.out.println("START_DOCUMENT");
					break;
					case XmlPullParser.START_TAG://开始读取某个标签
						if("version".equals(parser.getName())) {
							hashMap.put(parser.getName(), parser.nextText());
						} else if("name".equals(parser.getName())) {   
							hashMap.put(parser.getName(), parser.nextText());
						} else if("url".equals(parser.getName())) {   
							hashMap.put(parser.getName(), parser.nextText());
						} else if("note".equals(parser.getName())) {   
							hashMap.put(parser.getName(), parser.nextText());
						}
					break;
				    case XmlPullParser.END_TAG:
				    break;
				}
			   eventCode = parser.next();//继续读取下一个元素节点,并获取事件码
			    
			}
			System.out.println(hashMap.get("version"));
		} catch(Exception e) {
			
		}
		return hashMap;	
		

		/*try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document document = builder.parse(inStream);
			Element root = document.getDocumentElement();//获取根节点
			NodeList childNodes = root.getChildNodes();//获得所有子节点,然后遍历
			for (int j = 0; j < childNodes.getLength(); j++) {
				Node childNode = childNodes.item(j);
				if (childNode.getNodeType() == Node.ELEMENT_NODE) {
					Element childElement = (Element) childNode;
					if ("version".equals(childElement.getNodeName())) {
						hashMap.put("version", childElement.getFirstChild()
								.getNodeValue());
					}
					else if (("name".equals(childElement.getNodeName()))) {
						hashMap.put("name", childElement.getFirstChild()
								.getNodeValue());
					}
					else if (("url".equals(childElement.getNodeName()))) {
						hashMap.put("url", childElement.getFirstChild()
								.getNodeValue());
					} else if (("note".equals(childElement.getNodeName()))) {
						hashMap.put("note", childElement.getFirstChild()
								.getNodeValue());
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}*/
		
	}
}

版本更新的服务类

package com.wei.update;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import com.wei.util.MyApplication;
import com.wei.wotao.R;

//import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.View;
import android.widget.RemoteViews;

/**
 * 下载安装包的服务类
 * @author david
 */

public class UpdateService extends Service {

	// 文件存储
	private File saveDir;
	private File saveFile;
	private String apkUrl;
	
	// 通知栏
	private NotificationManager updateNotificationManager = null;
	private Notification updateNotification = null;
	
	// 通知栏跳转Intent
	private Intent updateIntent = null;
	private PendingIntent updatePendingIntent = null;

	// 下载状态
	private final static int DOWNLOAD_COMPLETE = 0;
	private final static int DOWNLOAD_FAIL = 1;
	
	private RemoteViews contentView;

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		System.out.println("onStartCommand");
		contentView = new RemoteViews(getPackageName(), R.layout.activity_app_update);
		// 获取传值
		String downloadDir = intent.getStringExtra("downloadDir");	
		apkUrl = MyApplication.site+intent.getStringExtra("apkUrl");
		// 如果有SD卡,则创建APK文件
		if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment
				.getExternalStorageState())) {
			
			saveDir = new File(Environment.getExternalStorageDirectory(),
					downloadDir);
			saveFile = new File(saveDir.getPath(), getResources()
					.getString(R.string.app_name) + ".apk");
		}

		this.updateNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		this.updateNotification = new Notification();

		// 设置下载过程中,点击通知栏,回到主界面
		updateIntent = new Intent();
		updatePendingIntent = PendingIntent.getActivity(this, 0, updateIntent, 0);
		// 设置通知栏显示内容
		updateNotification.icon = R.drawable.icon_info;
		updateNotification.tickerText = "开始下载";
		updateNotification.contentView.setProgressBar(R.id.progressBar1, 100, 0, true);
		updateNotification.setLatestEventInfo(this,
				getResources().getString(R.string.app_name), "0%",
				updatePendingIntent);
		// 发出通知
		updateNotificationManager.notify(0, updateNotification);
		new Thread(new DownloadThread()).start();
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	/** 下载的线程 */
	private class DownloadThread implements Runnable {
		Message message = updateHandler.obtainMessage();

		public void run() {
			message.what = DOWNLOAD_COMPLETE;
			if (saveDir!=null && !saveDir.exists()) {
				saveDir.mkdirs();
			}
			if (saveFile!=null && !saveFile.exists()) {
				try {
					saveFile.createNewFile();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			try {
				long downloadSize = downloadFile(apkUrl, saveFile);
				if (downloadSize > 0) {// 下载成功
					updateHandler.sendMessage(message);
				}
			} catch (Exception ex) {
				ex.printStackTrace();
				message.what = DOWNLOAD_FAIL;		
				updateHandler.sendMessage(message);// 下载失败
			}
		}

		public long downloadFile(String downloadUrl, File saveFile)
				throws Exception {
			int downloadCount = 0;
			int currentSize = 0;
			long totalSize = 0;
			int updateTotalSize = 0;
			int rate = 0;// 下载完成比例

			HttpURLConnection httpConnection = null;
			InputStream is = null;
			FileOutputStream fos = null;

			try {
				URL url = new URL(downloadUrl);
				httpConnection = (HttpURLConnection) url.openConnection();
				httpConnection.setRequestProperty("User-Agent",
						"PacificHttpClient");
				if (currentSize > 0) {
					httpConnection.setRequestProperty("RANGE", "bytes="
							+ currentSize + "-");
				}
				httpConnection.setConnectTimeout(200000);
				httpConnection.setReadTimeout(200000);
				updateTotalSize = httpConnection.getContentLength();//获取文件大小
				if (httpConnection.getResponseCode() == 404) {
					throw new Exception("fail!");
				}
				is = httpConnection.getInputStream();
				fos = new FileOutputStream(saveFile, false);
				byte buffer[] = new byte[1024 * 1024 * 3];
				int readsize = 0;
				while ((readsize = is.read(buffer)) != -1) {
					fos.write(buffer, 0, readsize);
					
					totalSize += readsize;//已经下载的字节数
					rate = (int) (totalSize * 100 / updateTotalSize);//当前下载进度
					// 为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次
					if ((downloadCount == 0) || rate - 0 > downloadCount) {
						downloadCount += 1;
						updateNotification.setLatestEventInfo(
								UpdateService.this, "正在下载", rate + "%",
								updatePendingIntent);//设置通知的内容、标题等
						updateNotification.contentView.setProgressBar(R.id.progressBar1, 100, rate, true);
						updateNotificationManager.notify(0, updateNotification);//把通知发布出去
					}
					
					
					
				}
			} finally {
				if (httpConnection != null) {
					httpConnection.disconnect();
				}
				if (is != null) {
					is.close();
				}
				if (fos != null) {
					fos.close();
				}
			}
			return totalSize;
		}
	}

	private Handler updateHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case DOWNLOAD_COMPLETE:
				//当下载完毕,自动安装APK(ps,打电话 发短信的启动界面工作)
				Uri uri = Uri.fromFile(saveFile);//根据File获得安装包的资源定位符
				Intent installIntent = new Intent(Intent.ACTION_VIEW);//设置Action
				installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//新的Activity会在一个新任务打开,而不是在原先的任务栈
				installIntent.setDataAndType(uri, "application/vnd.android.package-archive");//设置URI的数据类型
				startActivity(installIntent);//把打包的Intent传递给startActivity
				
				//当下载完毕,更新通知栏,且当点击通知栏时,安装APK
				updatePendingIntent = PendingIntent.getActivity(UpdateService.this, 0, installIntent, 0);
				updateNotification.defaults = Notification.DEFAULT_SOUND;// 铃声提醒
				updateNotification.setLatestEventInfo(UpdateService.this, getResources().getString(R.string.app_name),
						"下载完成,点击安装", updatePendingIntent);
				updateNotificationManager.notify(0, updateNotification);

				// 停止服务
				stopService(updateIntent);
				break;
			case DOWNLOAD_FAIL:
				// 下载失败
				updateNotification.setLatestEventInfo(UpdateService.this,
						getResources().getString(R.string.app_name),
						"下载失败,网络连接超时", updatePendingIntent);
				updateNotificationManager.notify(0, updateNotification);
				break;
			default:
				stopService(updateIntent);
				break;
			}
		}
	};
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值