One, foreword

App online update is a common requirement. When the new version is released, the user enters our app and an update prompt box will pop up to update the new version of app at the first time. Online updates are divided into the following steps:

 1, obtain the online version number, versionCode, through the interface2, compare the online versionCode with the local versionCode, and the update window will pop up3To download the APK file (file download)4To install the APKCopy the code

In terms of the above steps, the first two steps are relatively simple, and the last two steps are important. Due to the acquisition and protection of permissions and privacy in various Versions of Android, various adaptation problems will occur. Therefore, this article summarizes the methods of app online update and some adaptation problems encountered.

Two, APK download

Apk download is actually a file download, and there are many ways to download files:

  1, many tripartite frameworks have file upload and download capabilities, you can use the tripartite frameworks (e.g. Volley,OkHttp)2, or start a thread to download it (IntentService)3, the simplest way: The Android SDK actually provides us with a DownloadManager class, only need a simple configuration item setting, can easily achieve the download function.Copy the code

This article uses the third method, DownloadManager, to download apk.

1. UseDownloadManagerDownload the apk

DownloadManager is provided with the SDK, and the general process is as follows:

(1) Create a Request, simple configuration (download address, file saving address, etc.) (2) After the download is completed, the system will send a download completed broadcast, we need to listen to the broadcast. (3) After listening to the downloaded broadcast, find the downloaded APK file according to the ID (4) execute apK installation in the code.

public void downloadApk(String apkUrl, String title, String desc) {
        // Fix the bug: can't install the new version, should delete the existing file before downloading
        File apkFile = new File(weakReference.get().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "test.apk");

        if(apkFile ! =null && apkFile.exists()) {
         
            apkFile.delete();
           
        }

        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
        / / set the title
        request.setTitle(title);
        // Set the description
        request.setDescription(desc);
        // Display the notification bar after completion
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setDestinationInExternalFilesDir(weakReference.get(), Environment.DIRECTORY_DOWNLOADS, "test.apk");
        // Create a download folder on your SD card
        // Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).mkdir() ;
        // Specify to download to the SD card /download/my/ directory
        // request.setDestinationInExternalPublicDir("/codoon/","test.apk");

        request.setMimeType("application/vnd.android.package-archive");
        / / remember reqId
        mReqId = mDownloadManager.enqueue(request);
    }
Copy the code

As shown in the code above, first build a Request, set the download location, title, description, apK directory, etc. Finally, call mDownloadManager. Enqueue (Request) to start the download.

Note: We need to keep this mReqId in mind here, because once the download is complete, we need to look for the APK file based on this ID and then install apK.

2. Update the download progress

To download a file, we generally need to know the download progress and give users a friendly reminder on the interface. The same is true for app update. We need to display the current download progress and total progress on the interface to let users know how long they will wait. What about getting download progress?

Before downloading, we need to register an Observer in the Activity. When the download progress changes, we will notify the Observer and update the progress. The steps are as follows:

1First we define a DownloadChangeObserver to watch the progress of the download2, and update the UI progress in DownloadChangeObserver to prompt the user3Before downloading, register the Observer in your ActivityCopy the code

The specific code is as follows:

DownloadChangeObserver.class:

 class DownloadChangeObserver extends ContentObserver {

        /**
         * Creates a content observer.
         *
         * @param handler The handler to run {@link #onChange} on, or null if none.
         */
        public DownloadChangeObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange); updateView(); }}Copy the code

In the updateView() method, query the download progress.

 private void updateView(a) {
        int[] bytesAndStatus = new int[] {0.0.0};
        DownloadManager.Query query = new DownloadManager.Query().setFilterById(mReqId);
        Cursor c = null;
        try {
            c = mDownloadManager.query(query);
            if(c ! =null && c.moveToFirst()) {
                // Number of bytes downloaded
                bytesAndStatus[0] = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                // Total number of bytes to download
                bytesAndStatus[1] = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
                // The index of the column where the state resides
                bytesAndStatus[2] = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); }}finally {
            if(c ! =null) { c.close(); }}if(mUpdateListener ! =null) {
            mUpdateListener.update(bytesAndStatus[0], bytesAndStatus[1]);
        }

        Log.i(TAG, "Download progress:" + bytesAndStatus[0] + "/" + bytesAndStatus[1] + "");
    }
Copy the code

Query the progress according to the ID we recorded earlier, which has been commented in the code, so I won’t talk more about it.

To get progress, you need to register a DownloadChangeObserver before you download it, as follows:

weakReference.get().getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true,
                mDownLoadChangeObserver);
Copy the code

3. Obtain the download result

The DownloadManager will send a broadcast downloadmanager. ACTION_DOWNLOAD_COMPLETE after the download is complete. All we need to do is listen to the broadcast, receive the broadcast, and get the apk file to install.

Define a broadcast DownloadReceiver.

class DownloadReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(final Context context, final Intent intent) {
        / / install APK
        long completeDownLoadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);

        Logger.e(TAG, "Receive broadcast");
        Uri uri;
        Intent intentInstall = new Intent();
        intentInstall.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intentInstall.setAction(Intent.ACTION_VIEW);

        if (completeDownLoadId == mReqId) {
           uri = mDownloadManager.getUriForDownloadedFile(completeDownLoadId);
         }

         intentInstall.setDataAndType(uri, "application/vnd.android.package-archive"); context.startActivity(intentInstall); }}Copy the code

Sign up for the broadcast before downloading

 // Register the broadcast and listen for APK to download
  weakReference.get().registerReceiver(mDownloadReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
Copy the code

Through the above steps, basically complete the app online update function, under Android 6.0 can run normally. However, this article is not finished yet, every version of Android has some changes, so we need to adapt to different versions, otherwise, there will be problems, so let’s take a look at the related adaptation of Android 6.0,7.0,8.0.

3. Adapted to Android 6.0

Through the previous steps, the app online update below 6.0 can run normally, on Android6.0, when the installation of the following error will be reported:

Caused by:
5 android.content.ActivityNotFoundException:No Activity found to handle Intent { act=android.intent.action.VIEW typ=application/vnd.android.package-archive flg=0x10000000 }
Copy the code

After debugging, it is found that the Uri obtained by DownloadManager is different on Android6.0 and Android6.0.

(1) On Android 6.0, getUriForDownloadedFile returns the following value: //downloads/my_downloads/10 (2) GetUriForDownloadedFile value is: get file:///storage/emulated/0/Android/data/packgeName/files/Download/xxx.apk

// // // // // // // // // // // // // // // // // // What’s the solution? After searching for information, I found the solution:

   // Query the downloaded APK with downLoadId to solve the problem of installation after 6.0
    public static File queryDownloadedApk(Context context, long downloadId) {
        File targetApkFile = null;
        DownloadManager downloader = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);

        if(downloadId ! = -1) {
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(downloadId);
            query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
            Cursor cur = downloader.query(query);
            if(cur ! =null) {
                if (cur.moveToFirst()) {
                    String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                    if(! TextUtils.isEmpty(uriString)) { targetApkFile =newFile(Uri.parse(uriString).getPath()); } } cur.close(); }}return targetApkFile;
    }
Copy the code

Instead of using getUriForDownloadedFile to obtain the Uri, use the DownloadManager.COLUMN_LOCAL_URI field to obtain the APK address.

After adapting to Android 6.0, install apK code as follows:

 / * * *@param context
     * @param intent
     */
    private void installApk(Context context, Intent intent) {
        long completeDownLoadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);

        Logger.e(TAG, "Receive broadcast");
        Uri uri;
        Intent intentInstall = new Intent();
        intentInstall.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intentInstall.setAction(Intent.ACTION_VIEW);

        if (completeDownLoadId == mReqId) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { / / 6.0 below
                uri = mDownloadManager.getUriForDownloadedFile(completeDownLoadId);
            } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { / / 6.0 to 7.0
                File apkFile = queryDownloadedApk(context, completeDownLoadId);
                uri = Uri.fromFile(apkFile);
            } 

            // Install the application
            Logger.e("zhouwei"."Download done.");

            intentInstall.setDataAndType(uri, "application/vnd.android.package-archive"); context.startActivity(intentInstall); }}Copy the code
Adapt to Android 7.0

Just after adapting 6.0, there is a problem on the machine above 7.0, why? On Android 7.0, the file access permissions have been changed so that files cannot be accessed using the file Uri in the format of file://. Android 7.0 provides a FileProvider, which should be used to get the apk address and then install apk. Simple adaptation is as follows:

(1) Create a new XML folder in the res directory and create a file provider_Paths under XML:

<? The XML version = "1.0" encoding = "utf-8"? > <paths> <external-path name="external" path="" /> <external-files-path name="Download" path="" /> </paths>Copy the code

(2) Declare Provider in androidmanifest.xml:

<! - the Android 7.0 photos, APK download save the path - > < provider Android: name = "Android. Support. The v4. Content. FileProvider" android:authorities="packgeName.fileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> </provider>Copy the code

(3) Android 7.0 file address to obtain:

 uri = FileProvider.getUriForFile(context,
                        "packageNam.fileProvider".new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "xxx.apk"));
Copy the code

The installation code after the adaptation is as follows:

 / * * *@param context
     * @param intent
     */
    private void installApk(Context context, Intent intent) {
        long completeDownLoadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);

        Logger.e(TAG, "Receive broadcast");
        Uri uri;
        Intent intentInstall = new Intent();
        intentInstall.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intentInstall.setAction(Intent.ACTION_VIEW);

        if (completeDownLoadId == mReqId) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { / / 6.0 below
                uri = mDownloadManager.getUriForDownloadedFile(completeDownLoadId);
            } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { / / 6.0 to 7.0
                File apkFile = queryDownloadedApk(context, completeDownLoadId);
                uri = Uri.fromFile(apkFile);
            } else { // Android 7.0 or above
                uri = FileProvider.getUriForFile(context,
                        "packgeName.fileProvider".new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "xxx.apk"));
                intentInstall.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            }

            // Install the application
            Logger.e("zhouwei"."Download done.");

            intentInstall.setDataAndType(uri, "application/vnd.android.package-archive"); context.startActivity(intentInstall); }}Copy the code

Note: Replace the above packageNam with your own package name and XXX. Apk with your own APK name. For more information about FileProvider, I won’t expand on it here. For more information, please read hongyang’s article: [the Android 7.0 behavior changes by FileProvider in file sharing between applications] (https://blog.csdn.net/lmj623565791/article/details/72859156), speak clearly.

For Android 8.0: Application permissions from unknown sources

Good special tired, continue to adapt to Android 8.0, because there is no Android 8.0 mobile phone, has not been paid attention to, a few days ago a Huawei user feedback online update can not be the new version, the specific performance is: APK download completed, a flash, did not jump to the APK installation interface. After troubleshooting, it is determined that the Android 8.0 permission problem.

Android8.0 + – unknown source apps can not be installed by code (find apK on sd card, manual installation is ok), the unknown source app install permissions switch has been removed, replaced by the unknown source app management list, which requires you to enable the unknown source install permissions of your app. Google is doing this to prevent what started out as a serious app from starting to do illegal things through updates that violate users’ rights.

Knowing the problem, let’s adapt it:

(1) Declare REQUEST_INSTALL_PACKAGES in the manifest file

  <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
Copy the code

(2) Determine whether the user has been authorized in the code. If the user has been authorized, the user can install the application directly. If the user has not been authorized, the user can jump to the authorization list to enable the installation permission of the application from unknown sources.

Add the following code to the broadcast that listens for apK download status:

boolean haveInstallPermission;
            // Compatible with Android 8.0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

                // Obtain permission to install applications from unknown sources
                haveInstallPermission = context.getPackageManager().canRequestPackageInstalls();
                if(! haveInstallPermission) {// No permissions
                    // Pop up and go to the Settings page for authorization
                    final AndroidOInstallPermissionListener listener = new AndroidOInstallPermissionListener() {
                        @Override
                        public void permissionSuccess(a) {
                            installApk(context, intent);
                        }

                        @Override
                        public void permissionFail(a) {
                            ToastUtils.shortToast(context, "Authorization failed. Application cannot be installed."); }}; AndroidOPermissionActivity.sListener = listener; Intent intent1 =new Intent(context, AndroidOPermissionActivity.class);
                    context.startActivity(intent1);


                } else{ installApk(context, intent); }}else {
                installApk(context, intent);
            }
Copy the code

Because when authorized to play box prompts, we use an Activity to the agent creates an Activity: AndroidOPermissionActivity to apply for permission, after users click on Settings, jump to permissions Settings interface, Then we will determine whether the authorization is successful in onActivityResult.

AndroidOPermissionActivity code is as follows:

/** compatible with Android 8. * Created by zhouwei on 2018/3/23. */

public class AndroidOPermissionActivity extends BaseActivity {
    public static final int INSTALL_PACKAGES_REQUESTCODE = 1;
    private AlertDialog mAlertDialog;
    public static AppDownloadManager.AndroidOInstallPermissionListener sListener;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        / / window

        if (Build.VERSION.SDK_INT >= 26) {
            ActivityCompat.requestPermissions(this.new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, INSTALL_PACKAGES_REQUESTCODE);
        } else{ finish(); }}@RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case INSTALL_PACKAGES_REQUESTCODE:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if(sListener ! =null) { sListener.permissionSuccess(); finish(); }}else {
                    //startInstallPermissionSettingActivity();
                    showDialog();
                }
                break; }}private void showDialog(a) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.app_name);
        builder.setMessage("In order to upgrade XXX APP normally, please click the Set button to allow the installation of applications from unknown sources. This function is only available for XXX APP version upgrade.");
        builder.setPositiveButton("Settings".new DialogInterface.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void onClick(DialogInterface dialogInterface, int i) { startInstallPermissionSettingActivity(); mAlertDialog.dismiss(); }}); builder.setNegativeButton("Cancel".new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                if(sListener ! =null) { sListener.permissionFail(); } mAlertDialog.dismiss(); finish(); }}); mAlertDialog = builder.create(); mAlertDialog.show(); }@RequiresApi(api = Build.VERSION_CODES.O)
    private void startInstallPermissionSettingActivity(a) {
        // Note that this is a new 8.0 API
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, 1);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1 && resultCode == RESULT_OK) {
            // Authorization succeeded
            if(sListener ! =null) { sListener.permissionSuccess(); }}else {
            // Authorization failed
            if(sListener ! =null) {
                sListener.permissionFail();
            }
        }
        finish();
    }

    @Override
    protected void onDestroy(a) {
        super.onDestroy();
        sListener = null; }}Copy the code

Note: When jumping to an unknown application authorization list with an Intent, be sure to include the package name so you can jump directly to your app, otherwise you can only jump to the list.

There you go, online updates for Android 8.0.

Six, complete code, encapsulates a classAppDownloadManager

In order not to rely on an Activity, we encapsulate an AppDownloadManager that can be updated online in a few lines of code, giving the complete code:

public class AppDownloadManager {
    public static final String TAG = "AppDownloadManager";
    private WeakReference<Activity> weakReference;
    private DownloadManager mDownloadManager;
    private DownloadChangeObserver mDownLoadChangeObserver;
    private DownloadReceiver mDownloadReceiver;
    private long mReqId;
    private OnUpdateListener mUpdateListener;

    public AppDownloadManager(Activity activity) {
        weakReference = new WeakReference<Activity>(activity);
        mDownloadManager = (DownloadManager) weakReference.get().getSystemService(Context.DOWNLOAD_SERVICE);
        mDownLoadChangeObserver = new DownloadChangeObserver(new Handler());
        mDownloadReceiver = new DownloadReceiver();
    }

    public void setUpdateListener(OnUpdateListener mUpdateListener) {
        this.mUpdateListener = mUpdateListener;
    }

    public void downloadApk(String apkUrl, String title, String desc) {
        // Fix the bug: can't install the new version, should delete the existing file before downloading
        File apkFile = new File(weakReference.get().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_name.apk");

        if(apkFile ! =null && apkFile.exists()) {
            apkFile.delete();
        }

        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
        / / set the title
        request.setTitle(title);
        // Set the description
        request.setDescription(desc);
        // Display the notification bar after completion
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setDestinationInExternalFilesDir(weakReference.get(), Environment.DIRECTORY_DOWNLOADS, "app_name.apk");
        // Create a download folder on your SD card
        // Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).mkdir() ;
        // Specify to download to the SD card /download/my/ directory
        // request.setDestinationInExternalPublicDir("/codoon/","codoon_health.apk");

        request.setMimeType("application/vnd.android.package-archive");
        //
        mReqId = mDownloadManager.enqueue(request);
    }

    /** * Cancel download */
    public void cancel(a) {
        mDownloadManager.remove(mReqId);
    }

    /** * correspond to {@link Activity }
     */
    public void resume(a) {
        // Set the listener to uri.parse ("content://downloads/my_downloads")
        weakReference.get().getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true,
                mDownLoadChangeObserver);
        // Register the broadcast and listen for APK to download
        weakReference.get().registerReceiver(mDownloadReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }

    /** * correspond to {@link Activity#onPause()} ()}
     */
    public void onPause(a) {
        weakReference.get().getContentResolver().unregisterContentObserver(mDownLoadChangeObserver);
        weakReference.get().unregisterReceiver(mDownloadReceiver);
    }

    private void updateView(a) {
        int[] bytesAndStatus = new int[] {0.0.0};
        DownloadManager.Query query = new DownloadManager.Query().setFilterById(mReqId);
        Cursor c = null;
        try {
            c = mDownloadManager.query(query);
            if(c ! =null && c.moveToFirst()) {
                // Number of bytes downloaded
                bytesAndStatus[0] = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                // Total number of bytes to download
                bytesAndStatus[1] = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
                // The index of the column where the state resides
                bytesAndStatus[2] = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); }}finally {
            if(c ! =null) { c.close(); }}if(mUpdateListener ! =null) {
            mUpdateListener.update(bytesAndStatus[0], bytesAndStatus[1]);
        }

        Log.i(TAG, "Download progress:" + bytesAndStatus[0] + "/" + bytesAndStatus[1] + "");
    }

    class DownloadChangeObserver extends ContentObserver {

        /**
         * Creates a content observer.
         *
         * @param handler The handler to run {@link #onChange} on, or null if none.
         */
        public DownloadChangeObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange); updateView(); }}class DownloadReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(final Context context, final Intent intent) {
            boolean haveInstallPermission;
            // Compatible with Android 8.0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

                // Obtain permission to install applications from unknown sources
                haveInstallPermission = context.getPackageManager().canRequestPackageInstalls();
                if(! haveInstallPermission) {// No permissions
                    // Pop up and go to the Settings page for authorization
                    final AndroidOInstallPermissionListener listener = new AndroidOInstallPermissionListener() {
                        @Override
                        public void permissionSuccess(a) {
                            installApk(context, intent);
                        }

                        @Override
                        public void permissionFail(a) {
                            ToastUtils.shortToast(context, "Authorization failed. Application cannot be installed."); }}; AndroidOPermissionActivity.sListener = listener; Intent intent1 =new Intent(context, AndroidOPermissionActivity.class);
                    context.startActivity(intent1);


                } else{ installApk(context, intent); }}else{ installApk(context, intent); }}}/ * * *@param context
     * @param intent
     */
    private void installApk(Context context, Intent intent) {
        long completeDownLoadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);

        Logger.e(TAG, "Receive broadcast");
        Uri uri;
        Intent intentInstall = new Intent();
        intentInstall.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intentInstall.setAction(Intent.ACTION_VIEW);

        if (completeDownLoadId == mReqId) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { / / 6.0 below
                uri = mDownloadManager.getUriForDownloadedFile(completeDownLoadId);
            } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { / / 6.0 to 7.0
                File apkFile = queryDownloadedApk(context, completeDownLoadId);
                uri = Uri.fromFile(apkFile);
            } else { // Android 7.0 or above
                uri = FileProvider.getUriForFile(context,
                        "package_name.fileProvider".new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_name.apk"));
                intentInstall.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            }

            // Install the application
            Logger.e("zhouwei"."Download done.");

            intentInstall.setDataAndType(uri, "application/vnd.android.package-archive"); context.startActivity(intentInstall); }}// Query the downloaded APK with downLoadId to solve the problem of installation after 6.0
    public static File queryDownloadedApk(Context context, long downloadId) {
        File targetApkFile = null;
        DownloadManager downloader = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);

        if(downloadId ! = -1) {
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(downloadId);
            query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
            Cursor cur = downloader.query(query);
            if(cur ! =null) {
                if (cur.moveToFirst()) {
                    String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                    if(! TextUtils.isEmpty(uriString)) { targetApkFile =newFile(Uri.parse(uriString).getPath()); } } cur.close(); }}return targetApkFile;
    }

    public interface OnUpdateListener {
        void update(int currentByte, int totalByte);
    }

    public interface AndroidOInstallPermissionListener {
        void permissionSuccess(a);

        void permissionFail(a); }}Copy the code

Use is very simple, as follows:

(1) An update prompt box is displayed to prompt users to update

 private void showUpdateDialog(final AppUpdateInfo updateInfo) {
        AppUpdateDialog dialog = new AppUpdateDialog(getContext());
        dialog.setAppUpdateInfo(updateInfo);
        dialog.setOnUpdateClickListener(new AppUpdateDialog.OnUpdateClickListener() {
            @Override
            public void update(final AppUpdateDialog updateDialog) {
                String title = "app name";
                String desc = "Version Update";

                mDownloadManager.setUpdateListener(new AppDownloadManager.OnUpdateListener() {
                    @Override
                    public void update(int currentByte, int totalByte) {
                        updateDialog.setProgress(currentByte, totalByte);
                        if((currentByte == totalByte) && totalByte ! =0) { updateDialog.dismiss(); }}}); mDownloadManager.downloadApk(updateInfo.download_url, title, desc); }}); dialog.setCanceledOnTouchOutside(false);
        dialog.setCancelable(false);
        dialog.show();

    }
Copy the code

(2) Call the corresponding methods onResume and onPause:

 @Override
    public void onResume(a) {
        super.onResume();
        if(mDownloadManager ! =null) { mDownloadManager.resume(); }}Copy the code
 @Override
    public void onPause(a) {
        super.onPause();
        if(mDownloadManager ! =null) { mDownloadManager.onPause(); }}Copy the code

Seven,

This article summarizes some of the adaptation issues you’ve encountered with online app updates in your project. For Android 6.0 adaptation, you may not have encountered this problem if you don’t use DownloadManager. The 7.0 and 8.0 adaptation will be available either way.

This is the end of the app online update version adaptation, if you have any questions, welcome to point out.

More Android dry goods articles, pay attention to the public number [Android technology grocery store]