Android App自动更新之通知栏下载 Android App自动更新之通知栏下载
云涛连雾 人气:0版本更新说明
这里有调用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; } } }; }
加载全部内容