日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

【Android】Android程序自己主动更新

發(fā)布時間:2025/3/20 Android 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Android】Android程序自己主动更新 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

App自己主動更新的步驟可分為三步:

  • 檢查更新(假設(shè)有更新進(jìn)行第2步,否則返回)
  • 下載新版的APK安裝包
  • 安裝APK
  • 以下對這三步進(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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。