Android App自動(dòng)更新之通知欄下載
本文實(shí)例為大家分享了Android App自動(dòng)更新通知欄下載的具體代碼,供大家參考,具體內(nèi)容如下
版本更新說明
這里有調(diào)用UpdateService啟動(dòng)服務(wù)檢查下載安裝包等
1. 文件下載,下完后寫入到sdcard
2. 如何在通知欄上顯示下載進(jìn)度
3. 下載完畢自動(dòng)安裝
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; /** * 版本更新主類,這里有調(diào)用UpdateService啟動(dòng)服務(wù)檢查下載安裝包等 1. 文件下載,下完后寫入到sdcard 2. 如何在通知欄上顯示下載進(jìn)度 * 3. 下載完畢自動(dòng)安裝 4. 如何判斷是否有新版本 * * @author david */ public class UpdateManager { private static String packageName;// = "com.yipinzhe"; // 應(yīng)用的包名 private static String jsonUrl = "version.txt"; // JSON版本文件URL private static String xmlUrl = "version.xml"; // XML版本文件URL private static final String DOWNLOAD_DIR = "/"; // 應(yīng)用下載后保存的子目錄 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) { // 發(fā)現(xiàn)新版本,提示用戶更新 StringBuffer message = new StringBuffer(); message.append(mHashMap.get("note").replace("|", "\n")); AlertDialog.Builder alert = new AlertDialog.Builder(mContext); alert.setTitle("軟件升級(jí)") .setMessage(message.toString()) .setPositiveButton("更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 開啟更新服務(wù)UpdateService System.out.println("你點(diǎn)擊了更新"); 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 { // 獲取軟件版本號(hào),對(duì)應(yīng)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 { //如果服務(wù)器端是JSON文本文件 result = * MyApplication.handleGet(jsonUrl); if (result != null) { * mHashMap = parseJSON(result); } } catch (Exception e1) { * e1.printStackTrace(); } */ InputStream inStream = null; try { // 本機(jī)XML文件 inStream = UpdateManager.class.getClassLoader().getResourceAsStream("version.xml"); // 如果服務(wù)器端是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(); } /** *解析服務(wù)器端的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; } /** *解析服務(wù)器端的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");//設(shè)置數(shù)據(jù)源編碼 int eventCode = parser.getEventType();//獲取事件類型 while(eventCode != XmlPullParser.END_DOCUMENT) { System.out.println("循環(huán)開始"); switch (eventCode){ case XmlPullParser.START_DOCUMENT: //開始讀取XML文檔 System.out.println("START_DOCUMENT"); break; case XmlPullParser.START_TAG://開始讀取某個(gè)標(biāo)簽 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();//繼續(xù)讀取下一個(gè)元素節(jié)點(diǎn),并獲取事件碼 } 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();//獲取根節(jié)點(diǎn) NodeList childNodes = root.getChildNodes();//獲得所有子節(jié)點(diǎn),然后遍歷 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(); }*/ } }
版本更新的服務(wù)類
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; /** * 下載安裝包的服務(wù)類 * @author david */ public class UpdateService extends Service { // 文件存儲(chǔ) private File saveDir; private File saveFile; private String apkUrl; // 通知欄 private NotificationManager updateNotificationManager = null; private Notification updateNotification = null; // 通知欄跳轉(zhuǎn)Intent private Intent updateIntent = null; private PendingIntent updatePendingIntent = null; // 下載狀態(tài) 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卡,則創(chuàng)建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(); // 設(shè)置下載過程中,點(diǎn)擊通知欄,回到主界面 updateIntent = new Intent(); updatePendingIntent = PendingIntent.getActivity(this, 0, updateIntent, 0); // 設(shè)置通知欄顯示內(nèi)容 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); // 發(fā)出通知 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;//已經(jīng)下載的字節(jié)數(shù) rate = (int) (totalSize * 100 / updateTotalSize);//當(dāng)前下載進(jìn)度 // 為了防止頻繁的通知導(dǎo)致應(yīng)用吃緊,百分比增加10才通知一次 if ((downloadCount == 0) || rate - 0 > downloadCount) { downloadCount += 1; updateNotification.setLatestEventInfo( UpdateService.this, "正在下載", rate + "%", updatePendingIntent);//設(shè)置通知的內(nèi)容、標(biāo)題等 updateNotification.contentView.setProgressBar(R.id.progressBar1, 100, rate, true); updateNotificationManager.notify(0, updateNotification);//把通知發(fā)布出去 } } } 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: //當(dāng)下載完畢,自動(dòng)安裝APK(ps,打電話 發(fā)短信的啟動(dòng)界面工作) Uri uri = Uri.fromFile(saveFile);//根據(jù)File獲得安裝包的資源定位符 Intent installIntent = new Intent(Intent.ACTION_VIEW);//設(shè)置Action installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//新的Activity會(huì)在一個(gè)新任務(wù)打開,而不是在原先的任務(wù)棧 installIntent.setDataAndType(uri, "application/vnd.android.package-archive");//設(shè)置URI的數(shù)據(jù)類型 startActivity(installIntent);//把打包的Intent傳遞給startActivity //當(dāng)下載完畢,更新通知欄,且當(dāng)點(diǎn)擊通知欄時(shí),安裝APK updatePendingIntent = PendingIntent.getActivity(UpdateService.this, 0, installIntent, 0); updateNotification.defaults = Notification.DEFAULT_SOUND;// 鈴聲提醒 updateNotification.setLatestEventInfo(UpdateService.this, getResources().getString(R.string.app_name), "下載完成,點(diǎn)擊安裝", updatePendingIntent); updateNotificationManager.notify(0, updateNotification); // 停止服務(wù) stopService(updateIntent); break; case DOWNLOAD_FAIL: // 下載失敗 updateNotification.setLatestEventInfo(UpdateService.this, getResources().getString(R.string.app_name), "下載失敗,網(wǎng)絡(luò)連接超時(shí)", updatePendingIntent); updateNotificationManager.notify(0, updateNotification); break; default: stopService(updateIntent); break; } } }; }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android中@id和@+id及@android:id的區(qū)別介紹
這篇文章主要給大家介紹了關(guān)于Android中@id和@+id及@android:id的區(qū)別的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Android 錄制手機(jī)屏幕視頻生成GIF圖片實(shí)例詳解
這篇文章主要介紹了Android 錄制手機(jī)屏幕視頻生成GIF圖片實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03Android 觸摸事件監(jiān)聽(Activity層,ViewGroup層,View層)詳細(xì)介紹
這篇文章主要介紹了Android 觸摸事件監(jiān)聽(Activity層,ViewGroup層,View層)詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2016-12-12如何利用Android Studio將moudle變成jar示例詳解
這篇文章主要給大家介紹了關(guān)于如何利用Android Studio將moudle變成jar的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來跟著小編一起學(xué)習(xí)學(xué)習(xí)吧。2017-08-08Flutter加載圖片流程之ImageProvider源碼示例解析
這篇文章主要為大家介紹了Flutter加載圖片流程之ImageProvider源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04關(guān)于Fragment?already?added問題的解決方案
這篇文章主要介紹了關(guān)于Fragment?already?added問題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10Android實(shí)現(xiàn)Tab布局的4種方式(Fragment+TabPageIndicator+ViewPager)
Android現(xiàn)在實(shí)現(xiàn)Tab類型的界面方式越來越多,本文詳細(xì)介紹了Android實(shí)現(xiàn)Tab布局的4種方式,具有一定的參考價(jià)值,有興趣的可以了解一下。2016-11-11Android Handler的postDelayed()關(guān)閉的方法及遇到問題
這篇文章主要介紹了Android Handler的postDelayed()關(guān)閉的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04