Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

Verify non-Google Play app installs

Sideloading is manually installing an app onto a device without the use of an app store, such as Google Play. Because sideloading bypasses the app store, the user does not benefit from security, validation, and compatibility checks that Google Play completes before downloading an app to your device. This might result in runtime crashes if the app is not correctly installed.

For example, consider an app that uses Android App Bundles to optimize app download size using split APKs. When a user downloads the app from the Google Play store, it ensures that the device downloads and installs the complete set of split APKs required to run that app on that particular device. When you bypass Google Play to sideload an app, the platform does not have sufficient data to validate the app install, and proper functionality of the app is not guaranteed.

This page describes how to use Play Core library APIs to gracefully handle situations where your app’s base APK is installed but not other required split APKs. In this situation, the API presents the user with a dialog that explains the problem and provides the ability to properly install the app via the Google Play store, as shown in figure 1.

Figure 1. A failure dialog when Google Play detects an incomplete app install

This API works only on devices running Android 5.0 (API level 21) or higher, and you need to also include the following project dependencies:

  • Include the Play Core library 1.6.0 or higher in your project.
  • Download bundletool 0.9.0 or higher. Alternatively, if you use the Android Gradle plugin to build your app bundle, include the following in your app project’s build.gradle file:

    buildscript {
        dependencies {
            ...
            // Use bundletool 0.9.0 or higher when building with the
            // Android Gradle plugin.
            classpath 'com.android.tools.build:bundletool:0.9.0'
        }
    }
    

    You need one of these tools to build your app as an Android App Bundle and upload it to Google Play.

Check for missing app components

If you expect users to sideload your app, you should check whether the device has installed all the split APKs required to run your app. You can perform this check using the Play Core library, which compares the split APKs currently installed on the device with the ones that Google Play expects for the given device.

To run the check, use the methods described below:

Register checks through the manifest

If your app doesn't implement a custom Application class, the easiest way to have Google Play verify your app installation is by registering the check for missing split APKs via your app’s manifest, as shown below:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication" >
    <application
        ...
        android:name="com.google.android.play.core.missingsplits.MissingSplitsDetectingApplication" >
    </application>
    ...
</manifest>

Apply checks in a custom Application class

If you have a custom Application class, simply use MissingSplitsManager to perform the check in your app’s onCreate() method, as shown below.

Kotlin

class MyCustomApplication : Application {
    override fun onCreate() {
        if (MissingSplitsManagerFactory.create(this).disableAppIfMissingRequiredSplits()) {
            // Skip app initialization.
            return
        }

        super.onCreate()
        ...
    }
}

Java

public class MyCustomApplication extends Application {
    @Override
    public void onCreate() {

        if (MissingSplitsManagerFactory.create(this).disableAppIfMissingRequiredSplits()) {
            // Skip app initialization.
            return;
        }

        super.onCreate();
        ...
    }
}

Apply checks to content providers

If a user can access your app via a content provider, you also need to perform the check in your custom ContentProvider, as shown below. That’s because the Android framework initializes your content provider before invoking your app’s Application.onCreate() method.

Kotlin

class ExampleProvider : ContentProvider {
    override onCreate(): Boolean {
        if (MissingSplitsManagerFactory.create(context).isMissingRequiredSplits) {
            // Skip provider initialization.
            return false
        }

        super.onCreate();
        ...
    }
}

Java

public class ExampleProvider extends ContentProvider {
    @Override
    public boolean onCreate() {

        if (MissingSplitsManagerFactory.create(getContext()).isMissingRequiredSplits()) {
            // Skip provider initialization.
            return false;
        }

        super.onCreate();
        ...
    }
}