【Android】Android程式自己主動更新

來源:互聯網
上載者:User

標籤:connect   圖片   func   response   ret   exist   ora   current   sdn   

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

  1. 檢查更新(假設有更新進行第2步,否則返回)
  2. 下載新版的APK安裝包
  3. 安裝APK

以下對這三步進行解釋。當中會穿插相應代碼。App自己主動更新的這三步所有被封裝到了一個單獨的Updater類中,能夠直接拿來使用,我會在文章最後貼出原始碼github地址。

Updater 使用示範範例

通過單一的類Updater能夠方便的實現自己主動檢查更新、下載安裝包和自己主動安裝。能夠監聽下載進度,能夠自己定義更新提示等。儲存路徑能夠自由書寫,假設路徑中某個檔案夾不存在會自己主動建立。流式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();

第一步:檢查更新

這一步須要服務端的配合。服務端存放一個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>更新 - 吧啦吧啦;修複 - 吧啦吧啦;添加 - 巴拉巴拉巴</description></info>
  • <version>標籤指定服務端的版本號碼號和版本號碼名稱,該版本號碼號和版本號碼名稱相應Android項目配置裡的versionCodeversionName(Eclipse ADT項目可在 AndroidManifest.xml中的標籤中找到。Android Studio項目在module的build.gradle中的defaultConfig中找到)。
  • <url>標籤指定APK的,
  • <description>標籤指定更新內容。

client通過 HTTP 要求服務端的 update.xml檔案。然後解析 update.xml,比較服務端的版本號碼號與本地版本號碼號,假設服務端版本號碼號大於本地版本號碼號說明有更新,則依據 update.xml中指定的APK下載最新的APK,以下將會具體說明。

以下是檢查更新的代碼:

    /**     * 檢查 App 版本號碼號     *     * @return 假設有新版本號碼返回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 connection            httpConn.connect();            if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {                InputStream inputStream = httpConn.getInputStream();                // 解析 XML 資料                if (!parseXml(inputStream)) {                    return false;                }                // 比較本地版本號碼號與伺服器版本號碼號                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;    }

首先建立HTTPURLConnection訪問服務端update.xml檔案,然後解析服務端返回的update.xml檔案,並儲存版本號碼資訊、APK和更新日誌。解析完後通過擷取當前client的版本號碼號與服務端版本號碼號比較。假設服務端版本號碼號更大,說明服務端有更新的版本號碼。checkVersion() 方法返回true,否則返回false。

以下時檢查更新的代碼。須要注意的是。Android中不同意在主線程(UI線程)中發起網路請求,所以checkVersion()的調用須要放在非主線程中。實現非同步請求的方式有多種,這裡我使用 AsyncTask。

    public void checkUpdate() {        new AsyncTask<Void, Void, Boolean>() {            @Override            protected Boolean doInBackground(Void... params) {                boolean hasNewVersion = checkVersion();                return hasNewVersion;            }            @Override            protected void onPostExecute(Boolean hasNewVersion) {                super.onPostExecute(hasNewVersion);                if (mCheckUpdateListener == null                        || !mCheckUpdateListener.onCompleted(hasNewVersion, mRemoteVersionCode,                        mRemoteVersionName, mUpdateLog, mApkDownloadUrl)) {                    if (hasNewVersion) {                        showUpdateDialog();                    }                }            }        }.execute();    }
下載新版的APK安裝包

showUpdateDialog()調用後顯示更新提示對話方塊,在對話方塊確認button點擊事件中,首先建立DownloadManager.Request對象,然後設定該對象的各種屬性例如以下載儲存路徑、通知欄標題等,最後將該下載請求放到系統服務DownloadManager的下載隊列中。交給系統去處理下載邏輯。 為了監聽下載完畢事件,代碼裡注冊了廣播DownloadManager.ACTION_DOWNLOAD_COMPLETE。下載進度通過注冊ContentObserver來監聽。

    /**     * 顯示更新對話方塊     */    private void showUpdateDialog() {        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);        builder.setTitle(mTitle);        builder.setMessage(mUpdateLog);        builder.setPositiveButton(mDialogOkBtnTxt, new DialogInterface.OnClickListener() {            @Override            public 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)) {                    // 假設儲存路徑包括子檔案夾,須要先遞迴建立檔案夾                    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);                    // 注冊廣播,監聽下載完畢事件                    mContext.registerReceiver(mCompleteReceiver,                            new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));                    // 注冊監聽下載進度                    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() {            @Override            public void onClick(DialogInterface dialog, int which) {                dialog.cancel();            }        });        builder.create().show();    }    /**     * 假設參數 path 指定的路徑中的檔案夾不存在就建立指定檔案夾     *     * @param path 絕對路徑(包括檔案名稱,比如 ‘/sdcard/storage/download/test.apk‘)     * @return 假設成功建立檔案夾返回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下載完畢發出的,由於系統可能同一時候有多個下載任務,通過下載id區分。

        mCompleteReceiver = new BroadcastReceiver() {            @Override            public 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設定標識為Intent.FLAG_ACTIVITY_NEW_TASK。否則不能正常啟動安裝程式。

    /**     * 替換安裝當前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系統下載管理DownloadManager功能介紹及使用示範範例

【Android】Android程式自己主動更新

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.