【Android】App自动更新之通知栏下载
16lz
2021-01-26
版本更新说明
这里有调用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版本文件URLprivate static String xmlUrl = "version.xml"; // XML版本文件URLprivate 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() {@Overridepublic 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() {@Overridepublic void onClick(DialogInterface dialog,int which) {// 开启更新服务UpdateServiceSystem.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() {@Overridepublic void onClick(DialogInterface dialog,int which) {dialog.dismiss();}});alert.create().show();}};};/** 检查是否有新版本 */public void checkVersion() {try {// 获取软件版本号,对应AndroidManifest.xml下android:versionCodeversionCode = mContext.getPackageManager().getPackageInfo(packageName, 0).versionCode;} catch (NameNotFoundException e) {e.printStackTrace();}new Thread() {@Overridepublic 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;// 通知栏跳转Intentprivate Intent updateIntent = null;private PendingIntent updatePendingIntent = null;// 下载状态private final static int DOWNLOAD_COMPLETE = 0;private final static int DOWNLOAD_FAIL = 1;private RemoteViews contentView;@Overridepublic 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);}@Overridepublic 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() {@Overridepublic 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);//设置ActioninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//新的Activity会在一个新任务打开,而不是在原先的任务栈installIntent.setDataAndType(uri, "application/vnd.android.package-archive");//设置URI的数据类型startActivity(installIntent);//把打包的Intent传递给startActivity//当下载完毕,更新通知栏,且当点击通知栏时,安装APKupdatePendingIntent = 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;}}};}
更多相关文章
- Android(安卓)Studio 集成NDK 报错Error:No toolchains found in
- ADB源码分析(一)
- MAC操作系统上搭建Android开发平台环境
- Android(安卓)SDK下载安装及配置教程
- Android设置通知Notification
- android+eclipse+phonegap1.7(cordova)配置项目 .
- Android(安卓)Design Support Library使用示例(一)
- Android学习笔记10——Android的调试
- AndroidManifest.xml 文件里面的内容介绍