【Android】Android程序自己主动更新
App自己主動更新的步驟可分為三步:
以下對這三步進(jìn)行解釋。當(dāng)中會穿插相應(yīng)代碼。App自己主動更新的這三步所有被封裝到了一個單獨的Updater類中,能夠直接拿來使用,我會在文章最后貼出源代碼github地址。
Updater 使用演示樣例
通過單一的類Updater能夠方便的實現(xiàn)自己主動檢查更新、下載安裝包和自己主動安裝。能夠監(jiān)聽下載進(jìn)度,能夠自己定義更新提示等。保存路徑能夠自由書寫,假設(shè)路徑中某個文件夾不存在會自己主動創(chuàng)建。流式API接口易于使用。以下是使用演示樣例。一行代碼搞定自己主動更新:
String savePath = Environment.getExternalStorageDirectory() + "/whinc/download/whinc.apk"; String updateUrl = "http://192.168.1.168:8000/update.xml"; Updater.with(mContext).downloadListener(mListener).update(updateUrl).save(savePath).create().checkUpdate();第一步:檢查更新
這一步須要服務(wù)端的配合。服務(wù)端存放一個XML格式的配置文件(也能夠用JSON或其它格式)提供給client檢查更新。update.xml 格式例如以下:
<?xml version="1.0" encoding="utf-8"?> <info><version><code>4</code><name>1.0.4</name></version><url>http://192.168.1.168:8000/test.apk</url><description>更新 - 吧啦吧啦;修復(fù) - 吧啦吧啦;添加 - 巴拉巴拉巴</description> </info>- <version>標(biāo)簽指定服務(wù)端的版本號號和版本號名稱,該版本號號和版本號名稱相應(yīng)Android項目配置里的versionCode和versionName(Eclipse ADT項目可在 AndroidManifest.xml中的標(biāo)簽中找到。Android Studio項目在module的build.gradle中的defaultConfig中找到)。
- <url>標(biāo)簽指定APK的下載地址,
- <description>標(biāo)簽指定更新內(nèi)容。
client通過 HTTP 請求服務(wù)端的 update.xml文件。然后解析 update.xml,比較服務(wù)端的版本號號與本地版本號號,假設(shè)服務(wù)端版本號號大于本地版本號號說明有更新,則依據(jù) update.xml中指定的APK下載地址下載最新的APK,以下將會具體說明。
以下是檢查更新的代碼:
/*** 檢查 App 版本號號** @return 假設(shè)有新版本號返回true。否則返回false*/private boolean checkVersion() {URL url;HttpURLConnection httpConn = null;try {url = new URL(mCheckUpdateUrl);httpConn = (HttpURLConnection) url.openConnection();httpConn.setConnectTimeout(200000);httpConn.setReadTimeout(200000);httpConn.setUseCaches(false); // disable cache for current http connectionhttpConn.connect();if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {InputStream inputStream = httpConn.getInputStream();// 解析 XML 數(shù)據(jù)if (!parseXml(inputStream)) {return false;}// 比較本地版本號號與服務(wù)器版本號號PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);if (packageInfo.versionCode < mRemoteVersionCode) {return true;}} else {return false;}} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();} finally {httpConn.disconnect();}return false;}首先創(chuàng)建HTTPURLConnection訪問服務(wù)端update.xml文件,然后解析服務(wù)端返回的update.xml文件,并保存版本號信息、APK下載地址和更新日志。解析完后通過獲取當(dāng)前client的版本號號與服務(wù)端版本號號比較。假設(shè)服務(wù)端版本號號更大,說明服務(wù)端有更新的版本號。checkVersion() 方法返回true,否則返回false。
以下時檢查更新的代碼。須要注意的是。Android中不同意在主線程(UI線程)中發(fā)起網(wǎng)絡(luò)請求,所以checkVersion()的調(diào)用須要放在非主線程中。實現(xiàn)異步請求的方式有多種,這里我使用 AsyncTask。
public void checkUpdate() {new AsyncTask<Void, Void, Boolean>() {@Overrideprotected Boolean doInBackground(Void... params) {boolean hasNewVersion = checkVersion();return hasNewVersion;}@Overrideprotected void onPostExecute(Boolean hasNewVersion) {super.onPostExecute(hasNewVersion);if (mCheckUpdateListener == null|| !mCheckUpdateListener.onCompleted(hasNewVersion, mRemoteVersionCode,mRemoteVersionName, mUpdateLog, mApkDownloadUrl)) {if (hasNewVersion) {showUpdateDialog();}}}}.execute();}下載新版的APK安裝包
showUpdateDialog()調(diào)用后顯示更新提示對話框,在對話框確認(rèn)button點擊事件中,首先創(chuàng)建DownloadManager.Request對象,然后設(shè)置該對象的各種屬性例如以下載保存路徑、通知欄標(biāo)題等,最后將該下載請求放到系統(tǒng)服務(wù)DownloadManager的下載隊列中。交給系統(tǒng)去處理下載邏輯。 為了監(jiān)聽下載完畢事件,代碼里注冊了廣播DownloadManager.ACTION_DOWNLOAD_COMPLETE。下載進(jìn)度通過注冊ContentObserver來監(jiān)聽。
/*** 顯示更新對話框*/private void showUpdateDialog() {AlertDialog.Builder builder = new AlertDialog.Builder(mContext);builder.setTitle(mTitle);builder.setMessage(mUpdateLog);builder.setPositiveButton(mDialogOkBtnTxt, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();// 后臺下載mDownloadMgr = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);DownloadManager.Request request = new DownloadManager.Request(Uri.parse(mApkDownloadUrl));if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {// 假設(shè)保存路徑包括子文件夾,須要先遞歸創(chuàng)建文件夾if (!createDirIfAbsent(mSavePath)) {Log.e("TAG", "apk save path can not be created:" + mSavePath);return;}request.setDestinationUri(Uri.fromFile(new File(mSavePath)));request.setTitle(mNotificationTitle);request.setTitle(mNotificationMessage);// 注冊廣播,監(jiān)聽下載完畢事件mContext.registerReceiver(mCompleteReceiver,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));// 注冊監(jiān)聽下載進(jìn)度mContext.getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"),true, mContentObserver);mDownloadId = mDownloadMgr.enqueue(request);} else {Log.e("TAG", "can not access external storage!");return;}Toast.makeText(mContext, "正在后臺下載...", Toast.LENGTH_SHORT).show();}});builder.setNegativeButton(mDialogCancelBtnTxt, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.cancel();}});builder.create().show();}/*** 假設(shè)參數(shù) path 指定的路徑中的文件夾不存在就創(chuàng)建指定文件夾** @param path 絕對路徑(包括文件名稱,比如 '/sdcard/storage/download/test.apk')* @return 假設(shè)成功創(chuàng)建文件夾返回true,否則返回false*/private boolean createDirIfAbsent(String path) {String[] array = path.trim().split(File.separator);List<String> dirNames = Arrays.asList(array).subList(1, array.length - 1);StringBuilder pathBuilder = new StringBuilder(File.separator);for (String d : dirNames) {pathBuilder.append(d);File f = new File(pathBuilder.toString());if (!f.exists() && !f.mkdir()) {return false;}pathBuilder.append(File.separator);}return true;}安裝APK
一旦Apk下載完畢就會收到廣播消息,此時能夠運行安裝APK的動作,只是要先通過下載Id推斷該廣播事件是否是由于我們的APK下載完畢發(fā)出的,由于系統(tǒng)可能同一時候有多個下載任務(wù),通過下載id區(qū)分。
mCompleteReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);if (downloadId == mDownloadId) {installApk();release();}}};以下是 installApk() 方法,首先通過下載Id從DownloadManager中檢索到下載的APK存儲路徑,然后通過Intent安裝下載的APK,代碼很easy。注意,Intent設(shè)置標(biāo)識為Intent.FLAG_ACTIVITY_NEW_TASK。否則不能正常啟動安裝程序。
/*** 替換安裝當(dāng)前App。注意:簽名一致*/private void installApk() {// 獲取下載的 APK 地址Uri apkUri = mDownloadMgr.getUriForDownloadedFile(mDownloadId);Intent intent = new Intent(Intent.ACTION_VIEW);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setDataAndType(apkUri, "application/vnd.android.package-archive");mContext.startActivity(intent);}github 源代碼
whinc/Android-UpdateManager
比較好的參考資料:
DownloadManager | Android Developers
Android系統(tǒng)下載管理DownloadManager功能介紹及使用演示樣例
總結(jié)
以上是生活随笔為你收集整理的【Android】Android程序自己主动更新的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【POJ 2485】 Highways
- 下一篇: Android图像变化