Guía de soluciones de dispositivos exclusivos

Esta guía de soluciones ayuda a los desarrolladores y a los integradores de sistemas a mejorar de Google Cloud. Sigue nuestras instrucciones para encontrar soluciones para dispositivos exclusivos los comportamientos del modelo. Este libro de cocina funciona mejor para los desarrolladores que ya tienen una para dispositivos. Si es la primera vez que lo haces, consulta la sección Dispositivos exclusivos. descripción general.

Apps de Home personalizadas

Estas recetas son útiles si estás desarrollando una app para reemplazar la app de Home de Android y el Selector.

Sé la app de Home

Puedes configurar tu app como la de inicio del dispositivo para que se inicie. automáticamente cuando se inicia el dispositivo. También puedes habilitar la página principal botón que lleve la app de la lista de entidades permitidas al primer plano con bloqueo el modo de tarea.

Todas las apps de inicio controlan la categoría de intent CATEGORY_HOME. Esta es la forma en que el sistema reconoce una app de inicio. Establece una para ser la app de inicio predeterminada de las actividades de tu app como el controlador de intents de la pantalla principal preferido, llamando DevicePolicyManager.addPersistentPreferredActivity() como se muestra en el siguiente ejemplo:

Kotlin

// Create an intent filter to specify the Home category.
val filter = IntentFilter(Intent.ACTION_MAIN)
filter.addCategory(Intent.CATEGORY_HOME)
filter.addCategory(Intent.CATEGORY_DEFAULT)

// Set the activity as the preferred option for the device.
val activity = ComponentName(context, KioskModeActivity::class.java)
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager
dpm.addPersistentPreferredActivity(adminName, filter, activity)

Java

// Create an intent filter to specify the Home category.
IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_HOME);
filter.addCategory(Intent.CATEGORY_DEFAULT);

// Set the activity as the preferred option for the device.
ComponentName activity = new ComponentName(context, KioskModeActivity.class);
DevicePolicyManager dpm =
    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.addPersistentPreferredActivity(adminName, filter, activity);

Aún debes declarar el filtro de intents. del archivo de manifiesto de tu app, como se muestra en el siguiente fragmento XML:

<activity
        android:name=".KioskModeActivity"
        android:label="@string/kiosk_mode"
        android:launchMode="singleInstance"
        android:excludeFromRecents="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.HOME"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

Por lo general, no quieres que la app de selector aparezca en la pantalla Recientes. Sin embargo, no es necesario que agregues excludeFromRecents a la declaración de actividad porque el Launcher de Android oculta el que se inició inicialmente cuando el sistema se ejecuta en el modo de tareas bloqueadas.

Mostrar tareas separadas

FLAG_ACTIVITY_NEW_TASK puede ser una marca útil para apps de tipo selector, ya que cada tarea nueva aparece como un elemento separado en la Pantalla Overview. Para obtener más información sobre las tareas de la pantalla Recientes, lee Recientes Pantalla.

Kioscos públicos

Estas recetas son excelentes para dispositivos sin supervisión en espacios públicos, pero también ayudan a muchos usuarios de dispositivos dedicados a enfocarse en sus tareas.

Bloquea el dispositivo

Para asegurarte de que los dispositivos se usen según su uso previsto, puedes agregar para las restricciones de usuario que se indican en la tabla 1.

Tabla 1: Restricciones para los usuarios de los dispositivos de kiosco
Restricción de usuarios Descripción
DISALLOW_FACTORY_RESET Impide que un usuario restablezca el dispositivo a la configuración predeterminada de fábrica. Los administradores de dispositivos completamente administrados y el usuario principal pueden establecer esto restricción.
DISALLOW_SAFE_BOOT Impide que un usuario inicie el dispositivo en modo seguro en los que el sistema no iniciará automáticamente tu app. Los administradores de en dispositivos administrados, y el usuario principal puede establecer esta restricción.
DISALLOW_MOUNT_PHYSICAL_MEDIA Impide que el usuario del dispositivo active los volúmenes de almacenamiento que podría necesitar. conectarla al dispositivo. Los administradores de dispositivos completamente administrados y el usuario principal pueden establecer esta restricción.
DISALLOW_ADJUST_VOLUME Silencia el dispositivo y evita que su usuario cambie el sonido la configuración de volumen y vibración. Verifica que el kiosco no necesite audio para la reproducción de contenido multimedia o las funciones de accesibilidad. Los administradores de entornos completamente dispositivos, el usuario principal, los usuarios secundarios y los perfiles de trabajo pueden establecer restricción.
DISALLOW_ADD_USER Impide que el usuario del dispositivo agregue nuevos usuarios, como usuarios secundarios o usuarios restringidos. El sistema agrega automáticamente esta restricción de usuario a completamente administrados, pero es posible que se haya borrado. Los administradores de en dispositivos administrados, y el usuario principal puede establecer esta restricción.

En el siguiente fragmento, se muestra cómo puedes establecer las restricciones:

Kotlin

// If the system is running in lock task mode, set the user restrictions
// for a kiosk after launching the activity.
arrayOf(
        UserManager.DISALLOW_FACTORY_RESET,
        UserManager.DISALLOW_SAFE_BOOT,
        UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
        UserManager.DISALLOW_ADJUST_VOLUME,
        UserManager.DISALLOW_ADD_USER).forEach { dpm.addUserRestriction(adminName, it) }

Java

// If the system is running in lock task mode, set the user restrictions
// for a kiosk after launching the activity.
String[] restrictions = {
    UserManager.DISALLOW_FACTORY_RESET,
    UserManager.DISALLOW_SAFE_BOOT,
    UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
    UserManager.DISALLOW_ADJUST_VOLUME,
    UserManager.DISALLOW_ADD_USER};

for (String restriction: restrictions) dpm.addUserRestriction(adminName, restriction);

Te recomendamos que quites estas restricciones cuando tu app esté en modo de administrador de que un administrador de TI pudiera seguir usando estas funciones para el mantenimiento de los dispositivos. Para borrar la restricción, llama DevicePolicyManager.clearUserRestriction()

Suprimir diálogos de error

En algunos entornos, como para las demostraciones minoristas o la información pública es posible que no quieras mostrar diálogos de error a los usuarios. En Android 9.0 (API nivel 28) o versiones posteriores, puedes suprimir los diálogos de error del sistema para apps que no responden agregando Usuario de DISALLOW_SYSTEM_ERROR_DIALOGS restricción. El sistema reinicia las apps que no responden como si el usuario las cerrara la aplicación desde el cuadro de diálogo. En el siguiente ejemplo, se muestra cómo puedes hacerlo:

Kotlin

override fun onEnabled(context: Context, intent: Intent) {
    val dpm = getManager(context)
    val adminName = getWho(context)

    dpm.addUserRestriction(adminName, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS)
}

Java

public void onEnabled(Context context, Intent intent) {
  DevicePolicyManager dpm = getManager(context);
  ComponentName adminName = getWho(context);

  dpm.addUserRestriction(adminName, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS);
}

Si un administrador del usuario principal o secundario establece esta restricción, el sistema suprime los diálogos de error solo para ese usuario. Si un administrador de un dominio completamente El dispositivo establece esta restricción y el sistema elimina los diálogos para todos los usuarios.

Cómo mantener encendida la pantalla

Si estás creando un kiosco, puedes impedir que un dispositivo vaya a Sleep cuando está ejecutando la actividad de la app. Agrega la marca de diseño FLAG_KEEP_SCREEN_ON como se muestra en el siguiente ejemplo:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // Keep the screen on and bright while this kiosk activity is running.
    window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // Keep the screen on and bright while this kiosk activity is running.
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}

Verifica si el dispositivo está conectado a una CA, USB o conexión inalámbrica cargador. Regístrate para recibir transmisiones de cambio de batería y usar BatteryManager de salida para descubrir el estado de carga. Incluso puedes enviar alertas remotas a un departamento de TI administrador si el dispositivo se desconecta. Para obtener instrucciones paso a paso, lee Cómo supervisar el nivel de batería y la carga Estado.

También puedes configurar el STAY_ON_WHILE_PLUGGED_IN configuración global para mantener el dispositivo activo mientras está conectado a una fuente de alimentación. Los administradores de dispositivos completamente administrados, en Android 6.0 (nivel de API 23) o versiones posteriores, pueden llama a DevicePolicyManager.setGlobalSetting() como se muestra en el siguiente ejemplo:

Kotlin

val pluggedInto = BatteryManager.BATTERY_PLUGGED_AC or
        BatteryManager.BATTERY_PLUGGED_USB or
        BatteryManager.BATTERY_PLUGGED_WIRELESS
dpm.setGlobalSetting(adminName,
        Settings.Global.STAY_ON_WHILE_PLUGGED_IN, pluggedInto.toString())

Java

int pluggedInto = BatteryManager.BATTERY_PLUGGED_AC |
    BatteryManager.BATTERY_PLUGGED_USB |
    BatteryManager.BATTERY_PLUGGED_WIRELESS;
dpm.setGlobalSetting( adminName,
    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, String.valueOf(pluggedInto));

Paquetes de aplicación

Esta sección contiene recetas para instalar apps de manera eficiente en dispositivos dedicados.

Cómo almacenar paquetes de apps en caché

Si todos los usuarios de un dispositivo compartido comparten un conjunto común de apps, de evitar la descarga de aplicaciones siempre que sea posible. Para optimizar la experiencia a través de dispositivos compartidos con un conjunto fijo de usuarios, como dispositivos para los trabajadores por turno, en Android 9.0 (nivel de API 28) o versiones posteriores, puedes almacenar necesarios (APK) necesarios para las sesiones multiusuario.

La instalación de un APK almacenado en caché (que ya está instalado en el dispositivo) ocurre en dos etapas:

  1. El componente de administrador de un dispositivo completamente administrado (o un delegado;consulta esta página siguiente) establece la lista de APK que se conservarán en el dispositivo.
  2. Los componentes administradores de los usuarios secundarios afiliados (o sus delegados) pueden instalar el APK almacenado en caché en nombre del usuario. Los administradores del entorno de ejecución dispositivo, el usuario principal o un perfil de trabajo afiliado (o su delegados) también pueden instalar la app almacenada en caché si es necesario.

Para configurar la lista de APK que se conservarán en el dispositivo, el administrador llama DevicePolicyManager.setKeepUninstalledPackages() (es útil si no verificas que el APK esté instalado en el dispositivo) instalar una app justo antes de que la necesite un usuario. Para obtener una lista de paquetes previamente establecidos, puedes llamar DevicePolicyManager.getKeepUninstalledPackages() Después de llamar a setKeepUninstalledPackages() con cambios o cuando una instancia se borra el usuario, el sistema borra los APK almacenados en caché que ya no son necesarios.

Para instalar un APK almacenado en caché, llama a DevicePolicyManager.installExistingPackage() Este método solo puede instalar una app que el sistema ya haya almacenado en caché; tu solución para dispositivos exclusivos (o el usuario de un dispositivo) primero debe instalar la aplicación en el dispositivo antes de que puedas llamar a este método.

En el siguiente ejemplo, se muestra cómo podrías usar estas llamadas a la API en el administrador Un dispositivo completamente administrado y un usuario secundario:

Kotlin

// Set the package to keep. This method assumes that the package is already
// installed on the device by managed Google Play.
val cachedAppPackageName = "com.example.android.myapp"
dpm.setKeepUninstalledPackages(adminName, listOf(cachedAppPackageName))

// ...

// The admin of a secondary user installs the app.
val success = dpm.installExistingPackage(adminName, cachedAppPackageName)

Java

// Set the package to keep. This method assumes that the package is already
// installed on the device by managed Google Play.
String cachedAppPackageName = "com.example.android.myapp";
List<String> packages = new ArrayList<String>();
packages.add(cachedAppPackageName);
dpm.setKeepUninstalledPackages(adminName, packages);

// ...

// The admin of a secondary user installs the app.
boolean success = dpm.installExistingPackage(adminName, cachedAppPackageName);

Delega apps

Puedes delegar otra app para que administre el almacenamiento en caché. Puedes hacer esto para separar las funciones de la solución o ofrecer la posibilidad de que los administradores de TI usen sus propias aplicaciones. La app delegada obtiene los mismos permisos que el administrador. este componente. Por ejemplo, el delegado de una app del administrador de un usuario secundario puede llamar installExistingPackage(), pero no puede llamar a setKeepUninstalledPackages().

Sigue estos pasos para realizar una llamada delegada. DevicePolicyManager.setDelegatedScopes() e incluir DELEGATION_KEEP_UNINSTALLED_PACKAGES en el argumento de los permisos. En el siguiente ejemplo, se muestra cómo crear otra app el delegado:

Kotlin

var delegatePackageName = "com.example.tools.kept_app_assist"

// Check that the package is installed before delegating.
try {
    context.packageManager.getPackageInfo(delegatePackageName, 0)
    dpm.setDelegatedScopes(
            adminName,
            delegatePackageName,
            listOf(DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES))
} catch (e: PackageManager.NameNotFoundException) {
    // The delegate app isn't installed. Send a report to the IT admin ...
}

Java

String delegatePackageName = "com.example.tools.kept_app_assist";

// Check that the package is installed before delegating.
try {
  context.getPackageManager().getPackageInfo(delegatePackageName, 0);
  dpm.setDelegatedScopes(
      adminName,
      delegatePackageName,
      Arrays.asList(DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES));
} catch (PackageManager.NameNotFoundException e) {
  // The delegate app isn't installed. Send a report to the IT admin ...
}

Si todo sale bien, la app delegada recibe el ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED y se convierte en el delegado. La app puede llamar a los métodos de esta guía como si fuera el propietario del dispositivo o del perfil. Al realizar llamadas DevicePolicyManager, el delegado pasa null al administrador componente.

Instala paquetes de aplicación

A veces resulta útil instalar una app personalizada almacenada en caché local en una aplicación dispositivo. Por ejemplo, los dispositivos dedicados se implementan frecuentemente en en entornos con ancho de banda limitado o en áreas sin conectividad a Internet. Tu de la solución para dispositivos exclusivos debe tener en cuenta el ancho de banda de los clientes. Tu puede iniciar la instalación de otro paquete de aplicación (APK) con el PackageInstaller.

Si bien cualquier app puede instalar APK, los administradores en dispositivos completamente administrados también instalar (o desinstalar) paquetes sin la interacción del usuario. El administrador podría gestionar el dispositivo, un usuario secundario afiliado o un perfil de trabajo afiliado Después del tras finalizar la instalación, el sistema publica una notificación que informa a todos los usuarios del dispositivo ver. La notificación informa a los usuarios del dispositivo que se instaló la app (o (actualizado) por su administrador.

Tabla 2: Versiones de Android compatibles con la instalación de paquetes sin interacción del usuario
Versión de Android Componente de administrador para la instalación y desinstalación
Android 9.0 (nivel de API 28) o una versión posterior Usuarios secundarios afiliados y perfiles de trabajo, ambos en cuentas completamente administradas dispositivos
Android 6.0 (nivel de API 23) o una versión posterior Dispositivos completamente administrados

La manera en la que distribuyes una o más copias del APK en dispositivos exclusivos dependen de qué tan remotos estén los dispositivos y, posiblemente, de qué tan lejos están entre sí. Tu solución debe seguir las prácticas recomendadas de seguridad antes de instalar los APK en dispositivos exclusivos.

Puedes usar PackageInstaller.Session para crear una sesión que ponga en cola uno. o más APK para la instalación. En el siguiente ejemplo, recibimos el estado comentarios en nuestra actividad (modo singleTop), pero puedes usar un servicio o receptor de emisión:

Kotlin

// First, create a package installer session.
val packageInstaller = context.packageManager.packageInstaller
val params = PackageInstaller.SessionParams(
        PackageInstaller.SessionParams.MODE_FULL_INSTALL)
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)

// Add the APK binary to the session. The APK is included in our app binary
// and is read from res/raw but file storage is a more typical location.
// The I/O streams can't be open when installation begins.
session.openWrite("apk", 0, -1).use { output ->
    getContext().resources.openRawResource(R.raw.app).use { input ->
        input.copyTo(output, 2048)
    }
}

// Create a status receiver to report progress of the installation.
// We'll use the current activity.
// Here we're requesting status feedback to our Activity but this can be a
// service or broadcast receiver.
val intent = Intent(context, activity.javaClass)
intent.action = "com.android.example.APK_INSTALLATION_ACTION"
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val statusReceiver = pendingIntent.intentSender

// Start the installation. Because we're an admin of a fully managed device,
// there isn't any user interaction.
session.commit(statusReceiver)

Java

// First, create a package installer session.
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);

// Add the APK binary to the session. The APK is included in our app binary
// and is read from res/raw but file storage is a more typical location.
try (
    // These I/O streams can't be open when installation begins.
    OutputStream output = session.openWrite("apk", 0, -1);
    InputStream input = getContext().getResources().openRawResource(R.raw.app);
) {
  byte[] buffer = new byte[2048];
  int n;
  while ((n = input.read(buffer)) >= 0) {
    output.write(buffer, 0, n);
  }
}

// Create a status receiver to report progress of the installation.
// We'll use the current activity.
// Here we're requesting status feedback to our Activity but this can be a
// service or broadcast receiver.
Intent intent = new Intent(context, getActivity().getClass());
intent.setAction("com.android.example.APK_INSTALLATION_ACTION");
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
IntentSender statusReceiver = pendingIntent.getIntentSender();

// Start the installation. Because we're an admin of a fully managed device,
// there isn't any user interaction.
session.commit(statusReceiver);

La sesión envía comentarios sobre el estado de la instalación mediante intents. Cheque el campo EXTRA_STATUS de cada intent para obtener la estado. Recuerda que los administradores no reciben el Actualización de estado del STATUS_PENDING_USER_ACTION porque el usuario del dispositivo no necesita aprobar la instalación.

Para desinstalar apps, puedes llamar a PackageInstaller.uninstall. Los administradores de dispositivos completamente administrados, usuarios y perfiles de trabajo pueden desinstalar paquetes sin interacción del usuario al ejecutar versiones de Android compatibles (consulta tabla 2).

Inmovilizar las actualizaciones del sistema

Los dispositivos Android reciben actualizaciones inalámbricas del sistema y la aplicación software. Para congelar la versión del SO durante períodos críticos, como días festivos o otras horas de mayor actividad, los dispositivos exclusivos pueden suspender las actualizaciones del sistema inalámbrico durante 90 días. Para obtener más información, consulta Cómo administrar actualizaciones del sistema.

Configuración remota

Los parámetros de configuración administrados de Android permiten que los administradores de TI realicen las siguientes acciones: configurar tu app de forma remota. Puedes exponer parámetros de configuración, como listas de entidades permitidas, hosts de red o URLs de contenido para que tu app sea más útil para el equipo de TI de Google Workspace for Education.

Si tu app expone su configuración, recuerda incluir la configuración en tu en la documentación de Google Cloud. Si quieres obtener más información para exponer la configuración de tu app y reaccionar a cambios en la configuración, lee Establece parámetros de configuración administrados.

Configuración de desarrollo

Mientras desarrollas tu solución para dispositivos exclusivos, útil para establecer tu app como administrador de un dispositivo completamente administrado sin una configuración de fábrica restablecer. Para establecer el administrador de un dispositivo completamente administrado, sigue estos pasos:

  1. Compila e instala la app de controlador de política de dispositivo (DPC) en el dispositivo.
  2. Verifica que no haya cuentas en el dispositivo.
  3. Ejecuta el siguiente comando en el shell de Android Debug Bridge (adb). Tú debes reemplazar com.example.dpc/.MyDeviceAdminReceiver en el ejemplo por nombre del componente de administración de tu aplicación:

    adb shell dpm set-device-owner com.example.dpc/.MyDeviceAdminReceiver

Para ayudar a los clientes a implementar tu solución, deberás revisar otras opciones de inscripción. métodos. Recomendamos la inscripción en código QR para o dispositivos exclusivos.

Recursos adicionales

Para obtener más información sobre los dispositivos exclusivos, lee los siguientes documentos: