1. 程式人生 > >App版本升級

App版本升級

在我們進行App開發的時候,免不了進行進行版本迭代,所以就將自己的版本迭代進行整理,以便大家使用,也對自己以後的開發更方便 首先是請求後臺資料,獲取當前後臺版本號,然後和自己客戶端的版本號進行比對,如果高於當前版本,就進行升級  

   //versionCode 是當前App的版本號
if (versionCode < 伺服器版本號) {
                //不強制更新(這是我們的判斷,用來判斷是否是強制更新)
                if (SPUtil.getFormKey(this, Contact.ISFORCEUPDATE).equals("0")) {
                    //這是彈出框,用來展示更新描述的
                    final UpdateDialog updateDialog = new UpdateDialog(MainActivity.this, "版本更新", updateInfo, "升級");
                    SPUtil.setBooleanValue(MainActivity.this, Contact.ISUPDATE, true);
                    updateDialog.setDialogListener(new DialogListener() {
                        @Override
                        public void confirm(String tag) {
                            //這是用來請求儲存許可權的
                            permissionRequest(updateDialog, downloadUrl, "0", Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE);//Permission請求例項
                        }
                    });
                    updateDialog.show();
                } else {
                    //強制更新(彈出框可以自定義,只需要在點選升級的時候做操作就行)
                    final UpdateDialog updateDialog = new UpdateDialog(MainActivity.this, "版本更新", updateInfo, "升級");
                    updateDialog.setCanceledOnTouchOutside(false);
                    updateDialog.setCancelable(false);
                    updateDialog.setDialogListener(new DialogListener() {
                        @Override
                        public void confirm(String tag) {
                            permissionRequest(updateDialog, downloadUrl, "1", Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE);//Permission請求例項
                        }
                    });
                    updateDialog.show();
                }
            } else {
                //當前不更新
            }

這個Version我建立了一個工具類,用來獲取當前App的版本號和版本名稱,自行選擇  


/**
 * 獲取 versioncode versionname 工具類
 */
public class APKVersionCodeUtils {

    /**
     * 獲取當前本地apk的版本
     *
     * @param mContext
     * @return
     */
    public static int getVersionCode(Context mContext) {
        int versionCode = 0;
        try {
            //獲取軟體版本號,對應AndroidManifest.xml下android:versionCode
            versionCode = mContext.getPackageManager().
                    getPackageInfo(mContext.getPackageName(), 0).versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return versionCode;
    }

    /**
     * 獲取版本號名稱
     *
     * @param context 上下文
     * @return
     */
    public static String getVerName(Context context) {
        String verName = "";
        try {
            verName = context.getPackageManager().
                    getPackageInfo(context.getPackageName(), 0).versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return verName;
    }
}

因為我們在從伺服器下載完安裝包之後,就要將安裝包儲存到本地資料夾,所以在點選升級的時候,我們要先去申請讀寫許可權,這個許可權要在AndroidManifest裡面宣告一下,就不在多說  

//這是申請許可權的方法   
 private void permissionRequest(final UpdateDialog updateDialog, final String fileUrl, final String isForce, String... permissions) {
        mSetting = new PermissionSetting(this);
        AndPermission.with(this)
                .permission(permissions)
                .onGranted(new Action() {
                    @Override
                    public void onAction(List<String> permissions) {
                        //提示使用者正在下載
                        Toast.makeText(getApplicationContext(), "正在下載...", Toast.LENGTH_LONG).show();
                        //我將下載APK和安裝APK並替換放在了工具類中
                        DownloadUtils downloadUtils = new DownloadUtils(MainActivity.this);
                        downloadUtils.downloadAPK(fileUrl, "你下載安裝包的名稱,自行定義,以.apk結尾");
                        //判斷當前彈出框是否是強制升級,如果是就不讓他隱藏
                        if (isForce.equals("0")) {
                            updateDialog.dismiss();
                        } else {

                        }

                    }
                })
                .onDenied(new Action() {
                    @Override
                    public void onAction(@NonNull List<String> permissions) {
                        //許可權申請失敗,不做任何操作
                        Log.e("Main_Activity", "許可權申請失敗");
                    }
                })
                .start();
    }

我這裡的許可權申請再次說明只是用來使用他的申請成功和申請失敗的方法,你可以自己去找許可權申請方法,只要你能申請下來,就都可以,沒必要糾結我這個,因為我做了很多操作,程式碼有點麻煩,就不粘出來了  

//下載APK並安裝的工具類
public class DownloadUtils {
    //下載器
    private DownloadManager downloadManager;
    //上下文
    private Context mContext;
    //下載的ID
    private long downloadId;
    private Uri imageUri;

    public DownloadUtils(Context context) {
        this.mContext = context;
    }

    //下載apk
    public void downloadAPK(String url, String name) {
        downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
        //建立下載任務
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        //行動網路情況下是否允許漫遊
        request.setAllowedOverRoaming(false);
        request.setMimeType("application/vnd.android.packed-archive");
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"");
        //在通知欄中顯示,預設就是顯示的
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setTitle("通知欄的下載APP名稱");
        request.setDescription("通知欄的下載提示");
        request.setVisibleInDownloadsUi(true);


        //設定下載的路徑
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, name);
        File apkfile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "你之前下載的.apk結尾的安裝包名稱,以.apk結尾");
        if (apkfile.exists()) {
            apkfile.delete();
        }
        //獲取DownloadManager
        //將下載請求加入下載佇列,加入下載佇列後會給該任務返回一個long型的id,通過該id可以取消任務,重啟任務、獲取下載的檔案等等
        assert downloadManager != null;
        downloadId = downloadManager.enqueue(request);

        //註冊廣播接收者,監聽下載狀態
        mContext.registerReceiver(receiver,
                new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }

    //廣播監聽下載的各個狀態
    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            checkStatus();
        }
    };


    //檢查下載狀態
    private void checkStatus() {
        DownloadManager.Query query = new DownloadManager.Query();
        //通過下載的id查詢
        query.setFilterById(downloadId);
        Cursor c = downloadManager.query(query);
        if (c.moveToFirst()) {
            int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
            switch (status) {
                //下載暫停
                case DownloadManager.STATUS_PAUSED:
                    break;
                //下載延遲
                case DownloadManager.STATUS_PENDING:
                    break;
                //正在下載
                case DownloadManager.STATUS_RUNNING:
                    break;
                //下載完成
                case DownloadManager.STATUS_SUCCESSFUL:
                    //下載完成安裝APK
                    installApk();
                    DeafultToast.show("下載完成");
                    break;
                //下載失敗
                case DownloadManager.STATUS_FAILED:
                    Toast.makeText(mContext, "下載失敗", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
        c.close();
    }

    //    /**
//     * 7.0相容
//     */
//    private void installAPK() {
//        File apkFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "caizhidao.apk");
//        Intent intent = new Intent(Intent.ACTION_VIEW);
//        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//        if (Build.VERSION.SDK_INT >= 24) {
//            Uri apkUri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".provider", apkFile);
//            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
//        } else {
//            intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
//        }
//        mContext.startActivity(intent);
//    }

    //去呼叫你下載完成的apk進行安裝
    private void installApk() {
        File apkfile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "你之前下載完成的.apk名稱,以.apk結尾");
        if (!apkfile.exists()) {
            return;
        }
        Intent i = new Intent(Intent.ACTION_VIEW);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 7.0+以上版本
            Uri apkUri = FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", apkfile); //(重中之重,如果不一致,就會呼叫失敗,他找不到你下載過的安裝包,就會出現安裝失敗,再次提示,上線之前,一定要檢查一下升級是否好使)與manifest中定義的provider中的authorities=""保持一致
            i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            i.setDataAndType(apkUri, "application/vnd.android.package-archive");
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        } else {
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            i.setDataAndType(Uri.parse("file://" + apkfile.toString()),
                    "application/vnd.android.package-archive");
        }
        mContext.startActivity(i);
    }
}

雖然我在程式碼中寫了,但是還是要提醒一下大家,Uri apkUri = FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", apkfile);(一定要和AndroidManifest中定義的provider中的authorities一致,不然找不到安裝包啊!!!上線記得測試!測試!在測試!)

接下來就是我們AndroidManifest中的東西了,  

    //就在application下設定就行,可以存在多個   
 <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="你的包名.provider"
            android:exported="false"
            android:grantUriPermissions="true">

            <!-- 元資料 -->
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_path" />
        </provider>

記住啊,這個authorities和你程式碼中寫的一定要一樣啊,這個@xml/file_path是我們安裝後安裝的路徑,沒必要指定,就放在系統預設的地方就行


<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <paths>
        <external-path
            name="download"
            path="" />
    </paths>
</resources>

這個就是那個file_path,現在是結束了,但是大家一定要測試一下,希望這篇文章對大家能有所幫助~