版本更新說明
這裏有調用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;
}
}
};
}