# Distribute apps

> [!IMPORTANT]
> **Tip:** Set up your EMM console so that an IT admin can mark an app as **mandatory** or **optional** for individual users or groups. Remotely install mandatory apps onto users' devices and list optional apps in the managed Google Play store.

The Google Play EMM API supports the following distribution methods for
public and private apps:

- Users can [**manually install**](https://developers.google.com/android/work/play/emm-api/distribute#manual-install) apps from the managed Google Play store.
- IT admins can [**remotely install**](https://developers.google.com/android/work/play/emm-api/distribute#remote-install) apps onto users' devices.

## Manually install apps from the managed Google Play store

You can define which apps are available for a user to install in the
[`Device`](https://developers.google.com/android/work/play/emm-api/v1/devices)'s `policy` and set it by calling [`Devices.update`](https://developers.google.com/android/work/play/emm-api/v1/devices/update). When
provisioning a new device, you should set the policy before adding the managed
Google Play Account to the device, otherwise the policy won't be applied for a
short period of time after adding the account to the device.

The managed Play Store behavior is defined by the value of
`policy.productAvailabilityPolicy`:

- `all`: All public apps from the Play Store are available.
- `whitelist`: Only the apps listed in `policy.productPolicy` are available.

In both cases, all apps in `policy.productPolicy` are added by default to
the enterprise's store layout. The enterprise's store layout is the homepage
of the managed Play Store when `whitelist` is selected, and can be accessed
in a "Work Apps" tab when `all` is selected. You can allow your customer to
customize the enterprise's store layout by embedding the managed Google Play
iframe (see [Organize apps with the managed Google Play iframe](https://developers.google.com/android/work/play/emm-api/managed-play-iframe#organize-apps)).

## Remotely install apps onto user's devices

To remotely install (also called push install) an app on a user's device, set
`policy.productPolicy.autoInstallPolicy` in the [`Device`](https://developers.google.com/android/work/play/emm-api/v1/devices)'s `policy`. When
provisioning a new device, you should set the policy before adding the managed
Google Play Account to the device, otherwise the policy won't be applied for a
short period of time after adding the account to the device.

The `autoInstallMode` can be set to:

- `doNotAutoInstall`: The app is not automatically installed.
- `autoInstallOnce`: The app is automatically installed once, if the user uninstalls the app it won't be installed again.
- `forceAutoInstall`: The app is automatically installed, if the user uninstalls the app it will be installed again. On managed devices the DPC should block uninstall using [`DevicePolicyManager.setUninstallBlocked`](https://developers.google.com/android/reference/android/app/admin/DevicePolicyManager#setUninstallBlocked).

In case of failure (loss of connectivity, lack of storage, etc), installs are
retried automatically until they succeed. An exponential backoff retry strategy
is applied to avoid wasting battery and data in the case of unrecoverable
failures.

### Install priority

You can choose the order of installs by setting `autoInstallPriority`. The
priority must be an unsigned integer and the default value is 0. Apps will be
installed in increasing order or priority, meaning that apps with the lower
priority value will be installed first.

### Install constraints

You can set install constraints for each app by setting an
`autoInstallConstraint`, allowing you to control the required state of the
device during the install:

- whether the device should be connected to a Wi-Fi network,
- whether the device should be charging,
- and whether the device should be idle (not actively used by the user).

If the constraints are not met immediately then affected installs will be queued
until the constraints are met.

In an `autoInstallConstraint` the AND rule is applied between the fields. For
example, with the following `autoInstallConstraint`, the device must be both
charging and connected to an unmetered network (e.g. Wi-Fi) for the app to be
installed:

    "autoInstallConstraint": [
      "chargingStateConstraint" : "chargingRequired",
      "networkTypeConstraint" : "unmeteredNetwork"
    ]

### Auto-install apps on newly provisioned devices

The Google Play EMM API sends a `NewDeviceEvent` notification when a device is
first provisioned. To automatically push-install apps onto newly provisioned
devices, listen for `NewDeviceEvent` notifications. From each `NewDeviceEvent`,
retrieve the `userId` and `deviceId`, and then call [`Devices.update`](https://developers.google.com/android/work/play/emm-api/v1/devices/update) to set
the policy for that device.

To learn how to subscribe to EMM notifications, see
[Set up EMM notifications](https://developers.google.com/android/work/play/emm-api/about-notifications).

## App auto-install error feedback

Errors related to app installation are reported through [App Feedback](https://developer.android.com/work/app-feedback/overview), and
the DPC can monitor the [`EnterprisePolicyStatus`](https://developers.google.com/android/work/play/emm-api/distribute#EnterprisePolicyStatus) message sent through
[`KeyedAppStatesService`](https://developer.android.com/reference/kotlin/androidx/enterprise/feedback/KeyedAppStatesService).

To decode the Base64 encoded data, the DPC must generate classes based on the
proto definition of [`EnterprisePolicyStatus`](https://developers.google.com/android/work/play/emm-api/distribute#EnterprisePolicyStatus). Refer to [Protocol Buffers](https://developers.google.com/protocol-buffers/docs/proto)
documentation for instructions on generating proto classes.

With the generated classes, the DPC can decode the `EnterprisePolicyStatus`
object:

    EnterprisePolicyStatus enterprisePolicyStatus = EnterprisePolicyStatus.parseFrom(
        BaseEncoding.base64().decode(base64EncodedString)
    );

The [Device Policy](https://developers.google.com/android/work/play/emm-api/v1/devices) now includes the new optional field `PolicyId`.
When creating or updating a policy, the EMM can set the `PolicyId` to any string
value in order to identify a specific [Device Policy](https://developers.google.com/android/work/play/emm-api/v1/devices) version.

If available, the app install feedback will report the `PolicyId` so that the
DPC can match the received errors with specific policies.

### EnterprisePolicyStatus

    message EnterprisePolicyStatus {
      // Individual status for an app in the policy
      repeated ApplicationStatus app_status = 1;

      // Version of the policy for which this status applies.
      PolicyVersion version = 2;
    }

### ApplicationStatus

    // Individual status for an app.
    message ApplicationStatus {
      // The package name for the app.
      string package_name = 1;

      // The install status for the app. Only includes status for apps scheduled
      // to be auto-installed via the policy resource.
      AutoInstallStatus install_status = 2;
    }

### AutoInstallStatus

    // Auto-install status for an app.
    message AutoInstallStatus {
      // The error causing the install to fail if state is INSTALL_ERROR.
      EnterpriseAutoInstallError error = 1;

      // The current install state of the app.
      EnterpriseAutoInstallState state = 2;
    }

### PolicyVersion

    // The version of the policy which these install states apply to.
    message PolicyVersion {
      // A policy id which may be optionally set by the EMM.
      string policy_id = 1;
    }

### EnterpriseAutoInstallError

    // Install errors resulting in failure to install an app.
    enum EnterpriseAutoInstallError {
      // Catch-all for unrecognized enum values.
      ENTERPRISE_AUTO_INSTALL_ERROR_UNKNOWN = 0;

      // The app could not be found.
      ENTERPRISE_AUTO_INSTALL_ERROR_NOT_FOUND = 1;

      // The app is not available in the user's country.
      ENTERPRISE_AUTO_INSTALL_ERROR_UNAVAILABLE_COUNTRY = 2;

      // The app is not compatible with the device hardware.
      ENTERPRISE_AUTO_INSTALL_ERROR_NOT_COMPATIBLE_WITH_DEVICE = 3;

      // No license remained to grant ownership of the app, and the user did not
      // already own the app.
      ENTERPRISE_AUTO_INSTALL_ERROR_NO_LICENSES_REMAINING = 4;

      // Required permissions for the app have not been accepted.
      ENTERPRISE_AUTO_INSTALL_ERROR_MISSING_PERMISSION = 5;

      // The app is not available based on the enterprise availability policy.
      ENTERPRISE_AUTO_INSTALL_ERROR_NOT_APPROVED_OR_UNAVAILABLE = 6;

      // The app is not available to the user or device.
      ENTERPRISE_AUTO_INSTALL_ERROR_APP_UNAVAILABLE = 7;

      // Failed to grant license because the user already has ownership.
      ENTERPRISE_AUTO_INSTALL_ERROR_INCOMPATIBLE_OWNERSHIP = 8;

      // The admin has not accepted the terms of service.
      ENTERPRISE_AUTO_INSTALL_ERROR_TOS_NOT_ACCEPTED = 9;

      // The device does not have enough RAM.
      ENTERPRISE_AUTO_INSTALL_ERROR_INSUFFICIENT_RAM = 10;

      // The app is incompatible with the device carrier.
      ENTERPRISE_AUTO_INSTALL_ERROR_NOT_COMPATIBLE_WITH_DEVICE_CARRIER = 11;

      // The app is incompatible with the country or carrier.
      ENTERPRISE_AUTO_INSTALL_ERROR_NOT_COMPATIBLE_WITH_DEVICE_COUNTRY_OR_CARRIER = 12;

      // The app is incompatible with the safe search level.
      ENTERPRISE_AUTO_INSTALL_ERROR_NOT_COMPATIBLE_WITH_DEVICE_SAFE_SEARCH_LEVEL = 13;

      // The app could not be installed due to an installer error.
      ENTERPRISE_AUTO_INSTALL_ERROR_INSTALL_FAILED = 14;

      // The app could not be installed due to network errors.
      ENTERPRISE_AUTO_INSTALL_ERROR_NETWORK_FAILED = 15;

      // The device does not have enough storage.
      ENTERPRISE_AUTO_INSTALL_ERROR_INSUFFICIENT_STORAGE = 16;
    }

### EnterpriseAutoInstallState

    // The current install state for an app.
    enum EnterpriseAutoInstallState {
      // Catch-all for unrecognized enum values.
      INSTALL_STATE_UNKNOWN = 0;

      // The app has been received by Play but an install attempt has not completed
      // yet.
      INSTALL_STATE_PENDING = 1;

      // The latest install attempt failed and will be retried automatically.
      INSTALL_STATE_ERROR = 2;

      // The app has been installed.
      INSTALL_STATE_INSTALLED = 3;
    }

## Distribute apps for closed testing

Closed testing allows app developers to get feedback on early versions of their
app from trusted users. Developers can set up closed tests in the Google Play
Console. You use the Play EMM API to enable IT admins to distribute closed
versions (also called tracks) of apps to specific users. Your enterprise
customers can use this feature to not only test 3rd party apps, but also to test
private apps developed in-house.

### Eligible apps

Before a developer adds an enterprise to an app's list of closed testers, the
app should meet the following criteria:

- A production version of the app is published on Google Play.
- In the Google Play Console, **Managed Google Play** is enabled in the app's **Advanced Settings** page.
- Any closed versions of the app meet [version code requirements](https://support.google.com/googleplay/android-developer/answer/3131213#version_codes).

### Add an enterprise to closed tests

App developers can add enterprises to tests that use the methods **Closed Alpha
Testing** , or **Alpha Testing using Google Groups** . For instructions, see guide
on how to [set up an open, closed, or internal test](https://support.google.com/googleplay/android-developer/answer/3131213).
The developer needs to enter the organization ID (also referred to as
*enterprise ID*) of each participating enterprise. IT admins can provide their
organization's ID to 3rd party app developers by following these steps:

1. Sign in to the [managed Google Play store](https://play.google.com/work).
2. Click **Admin Settings**.
3. Copy the Organization ID string from the Organization information box and send it to the developer.

#### Additional requirements for private apps

For private apps, the developer also needs to add the organization ID of each
participating enterprise in the **Managed Google Play** tab of the app's
Advanced Settings page. For instructions, see
[Publish a private app](https://support.google.com/googleplay/work/answer/6145139#publishprivate).

### Distribute closed tracks to users

To retrieve a list of tracks available to an enterprise for a specified app,
call [`Products.get`](https://developers.google.com/android/work/play/emm-api/v1/products/get). The `appTracks[]` list contained in the response includes
the tracks available for each app. The `appTracks[].trackAlias` is a user
readable name for the track that you can display in your EMM console, and the
`appTracks[].trackId` is the machine readable ID for the track.

To grant a user visibility to an app's closed track, set the
`policy.productPolicy[].trackIds[]` in the
[`Device`](https://developers.google.com/android/work/play/emm-api/v1/devices)'s `policy`. If multiple tracks are available for a device, the
available version with the highest version code will be installed.

The trackIds will be automatically removed from [`Products.get`](https://developers.google.com/android/work/play/emm-api/v1/products/get) call in certain
scenarios such as the following:

- Track's app version is promoted to another track or to the production.
- The production version is updated with a higher version than the track.
- A developer stops the track.

## Keep track of paid app licenses

> [!WARNING]
> From September 2019, organizations can no longer [purchase app
> licenses through managed Google Play](https://support.google.com/googleplay/work/answer/6150398). However, they can still use any licenses they already own.

For paid apps the [`Grouplicenses`](https://developers.google.com/android/work/play/emm-api/v1/grouplicenses) object keeps track of how many licenses an
enterprise owns and how many licenses are in use. You can call
[`Grouplicenses.get`](https://developers.google.com/android/work/play/emm-api/v1/grouplicenses/get) to obtain license details for an app.

Before a paid app can be installed on a device, the enterprise needs to have a
license available for the app. If a license is available, the app is installed
on the device and an [`Entitlements`](https://developers.google.com/android/work/play/emm-api/v1/entitlements) object is created. An `Entitlements`
object links a license with a user and decrements the available license count
for the app. If there are no licenses available, then app installation fails and
no `Entitlements` object is created.

`Grouplicenses` and `Entitlements` objects are not used by applications that are
distributed without charge.