1. 程式人生 > >Android應用更新-自動檢測版本及自動升級

Android應用更新-自動檢測版本及自動升級

步驟:

  • 1.檢測當前版本的資訊AndroidManifest.xml–>manifest–>[Android]

  • 2.從伺服器獲取版本號(版本號存在於xml檔案中)並與當前檢測到的版本進行匹配,如果不匹配,提示使用者進行升級,如果匹配則進入程式主介面。(demo中假設需要更新)

  • 3.當提示使用者進行版本升級時,如果使用者點選了“更新”,系統將自動從伺服器上下載安裝包並進行自動升級,如果點選取消將進入程式主介面。

效果圖如下:

更新
下載1

下載2

安裝

下面介紹一下程式碼的實現:

  • 1.獲取應用的當前版本號,我是封裝了一個工具類來獲取
 // 獲取本版本號,是否更新
        int
vision = Tools.getVersion(this);

獲取當前版本號工具類:


public class Tools {
    /**
     * 檢查是否存在SDCard
     *
     * @return
     */
    public static boolean hasSdcard() {
        String state = Environment.getExternalStorageState();
        if (state.equals(Environment.MEDIA_MOUNTED)) {
            return
true; } else { return false; } } /** * 2 * 獲取版本號 3 * @return 當前應用的版本號 4 */ public static int getVersion(Context context) { try { PackageManager manager = context.getPackageManager(); PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0
); String version = info.versionName; int versioncode = info.versionCode; return versioncode; } catch (Exception e) { e.printStackTrace(); } return 0; } }
  • 2.獲取伺服器版本號,是否要更新(此處就是簡單的網路請求拿到需要的資料即可,我是寫了固定值)
 // 獲取更新版本號
    private void getVersion(final int vision) {
//         {"data":{"content":"其他bug修復。","id":"2","api_key":"android",
//         // "version":"2.1"},"msg":"獲取成功","status":1}
        String data = "";
        //網路請求獲取當前版本號和下載連結
        //實際操作是從伺服器獲取
        //demo寫死了

        String newversion = "2.1";//更新新的版本號
        String content = "\n" +
                "就不告訴你我們更新了什麼-。-\n" +
                "\n" +
                "----------萬能的分割線-----------\n" +
                "\n" +
                "(ㄒoㄒ) 被老闆打了一頓,還是來告訴你吧:\n" +

                "1.下架商品誤買了?恩。。。我搞了點小動作就不會出現了\n" +
                "2.側邊欄、彈框優化 —— 這個你自己去探索吧,總得留點懸念嘛-。-\n";//更新內容
        String url = "http://openbox.mobilem.360.cn/index/d/sid/3429345";//安裝包下載地址

        double newversioncode = Double
                .parseDouble(newversion);
        int cc = (int) (newversioncode);

        System.out.println(newversion + "v" + vision + ",,"
                + cc);
        if (cc != vision) {
            if (vision < cc) {
                System.out.println(newversion + "v"
                        + vision);
                // 版本號不同
                ShowDialog(vision, newversion, content, url);
            }
        }
    }
  • 3.接下來就是下載檔案了
    (1) 顯示下載
    此處用的是自定義按鈕:
 /**
     * 升級系統
     *
     * @param content
     * @param url
     */
    private void ShowDialog(int vision, String newversion, String content,
                            final String url) {
        final MaterialDialog dialog = new MaterialDialog(this);
        dialog.content(content).btnText("取消", "更新").title("版本更新 ")
                .titleTextSize(15f).show();
        dialog.setCanceledOnTouchOutside(false);
        dialog.setOnBtnClickL(new OnBtnClickL() {// left btn click listener
            @Override
            public void onBtnClick() {
                dialog.dismiss();
            }
        }, new OnBtnClickL() {// right btn click listener

            @Override
            public void onBtnClick() {
                dialog.dismiss();
                // pBar = new ProgressDialog(MainActivity.this,
                // R.style.dialog);
                pBar = new CommonProgressDialog(MainActivity.this);
                pBar.setCanceledOnTouchOutside(false);
                pBar.setTitle("正在下載");
                pBar.setCustomTitle(LayoutInflater.from(
                        MainActivity.this).inflate(
                        R.layout.title_dialog, null));
                pBar.setMessage("正在下載");
                pBar.setIndeterminate(true);
                pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                pBar.setCancelable(true);
                // downFile(URLData.DOWNLOAD_URL);
                final DownloadTask downloadTask = new DownloadTask(
                        MainActivity.this);
                downloadTask.execute(url);
                pBar.setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        downloadTask.cancel(true);
                    }
                });
            }
        });
    }

原生的按鈕:

 new android.app.AlertDialog.Builder(this)
                .setTitle("版本更新")
                .setMessage(content)
                .setPositiveButton("更新", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        pBar = new CommonProgressDialog(MainActivity.this);
                        pBar.setCanceledOnTouchOutside(false);
                        pBar.setTitle("正在下載");
                        pBar.setCustomTitle(LayoutInflater.from(
                                MainActivity.this).inflate(
                                R.layout.title_dialog, null));
                        pBar.setMessage("正在下載");
                        pBar.setIndeterminate(true);
                        pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                        pBar.setCancelable(true);
                        // downFile(URLData.DOWNLOAD_URL);
                        final DownloadTask downloadTask = new DownloadTask(
                                MainActivity.this);
                        downloadTask.execute(url);
                        pBar.setOnCancelListener(new DialogInterface.OnCancelListener() {
                            @Override
                            public void onCancel(DialogInterface dialog) {
                                downloadTask.cancel(true);
                            }
                        });
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                })
                .show();

(2)通過非同步任務實現進度++


    /**
     * 下載應用
     *
     * @author Administrator
     */
    class DownloadTask extends AsyncTask<String, Integer, String> {

        private Context context;
        private PowerManager.WakeLock mWakeLock;

        public DownloadTask(Context context) {
            this.context = context;
        }

        @Override
        protected String doInBackground(String... sUrl) {
            InputStream input = null;
            OutputStream output = null;
            HttpURLConnection connection = null;
            File file = null;
            try {
                URL url = new URL(sUrl[0]);
                connection = (HttpURLConnection) url.openConnection();
                connection.connect();
                // expect HTTP 200 OK, so we don't mistakenly save error
                // report
                // instead of the file
                if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                    return "Server returned HTTP "
                            + connection.getResponseCode() + " "
                            + connection.getResponseMessage();
                }
                // this will be useful to display download percentage
                // might be -1: server did not report the length
                int fileLength = connection.getContentLength();
                if (Environment.getExternalStorageState().equals(
                        Environment.MEDIA_MOUNTED)) {
                    file = new File(Environment.getExternalStorageDirectory(),
                            DOWNLOAD_NAME);

                    if (!file.exists()) {
                        // 判斷父資料夾是否存在
                        if (!file.getParentFile().exists()) {
                            file.getParentFile().mkdirs();
                        }
                    }

                } else {
                    Toast.makeText(MainActivity.this, "sd卡未掛載",
                            Toast.LENGTH_LONG).show();
                }
                input = connection.getInputStream();
                output = new FileOutputStream(file);
                byte data[] = new byte[4096];
                long total = 0;
                int count;
                while ((count = input.read(data)) != -1) {
                    // allow canceling with back button
                    if (isCancelled()) {
                        input.close();
                        return null;
                    }
                    total += count;
                    // publishing the progress....
                    if (fileLength > 0) // only if total length is known
                        publishProgress((int) (total * 100 / fileLength));
                    output.write(data, 0, count);

                }
            } catch (Exception e) {
                System.out.println(e.toString());
                return e.toString();

            } finally {
                try {
                    if (output != null)
                        output.close();
                    if (input != null)
                        input.close();
                } catch (IOException ignored) {
                }
                if (connection != null)
                    connection.disconnect();
            }
            return null;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // take CPU lock to prevent CPU from going off if the user
            // presses the power button during download
            PowerManager pm = (PowerManager) context
                    .getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    getClass().getName());
            mWakeLock.acquire();
            pBar.show();
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            super.onProgressUpdate(progress);
            // if we get here, length is known, now set indeterminate to false
            pBar.setIndeterminate(false);
            pBar.setMax(100);
            pBar.setProgress(progress[0]);
        }

        @Override
        protected void onPostExecute(String result) {
            mWakeLock.release();
            pBar.dismiss();
            if (result != null) {

//                // 申請多個許可權。大神的介面
//                AndPermission.with(MainActivity.this)
//                        .requestCode(REQUEST_CODE_PERMISSION_OTHER)
//                        .permission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
//                        // rationale作用是:使用者拒絕一次許可權,再次申請時先徵求使用者同意,再開啟授權對話方塊,避免使用者勾選不再提示。
//                        .rationale(new RationaleListener() {
//                                       @Override
//                                       public void showRequestPermissionRationale(int requestCode, Rationale rationale) {
//                                           // 這裡的對話方塊可以自定義,只要呼叫rationale.resume()就可以繼續申請。
//                                           AndPermission.rationaleDialog(MainActivity.this, rationale).show();
//                                       }
//                                   }
//                        )
//                        .send();
                // 申請多個許可權。
                AndPermission.with(MainActivity.this)
                        .requestCode(REQUEST_CODE_PERMISSION_SD)
                        .permission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
                        // rationale作用是:使用者拒絕一次許可權,再次申請時先徵求使用者同意,再開啟授權對話方塊,避免使用者勾選不再提示。
                        .rationale(rationaleListener
                        )
                        .send();


                Toast.makeText(context, "您未開啟SD卡許可權" + result, Toast.LENGTH_LONG).show();
            } else {
                // Toast.makeText(context, "File downloaded",
                // Toast.LENGTH_SHORT)
                // .show();
                update();
            }

        }
    }
  private static final int REQUEST_CODE_PERMISSION_SD = 101;

    private static final int REQUEST_CODE_SETTING = 300;
    private RationaleListener rationaleListener = new RationaleListener() {
        @Override
        public void showRequestPermissionRationale(int requestCode, final Rationale rationale) {
            // 這裡使用自定義對話方塊,如果不想自定義,用AndPermission預設對話方塊:
            // AndPermission.rationaleDialog(Context, Rationale).show();

            // 自定義對話方塊。
            AlertDialog.build(MainActivity.this)
                    .setTitle(R.string.title_dialog)
                    .setMessage(R.string.message_permission_rationale)
                    .setPositiveButton(R.string.btn_dialog_yes_permission, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();
                            rationale.resume();
                        }
                    })

                    .setNegativeButton(R.string.btn_dialog_no_permission, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();
                            rationale.cancel();
                        }
                    })
                    .show();
        }
    };
    //----------------------------------SD許可權----------------------------------//


    @PermissionYes(REQUEST_CODE_PERMISSION_SD)
    private void getMultiYes(List<String> grantedPermissions) {
        Toast.makeText(this, R.string.message_post_succeed, Toast.LENGTH_SHORT).show();
    }

    @PermissionNo(REQUEST_CODE_PERMISSION_SD)
    private void getMultiNo(List<String> deniedPermissions) {
        Toast.makeText(this, R.string.message_post_failed, Toast.LENGTH_SHORT).show();

        // 使用者否勾選了不再提示並且拒絕了許可權,那麼提示使用者到設定中授權。
        if (AndPermission.hasAlwaysDeniedPermission(this, deniedPermissions)) {
            AndPermission.defaultSettingDialog(this, REQUEST_CODE_SETTING)
                    .setTitle(R.string.title_dialog)
                    .setMessage(R.string.message_permission_failed)
                    .setPositiveButton(R.string.btn_dialog_yes_permission)
                    .setNegativeButton(R.string.btn_dialog_no_permission, null)
                    .show();

            // 更多自定dialog,請看上面。
        }
    }

    //----------------------------------許可權回撥處理----------------------------------//

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
            grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        /**
         * 轉給AndPermission分析結果。
         *
         * @param object     要接受結果的Activity、Fragment。
         * @param requestCode  請求碼。
         * @param permissions  許可權陣列,一個或者多個。
         * @param grantResults 請求結果。
         */
        AndPermission.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_CODE_SETTING: {
                Toast.makeText(this, R.string.message_setting_back, Toast.LENGTH_LONG).show();
                //設定成功,再次請求更新
                getVersion(Tools.getVersion(MainActivity.this));
                break;
            }
        }
    }

(3) 當apk檔案下載完畢時,開啟安裝

   private void update() {
        //安裝應用
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(new File(Environment
                        .getExternalStorageDirectory(), DOWNLOAD_NAME)),
                "application/vnd.android.package-archive");
        startActivity(intent);
    }

原始碼