SoFunction
Updated on 2025-04-18

Android implements the automatic update function of Android APP

Android implements the automatic update function of Android APP

Updated: April 18, 2025 08:25:10 Author: Katie.
In the entire life cycle of mobile applications, version iteration and user update experience are crucial. The traditional practice is to rely on Google Play Store to force updates, but in some scenarios, we need to control the update process more instantly. Therefore, this article introduces the Android application automatic update function. Friends who need it can refer to it.

1. Project introduction

Version iteration and user update experience are crucial throughout the life cycle of a mobile application. The traditional approach is to rely on Google Play Store to force updates, but in some scenarios, we need to:

  • More instant control of update processes(such as grayscale, forced upgrades, reminder upgrades, etc.);

  • Support out-of-market distribution, such as internal enterprise application distribution and third-party application stores;

  • Custom update UI, consistent with the application style.

This project example will show two mainstream solutions:

  1. Google Play In‑App Updates(Official solution, suitable for applications on the Play Store)

  2. Self-built service + APK Download & Install(Applicable to non-Play distribution scenarios)

Through this tutorial, you will learn how to detect new versions in the app, pop up upgrade dialogs, download APKs in the background, and seamlessly trigger the installation process, greatly improving the user experience.

2. Related knowledge

  1. Google Play Core Library

    • :core:Includes the In‑App Updates API, allowing applications to check and trigger the "Flexible Update" or "Update Now" process at runtime without the need for users to go to the Play Store interface.

  2. FileProvider & Installation Intent

    • For self-built update solutions, you need toConfigurationFileProvider, and passIntent.ACTION_VIEWCarrying APKcontent://URI, call the system installation interface.

  3. WorkManager / DownloadManager

    • Long tasks (such as background download APK) should be usedWorkManagerOr systemDownloadManager, ensure that the download can run stably in the background and can be continuously transmitted after restarting.

  4. Runtime Permissions & Compatibility

    • Android 8.0+ (API 26+) installation requires the permission to obtain "Allow installation of unknown applications" (REQUEST_INSTALL_PACKAGES)。

    • Android 7.0+ (API 24+) file URI must goFileProvider, otherwise it will be thrownFileUriExposedException

Ideas for project implementation

  1. Version detection

    • Play Solution: Calling Play Core()Check for update status.

    • Self-built plan: Initiate a network request to your own server (such as GET/latest_version.json), get the latest version number, APK download address, update instructions, etc.

  2. Pop-up interaction

    • Select Update Now (force) or Flexible Update (allowing the background to restart the installation when running) according to the policy and display the update log.

  3. Download APK

    • Play Solution: Automatically downloaded by Play Core.

    • Self-built plan:useDownloadManagerStart the download and listen to the broadcast to get the download completion notification.

  4. Trigger installation

    • After the download is completed, constructIntent.ACTION_VIEW, specify the MIME typeapplication/-archive,useFileProviderShare the APK URI and start the installation process.

4. Complete code (All‑in‑One, with detailed comments)

// =======================================
// File: + MainActivity// (This example writes Manager and Activity in one place, and distinguishes it from comments)// =======================================
 
package ;
 
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
 
import ;
import ;
import ;
import ;
import ;
 
// —— Play Core library dependencies (update now/flexible update)// implementation ":core:1.10.3"
import ;
import ;
import ;
import ;
import ;
 
import ;
 
import ;
import ;
import ;
import ;
import ;
 
public class MainActivity extends AppCompatActivity {
 
    // ------------------------------------------------------------------------------------------------------------------------------    private static final int REQUEST_CODE_UPDATE = 100;               // Play update request code    private static final int REQUEST_INSTALL_PERMISSION = 101;        // Dynamic installation permissions    private static final String TAG = "AutoUpdate";
    private long downloadId;                                          // DownloadManager returns ID    private DownloadManager downloadManager;
 
    // ---------- onCreate ----------
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        (savedInstanceState);
        setContentView(.activity_main);  // See below for layout 
        // The button triggers two updates        Button btnPlayUpdate    = findViewById();
        Button btnCustomUpdate  = findViewById();
 
        (new () {
            @Override public void onClick(View v) {
                checkPlayUpdate();   // Play Store Update            }
        });
 
        (new () {
            @Override public void onClick(View v) {
                checkCustomUpdate(); // Self-built server update            }
        });
 
        // Initialize DownloadManager        downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        // Register to download and complete the broadcast        registerReceiver(onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }
 
    // --------- 1. Play In‑App Updates Check --------    private void checkPlayUpdate() {
        // Create AppUpdateManager         appUpdateManager =
                (this);
 
        // Get update information asynchronously        Task<AppUpdateInfo> appUpdateInfoTask = ();
        (info -> {
            // Determine whether there is an update and supports immediate update            if (() == UpdateAvailability.UPDATE_AVAILABLE
                    && ()) {
                try {
                    // Initiate a flexible update request                    (
                            info,
                            ,
                            this,
                            REQUEST_CODE_UPDATE);
                } catch (Exception e) {
                    (TAG, "Play update failed to start", e);
                }
            } else {
                (this, "No update available or this update type is not supported", Toast.LENGTH_SHORT).show();
            }
        });
    }
 
    // ---------- 2. Self-built server version detection ---------    private void checkCustomUpdate() {
        new Thread(() -> {
            try {
                // 1) Request server JSON                URL url = new URL("/latest_version.json");
                HttpURLConnection conn = (HttpURLConnection) ();
                (5000);
                ("GET");
                InputStream in = ();
                Scanner sc = new Scanner(in).useDelimiter("\\A");
                String json = () ? () : "";
                JSONObject obj = new JSONObject(json);
                final int serverVersionCode = ("versionCode");
                final String apkUrl       = ("apkUrl");
                final String changeLog   = ("changeLog");
 
                // 2) Get the local version number                int localVersionCode = getPackageManager()
                        .getPackageInfo(getPackageName(), 0).versionCode;
 
                if (serverVersionCode > localVersionCode) {
                    // There is a new version, go back to the main thread pop-up prompt                    runOnUiThread(() ->
                        showUpdateDialog(apkUrl, changeLog)
                    );
                } else {
                    runOnUiThread(() ->
                        (this, "It's the latest version", Toast.LENGTH_SHORT).show()
                    );
                }
            } catch (Exception e) {
                (TAG, "Check for update failed", e);
            }
        }).start();
    }
 
    // ---------- 3. An update dialog box pops up ---------    private void showUpdateDialog(String apkUrl, String changeLog) {
        new (this)
            .setTitle("Discover a new version")
            .setMessage(changeLog)
            .setCancelable(false)
            .setPositiveButton("Update now", (dialog, which) -> {
                startDownload(apkUrl);
            })
            .setNegativeButton("Let's talk about it later", null)
            .show();
    }
 
    // ---------- 4. Start the system DownloadManager Download APK ---------    private void startDownload(String apkUrl) {
         request = new ((apkUrl));
        (.NETWORK_WIFI
                                      | .NETWORK_MOBILE);
        ("Downloading update package");
        (Environment.DIRECTORY_DOWNLOADS, "");
        // Start downloading        downloadId = (request);
    }
 
    // ---------- 5. The monitoring download is completed and the installation is triggered.    private BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
        @Override public void onReceive(Context context, Intent intent) {
            long id = (DownloadManager.EXTRA_DOWNLOAD_ID, -1);
            if (id != downloadId) return;
 
            // Download is completed, install the APK            File apkFile = new File((
                            Environment.DIRECTORY_DOWNLOADS), "");
 
            // Android 8.0+ requires request for installation of unknown application permissions            if (.SDK_INT >= Build.VERSION_CODES.O) {
                boolean canInstall = getPackageManager().canRequestPackageInstalls();
                if (!canInstall) {
                    // Request "install unknown application" permission                    (,
                        new String[]{.REQUEST_INSTALL_PACKAGES},
                        REQUEST_INSTALL_PERMISSION);
                    return;
                }
            }
            installApk(apkFile);
        }
    };
 
    // ---------- 6. Process the results of the application for permissions from unknown sources ---------    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        if (requestCode == REQUEST_INSTALL_PERMISSION) {
            if (>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED) {
                // Trigger the installation again (assuming the APK is still downloading the directory)                File apkFile = new File((
                                Environment.DIRECTORY_DOWNLOADS), "");
                installApk(apkFile);
            } else {
                (this, "Installation permission denied, cannot be updated automatically", Toast.LENGTH_LONG).show();
            }
        }
        (requestCode, permissions, grantResults);
    }
 
    // ---------- 7. Install APK helper method --------    private void installApk(File apkFile) {
        Uri apkUri = (this,
                getPackageName() + ".fileprovider", apkFile);
 
        Intent intent = new Intent(Intent.ACTION_VIEW);
        (apkUri, "application/-archive");
        (Intent.FLAG_GRANT_READ_URI_PERMISSION);
        (Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            startActivity(intent);
        } catch (ActivityNotFoundException e) {
            (this, "Cannot start installer", Toast.LENGTH_LONG).show();
        }
    }
 
    // ---------- 8. Log out of Activity when destroyed Receiver --------    @Override
    protected void onDestroy() {
        ();
        unregisterReceiver(onDownloadComplete);
    }
}
<!-- ======================================
document: 
Notice:Requires configuration FileProvider With permissions
====================================== -->
<manifest xmlns:andro
    package="">
 
    <!-- Install unknown source permissions(Android 8.0+ Need to apply dynamically) -->
    <uses-permission android:name=".REQUEST_INSTALL_PACKAGES"/>
    <uses-permission android:name=""/>
    <uses-permission android:name=".WRITE_EXTERNAL_STORAGE"/>
 
    <application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:theme="@style/">
 
        <!-- FileProvider statement -->
        <provider
            android:name=""
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name=".FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
 
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name=""/>
                <category android:name=""/>
            </intent-filter>
        </activity>
    </application>
</manifest>
<!-- ======================================
document: res/xml/file_paths.xml
FileProvider Path configuration
====================================== -->
<paths xmlns:andro>
    <external-path name="download" path="Download/"/>
</paths>
<!-- ======================================
document: res/layout/activity_main.xml
Simple sample interface
====================================== -->
<LinearLayout xmlns:andro
    android:orientation="vertical" android:gravity="center"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:padding="24dp">
 
    <Button
        android:
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Play In‑App Update"/>
 
    <View android:layout_height="16dp" android:layout_width="match_parent"/>
 
    <Button
        android:
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Self-built service update"/>
</LinearLayout>

5. Method interpretation

  • checkPlayUpdate()
    Check update availability on Google Play and start the download and installation process in a "flexible update" way.

  • checkCustomUpdate()
    passHttpURLConnectionRequest server JSON, parse the latestversionCodeandapkUrl, compare the local version and decide whether to pop up the window.

  • showUpdateDialog(...)
    Based on server returnchangeLogBuildAlertDialog, provides two interactions: "Update now" and "Say later".

  • startDownload(String apkUrl)
    Usage systemDownloadManagerInitiate a background download and save it to the public directory, supporting breakpoint relay and system download notifications.

  • BroadcastReceiver onDownloadComplete
    MonitorDownloadManager.ACTION_DOWNLOAD_COMPLETEBroadcast, confirm that the installation process is triggered after this download.

  • onRequestPermissionsResult(...)
    Process the authorization results of Android 8.0+ "Installation Unknown Source" permission, and continue to call after authorization.installApk()

  • installApk(File apkFile)
    passFileProviderGet the content URI of the APK and use itIntent.ACTION_VIEWCall the system installer.

6. Project Summary

Advantages

  • Play Core In‑App Update: Official support, the experience is consistent with the Play Store, without the need to manually manage download logic.

  • Self-built plan: Flexible and controllable, supports any distribution channel, customizes UI and grayscale policies.

Pay attention and optimization

  1. Permissions and compatibility

    • Android 7.0+ must be usedFileProvider

    • Android 8.0+ requires dynamic applicationREQUEST_INSTALL_PACKAGES

  2. Download failed and try again

    • Can be combinedWorkManagerAdded the logic of retry and network disconnection.

  3. Security

    • It is recommended to perform signature verification of the APK (calculate SHA256 and the server) to prevent it from being tampered with.

  4. UI Experience

    • Make more status prompts for "Update Now" and "Background Update".

    • Download progress bar, progress notification, etc. can be displayed.

  5. Grayscale/forced upgrade

    • You can add policy fields in the server JSON, such asforceUpdate, prohibit "Say it later" in the dialog box.

This is the article about Android implementing the automatic update function of Android APP. For more relevant content on Android APP, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!

  • Android
  • APP
  • Automatic update

Related Articles

  • How to preset APK in Android system source code

    Today, the editor will share with you an article about presetting APKs in the Android system source code. The editor thinks the content is pretty good. Now I share it with you. It has good reference value. Friends in need will follow the editor to take a look.
    2018-12-12
  • Detailed explanation of the solution to the compatibility of Android immersive implementation

    This article mainly introduces a detailed explanation of the solutions to the compatibility of Android immersive implementation. The editor thinks it is quite good. I will share it with you now and give you a reference. Let's take a look with the editor
    2017-11-11
  • Android method to change the default location of Toast

    Below, the editor will introduce you to an article about how to change the default location of Toast on Android. The editor thinks it is quite good, so I will share it with you now and give you a reference. Let's take a look with the editor
    2017-04-04
  • Some thoughts on getting current activities in Android development

    This article mainly introduces some thoughts on obtaining current activities during Android development. Interested friends can refer to it.
    2016-02-02
  • Detailed explanation of the five major layout methods of Android

    This article mainly introduces the knowledge and information of the five major layouts of Android. Here we have compiled detailed layout information, implementation sample code, and implementation renderings. Interested friends can refer to it.
    2016-09-09
  • Android method to implement marble effect based on TextView attribute android:ellipsize

    This article mainly introduces the method of Android to achieve marble effects based on TextView attributes android:ellipsize. It involves the related attributes and usage methods of TextView involved in Android marble effects. Friends who need it can refer to it
    2016-08-08
  • Unicode code values ​​for some special characters in Android (such as: ←↑→↓ and other arrow symbols)

    This article mainly introduces the Unicode code values ​​of some special characters in Android (such as: ←↑→↓ and other arrow symbols). Friends who need it can refer to it.
    2017-03-03
  • Android Web jump to the app specified page and pass parameter instance

    This article mainly introduces the Android Web to jump to the app specified page and pass parameter instances. It has good reference value and hopes it will be helpful to everyone. Let's take a look with the editor
    2020-03-03
  • 2 ways to realize real-time viewPager

    This article mainly introduces two ways to realize real-time viewPager on Android, which has certain reference value. Interested friends can refer to it.
    2016-10-10
  • Android Zoom Animation Summary

    ScaleAnimation is the scaling animation, with many application scenarios, such as the common hidden menu click to display. This article mainly introduces the use of Android scaling animation ScaleAnimation. Friends who need it can refer to it.
    2024-03-03

Latest Comments