Cambios en el comportamiento: apps orientadas a Android 12

Al igual que las versiones anteriores, Android 12 incluye cambios de comportamiento que podrían afectar tu app. Los siguientes cambios se aplican exclusivamente a las apps orientadas a Android 12 o versiones posteriores. Si tu app está orientada a Android 12, debes modificarla para que admita estos comportamientos correctamente, cuando corresponda.

Asegúrate de revisar también la lista de cambios en el comportamiento que afectan a todas las apps que se ejecutan en Android 12.

Experiencia del usuario

Mejoras en el comportamiento de pantalla en pantalla

En Android 12, se introducen mejoras en el comportamiento del modo pantalla en pantalla (PiP). Consulta Mejoras de pantalla en pantalla para obtener más información.

Notificaciones personalizadas

En Android 12, se cambia la apariencia y el comportamiento de las notificaciones totalmente personalizadas. Antes, las notificaciones personalizadas podían usar toda el área de notificaciones y proporcionar sus propios diseños y estilos. De esta manera, se producían antipatrones que podían confundir a los usuarios y causar errores de compatibilidad en diferentes dispositivos.

En el caso de las apps orientadas a Android 12, las notificaciones con vistas de contenido personalizado ya no utilizan el área de notificaciones completa. En su lugar, el sistema aplica una plantilla estándar. Esta plantilla garantiza que las notificaciones personalizadas tengan la misma decoración que otras notificaciones en todos los estados, como el ícono y las opciones de expansión de la notificación (en el estado contraído), el ícono o el nombre de la app y la opción de contracción (en el estado de expansión). Este comportamiento es casi idéntico al comportamiento de Notification.DecoratedCustomViewStyle.

De esta manera, Android 12 permite que todas las notificaciones sean visualmente coherentes y fáciles de analizar, con una expansión de notificaciones familiar y fácil de encontrar para los usuarios.

En la siguiente ilustración, se muestra una notificación personalizada en la plantilla estándar:

Los siguientes ejemplos muestran cómo se procesarían las notificaciones personalizadas en un estado contraído y expandido:

El cambio en Android 12 afecta a las apps que definen subclases de Notification.Style personalizadas o que usan los métodos setCustomContentView(RemoteViews), setCustomBigContentView(RemoteViews) y setCustomHeadsUpContentView(RemoteViews) de Notification.Builder.

Si la app usa notificaciones totalmente personalizadas, te recomendamos que pruebes con la plantilla nueva lo antes posible.

  1. Habilita el cambio de notificaciones personalizadas:

    1. Cambia el elemento targetSdkVersion de tu app a S para habilitar el nuevo comportamiento.
    2. Vuelve a compilar.
    3. Instala la app en un dispositivo o emulador que ejecute Android 12.
  2. Prueba todas las notificaciones que usan vistas personalizadas a fin de asegurarte de que se vean como esperabas en el panel. Durante la prueba, ten en cuenta estas consideraciones y realiza los ajustes necesarios:

    • Cambiaron las dimensiones de las vistas personalizadas. En general, la altura otorgada a las notificaciones personalizadas es menor que antes. En el estado contraído, la altura máxima del contenido personalizado disminuyó de 106 dp a 48 dp. Además, hay menos espacio horizontal.

    • Todas las notificaciones se pueden expandir en las apps que se orientan a Android 12. Es decir, por lo general, si usas setCustomContentView, también querrás usar setBigCustomContentView para asegurarte de que los estados contraídos y expandidos sean coherentes.

    • Para asegurarte de que el estado de "Atención" se vea como esperas, no olvides aumentar la importancia del canal de notificaciones a "HIGH" (ventana emergente).

En las apps que se orienten a Android 12, el sistema realiza varios cambios en la manera en que se verifica Android App Links. Estos cambios mejoran la confiabilidad de la experiencia de vinculación de apps y les brindan más control a los desarrolladores de apps y los usuarios finales.

Si te orientas a Android 12 y dependes de la verificación de Android App Link para abrir vínculos web en la app, actualiza las declaraciones de Android App Links a fin de admitir los cambios en el proceso de verificación. También puedes invocar manualmente la verificación del dominio para probar la confiabilidad de las declaraciones.

Privacidad

Ubicación aproximada

El diálogo tiene dos conjuntos de opciones: uno encima del otro
Figura 1: Diálogo de permisos del sistema que aparece cuando la app se orienta a Android 12 y realiza una sola solicitud de tiempo de ejecución de ACCESS_FINE_LOCATION y ACCESS_COARSE_LOCATION.

Cuando los usuarios utilizan una app que se orienta a Android 12, pueden solicitar que esta solo tenga acceso a información de la ubicación aproximada.

.

Si la app se orienta a Android 12 y solicita el permiso de tiempo de ejecución de ACCESS_FINE_LOCATION, también debes solicitar el permiso de ACCESS_COARSE_LOCATION. Debes incluir ambos en una sola solicitud de tiempo de ejecución.

Cuando la app solicita ACCESS_FINE_LOCATION y ACCESS_COARSE_LOCATION, el diálogo de permisos del sistema incluye las siguientes opciones nuevas para el usuario, como se muestra en la figura 1:

  • Precisa: Brinda la precisión de la ubicación que proporciona el permiso ACCESS_FINE_LOCATION.
  • Aproximada: Brinda la precisión de la ubicación que proporciona el permiso ACCESS_COARSE_LOCATION.

Obtén más información sobre la ubicación aproximada en Android 12.

Hibernación de apps

En Android 12, se expande el comportamiento del restablecimiento automático de permisos que se introdujo en Android 11 (nivel de API 30). Si la app se orienta a Android 12 y el usuario no interactúa con esta por algunos meses, el sistema restablece automáticamente los permisos otorgados y coloca la app en un estado de hibernación.

Una app en hibernación tiene las siguientes características:

  • El sistema optimiza el espacio de almacenamiento en lugar del rendimiento. Se quitan todos los archivos de la caché de la app.
  • La app no puede ejecutar trabajos ni alertas en segundo plano.
  • La app no puede recibir notificaciones push, incluidos los mensajes de prioridad alta que se envían a través de Firebase Cloud Messaging.

Cuando el usuario interactúa con la app, esta sale de la hibernación y puede volver a crear trabajos, alertas y notificaciones. Sin embargo, debes volver a programar cualquier trabajo, alerta o notificación que se haya programado antes de que la app entrara en hibernación. Este flujo de trabajo es similar a cuando el usuario fuerza manualmente la detención de la app desde la configuración del sistema. Para admitir este flujo de trabajo con más facilidad, usa WorkManager. También puedes agregar la lógica de reprogramación en el receptor de emisión ACTION_BOOT_COMPLETED, que se invoca cuando la app sale de la hibernación y después de que se inicia el dispositivo.

Solicítale al usuario que inhabilite la hibernación

Si prevés que la hibernación afectará un caso de uso en la app, puedes enviarle al usuario una solicitud para otorgarle a la app una exención de hibernación y restablecimiento automático de permisos. Esta exención es útil para situaciones en las que los usuarios esperan que la app funcione principalmente en segundo plano, incluso sin que ellos interactúen con la app, por ejemplo, cuando esta realiza una o más de las siguientes acciones:

  • Informa de manera periódica la ubicación de los miembros de la familia para brindar seguridad familiar.
  • Sincroniza datos entre un dispositivo y el servidor de la app.
  • Se comunica con dispositivos inteligentes, como un TV.
  • Se vincula a dispositivos complementarios, como un reloj.

Para solicitar una exención, invoca un intent que contenga la acción de intent Intent.ACTION_APPLICATION_DETAILS_SETTINGS. En la pantalla que aparece, los usuarios pueden desactivar la opción Quitar permisos y liberar espacio.

Prueba el comportamiento de hibernación

Para colocar la app en el estado de hibernación con fines de prueba, haz lo siguiente:

  1. Habilita el comportamiento en el dispositivo:

    adb shell device_config put app_hibernation app_hibernation_enabled true
    
  2. Cambia el estado de la app para que entre en hibernación. El comando que incluye la marca --global obliga a la app a entrar en una "hibernación completa", de modo que se pueda simular la situación en la que el sistema coloca la app en estado de hibernación para todos los usuarios en un dispositivo multiusuario.

    adb shell cmd app_hibernation set-state PACKAGE-NAME true && \
      adb shell cmd app_hibernation set-state --global PACKAGE-NAME true
    

Límite de frecuencia para los sensores de movimiento

Para proteger información posiblemente sensible sobre los usuarios, si la app se orienta a Android 12, el sistema establece un límite en la frecuencia de actualización de los datos a partir de ciertos sensores de movimiento y de posición. Estos datos incluyen valores que se registran mediante el acelerómetro, el giroscopio y el sensor de campo geomagnético del dispositivo.

El límite de frecuencia de actualización depende de la manera en que accedes a los datos del sensor:

  • Si llamas al método registerListener(), la tasa de muestreo del sensor se limita a 200 Hz. Esto se aplica a todas las variantes sobrecargadas del método registerListener().
  • Si usas la clase SensorDirectChannel, la tasa de muestreo del sensor se limita a RATE_NORMAL, que suele ser, aproximadamente, 50 Hz.

Si la app se orienta a Android 12 y necesita recopilar datos del sensor de movimiento con una frecuencia mayor, debes declarar el permiso HIGH_SAMPLING_RATE_SENSORS. De lo contrario, si la app intenta recopilar datos del sensor de movimiento a una frecuencia mayor sin declarar este permiso, se produce una excepción SecurityException.

.

Auditoría de acceso a los datos

La API de auditoría de acceso a los datos, que se introdujo en Android 11 (nivel de API 30), te permite crear etiquetas de atribución, según los casos de uso de la app. Estas etiquetas te permiten determinar, con mayor facilidad, qué parte de la app realiza un tipo específico de acceso a los datos.

Si la app se orienta a Android 12, debes declarar estas etiquetas de atribución en el archivo de manifiesto de la app, con el formato que se muestra en el siguiente fragmento de código. Si la app se orienta a Android 12 y tratas de usar una etiqueta de atribución que no declaras en el archivo de manifiesto, el sistema crea una etiqueta null por ti y registra un mensaje en Logcat.


<manifest ...>
    <!-- The value of "android:tag" must be a literal string, and the
         value of "android:label" must be a resource. The value of
         "android:label" should be user-readable. -->
    <attribution android:tag="sharePhotos"
                 android:label="@string/share_photos_attribution_label" />
    ...
</manifest>

Nuevas cookies de SameSite en WebView

El componente WebView de Android se basa en Chromium, el proyecto de código abierto que potencia el navegador Chrome de Google. Durante el último año, Chromium introdujo cambios en el manejo de cookies de terceros con el objetivo de proporcionar mayor seguridad y privacidad, y ofrecer a los usuarios más transparencia y control. Estos cambios ya están disponibles para muchos usuarios de Chrome y, a partir de Android 12, los cambios ahora se aplicarán a WebView.

El atributo SameSite de una cookie controla si se puede enviar con cualquier solicitud o solo con solicitudes del mismo sitio. La versión base de WebView en Android 12 (versión 89.0.4385.0) incluye los siguientes cambios de protección de la privacidad que mejoran el manejo predeterminado de cookies de terceros y protegen contra el uso compartido entre sitios no deseados:

  • Las cookies que no tienen un atributo SameSite se consideran SameSite=Lax.
  • Las cookies con SameSite=None también deben especificar el atributo Secure, lo que significa que requieren un contexto seguro y deben enviarse mediante HTTPS.
  • Los vínculos entre las versiones HTTP y HTTPS de un sitio ahora se tratan como solicitudes entre sitios, por lo que las cookies no se envían, a menos que se marquen de forma adecuada como SameSite=None; Secure.

Para los desarrolladores, la práctica general es identificar las dependencias de cookies entre sitios en tus flujos de usuarios críticos y garantizar que el atributo SameSite esté establecido de forma explícita con los valores apropiados cuando sea necesario. Debes especificar de forma explícita las cookies que pueden funcionar en sitios web o en distintas navegaciones del mismo sitio que pasan de HTTP a HTTPS.

Si deseas obtener más información para desarrolladores web acerca de estos cambios, consulta los artículos Explicación de las cookies de SameSite y Schemeful SameSite.

Prueba los comportamientos de SameSite en tu app

Si tu app usa WebView, o si administras un sitio web o servicio que usa cookies, te recomendamos que pruebes tus flujos en WebView de Android 12. Si encuentras problemas, es posible que debas actualizar tus cookies para admitir los nuevos comportamientos de SameSite.

Observa los problemas en los accesos y el contenido integrado, en los flujos de registro, en las compras y en otros flujos de autenticación en los que el usuario comienza en una página insegura y pasa a una página segura.

Si quieres probar una app con WebView, debes completar uno de los siguientes pasos con el fin de habilitar los nuevos comportamientos de SameSite para la app que deseas probar:

  • Habilita manualmente los comportamientos de SameSite en el dispositivo de prueba. Para ello, activa la marca de IU webview-enable-modern-cookie-same-site en las herramientas para desarrolladores de WebView.

    Este enfoque te permite realizar pruebas en cualquier dispositivo que ejecute Android 5.0 (nivel de API 21) o una versión posterior, incluido Android 12, y WebView versión 89.0.4385.0 o posterior.

  • Compila tu app para que se oriente a Android 12 mediante targetSdkVersion.

    Si usas este enfoque, debes usar un dispositivo que ejecute Android 12 y WebView 89.0.4385.0 o versiones posteriores.

Para obtener información sobre la depuración remota de WebView en Android, consulta Cómo comenzar a usar los dispositivos Android de depuración remota.

Otros recursos

Para obtener más información sobre los nuevos comportamientos de SameSite y su implementación en Chrome y WebView, visita la página de actualizaciones de Chromium SameSite. Si encuentras un error en WebView o Chromium, puedes informarlo en la herramienta pública de seguimiento de errores de Chromium.

Restricción de copia de seguridad de adb

Para ayudar a proteger los datos de apps privadas, Android 12 cambia el comportamiento predeterminado del comando adb backup. En el caso de las apps orientadas a Android 12, cuando un usuario ejecuta el comando adb backup, los datos de la app se excluyen de otros datos del sistema que se exportan del dispositivo.

Si tus flujos de trabajo de prueba o desarrollo usan los datos de la app con adb backup, ahora puedes habilitar la exportación de los datos si configuras android:debuggable como true en el archivo de manifiesto de tu app.

Seguridad

Exportación de componentes más segura

Si tu app está orientada a Android 12 y contiene actividades, servicios o receptores de emisión que usan filtros de intents, debes declarar explícitamente el atributo android:exported para estos componentes de la app.

El siguiente fragmento de código muestra un ejemplo de un servicio que contiene un filtro de intents y está configurado correctamente para Android 12:

<service android:name="com.example.app.backgroundService"
         android:exported="false">
    <intent-filter>
        <action android:name="com.example.app.START_BACKGROUND" />
    </intent-filter>
</service>

Mensajes en Android Studio

Si la app incluye una actividad, un servicio o un receptor de emisión que utilice filtros de intents, pero no declara android:exported, aparecen los siguientes mensajes de advertencia, según la versión de Android Studio que uses:

Android Studio 2020.3.1 Canary 11 o posterior

Se muestran los siguientes mensajes:

  1. En el archivo de manifiesto, aparece la siguiente advertencia de lint:

    When using intent filters, please specify android:exported as well
    
  2. Cuando intentas compilar la app, aparece el siguiente mensaje de error de compilación:

    Manifest merger failed : Apps targeting Android 12 and higher are required \
    to specify an explicit value for android:exported when the corresponding \
    component has an intent filter defined.
    
Versiones anteriores de Android Studio

Si intentas instalar la app, Logcat muestra el siguiente mensaje de error:

Installation did not succeed.
The application could not be installed: INSTALL_FAILED_VERIFICATION_FAILURE
List of apks:
[0] '.../build/outputs/apk/debug/app-debug.apk'
Installation failed due to: 'null'

Mutabilidad de PendingIntent

Si tu app está orientada a Android 12, debes especificar la mutabilidad de cada objeto PendingIntent que cree la app. Este requisito adicional mejora la seguridad de tu app.

Para declarar que un objeto PendingIntent determinado es mutable o inmutable, usa la marca PendingIntent.FLAG_MUTABLE o PendingIntent.FLAG_IMMUTABLE, respectivamente. Si tu app intenta crear un objeto PendingIntent sin establecer una de esas marcas de mutabilidad, el sistema arroja una excepción IllegalArgumentException, y aparece el siguiente mensaje en Logcat:

PACKAGE_NAME: Targeting S+ (version 10000 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.

Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.

Crea intents pendientes inmutables cuando sea posible

En la mayoría de los casos, tu app debe crear objetos PendingIntent inmutables, como se muestra en el siguiente fragmento de código. Si un objeto PendingIntent es inmutable, una app no puede modificar el intent para ajustar el resultado de invocación del intent.

Kotlin

val pendingIntent = PendingIntent.getActivity(applicationContext,
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE)

Java

PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE);

Sin embargo, algunas apps necesitan crear objetos PendingIntent mutables:

Si tu app crea un objeto PendingIntent mutable, te recomendamos que uses un intent explícito y completes el elemento ComponentName. De esa manera, cada vez que otra app invoque el PendingIntent y pase el control a tu app, siempre se iniciará el mismo componente.

Prueba el cambio de mutación del intent pendiente

Para determinar si falta alguna declaración de mutación en tu app, busca la siguiente advertencia de lint en Android Studio:

Warning: Missing PendingIntent mutability flag [UnspecifiedImmutableFlag]

Durante la Vista previa para desarrolladores, puedes inhabilitar este comportamiento del sistema a fin de realizar pruebas. Para ello, desactiva la marca de compatibilidad de la app PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED.

Lanzamientos no seguros de intents

Con el objetivo de mejorar la seguridad de la plataforma, Android 12 proporciona una función de depuración que te advierte si tu app realiza un lanzamiento no seguro de un intent. Por ejemplo, la app puede realizar un lanzamiento no seguro de un intent que se vuelve a crear a partir de un URI o un lanzamiento no seguro de un intent anidado, que se define en la siguiente sección.

Acerca de los intents anidados

Un intent anidado es un intent que se pasa como un valor adicional en otro intent. Si tu app realiza las dos acciones siguientes, se producirá un incumplimiento de StrictMode.

Configura la app para que detecte lanzamientos no seguros de intents

Para verificar lanzamientos de intents no seguros en la app, llama a detectUnsafeIntentLaunch() cuando configures VmPolicy, como se muestra en el siguiente fragmento de código. Si la app detecta un incumplimiento de StrictMode, te recomendamos detener la ejecución de la app a fin de proteger la información potencialmente sensible.

Kotlin

fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build())
}

Java

protected void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build());
}

Usa los intents de manera más responsable

Tu app podría lanzar intents para navegar entre componentes dentro de ella o para realizar una acción en nombre de otra app. A fin de minimizar las posibilidades de encontrar un incumplimiento de StrictMode en cualquier situación, haz lo siguiente:

  • Copia solamente los valores adicionales y fundamentales dentro de los intents, y realiza cualquier limpieza o validación necesaria. Es posible que la app copie los valores adicionales de un intent a otro que se use para lanzar un componente nuevo. Esto sucede cuando la app llama a putExtras(Intent) o putExtras(Bundle). Si la app realiza una de estas operaciones, copia solo los valores adicionales que espera el componente receptor. Si el otro intent (que recibe la copia) lanza un componente que no se exportó, limpia y valida los valores adicionales antes de copiarlos en el intent que lanza el componente.
  • Lanzamiento interno del intent anidado: Asegúrate de que estos componentes no se exporten.
  • Lanzamiento entre apps del intent anidado: Usa un elemento PendingIntent en lugar de un intent anidado. De esta manera, cuando PendingIntent no está separado del elemento Intent que lo contiene, el componente de una app puede iniciar el PendingIntent con la identidad del proceso de llamada. Esta configuración permite que una app de proveedor envíe una devolución de llamada a cualquier componente, incluido un componente no exportado, de la app emisora.

    Si deseas obtener más información para identificar esta situación y realizar cambios en tu app, lee la entrada de blog sobre intents anidados de Android en Medium.

Rendimiento

Restricciones para el inicio del servicio en primer plano

Las apps orientadas a Android 12 ya no pueden iniciar servicios en primer plano mientras se ejecutan en segundo plano, excepto en algunos casos especiales. Si una app intenta iniciar un servicio en primer plano mientras se ejecuta en segundo plano, se produce una excepción (salvo en algunos casos especiales). Considera usar WorkManager para programar y comenzar a trabajar mientras tu app se ejecuta en segundo plano.

Si quieres obtener más información sobre cómo esto afecta a tu app y cómo puedes actualizarla según estos cambios, lee la guía sobre las restricciones del inicio del servicio en primer plano. También puedes revisar el archivo WorkManagerSample en GitHub.

Permiso de alarmas exactas

Con el fin de motivar que las apps conserven los recursos del sistema, Android 12 exige el acceso especial de apps a "Alarmas y recordatorios" a las apps que se orientan a Android 12 y establecen alarmas exactas.

Para obtener este acceso especial de apps, solicita el permiso SCHEDULE_EXACT_ALARM en el manifiesto.

Las alarmas exactas solo deben usarse para las funciones para el usuario, por ejemplo, una de las situaciones que se describen en la sección de casos de uso aceptables.

Tanto el usuario como el sistema pueden revocar el acceso especial de apps a "Alarmas y recordatorios". Cuando se revoca este acceso para la app, esta se detiene y se cancelan todas las alarmas exactas para el futuro.

Cuando se le otorga a la app el acceso especial de apps a "Alarmas y recordatorios", el sistema le envía a esta la emisión ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. Tu app deberá implementar un receptor de emisión que haga lo siguiente:

  1. Confirme que la app todavía tenga el acceso especial de apps. Para ello, llama a canScheduleExactAlarms().
  2. Reprograme cualquier alarma exacta que necesite la app, en función de su estado actual. Esta lógica debería ser similar a lo que hace la app cuando recibe la emisión ACTION_BOOT_COMPLETED.

Si la app intenta usar API que establecen alarmas exactas, pero no se le otorga el acceso especial de apps, se produce una excepción SecurityException.

Considera si el caso de uso de la app requiere, en realidad, alarmas exactas, por ejemplo, una de las situaciones que se describen en la sección de casos de uso aceptables. Usa WorkManager o JobScheduler para realizar trabajos más largos o trabajos que requieran acceso a la red. Para realizar trabajos mientras el dispositivo está en modo Descanso, crea una alarma inexacta con setAndAllowWhileIdle() y comienza a trabajar a partir de la alarma.

Alarmas exactas e inexactas

La app establece una alarma exacta cuando llama a los siguientes métodos:

Por el contrario, estableces una alarma inexacta cuando llamas a los siguientes métodos:

Casos de uso aceptables para este permiso

La opción se denomina &quot;Permitir configuración de alarmas y recordatorios&quot;
Figura 2: Página de acceso especial a "Alarmas y recordatorios" en la configuración del sistema, en la que los usuarios pueden permitir que la app establezca alarmas exactas.

La app debe usar alarmas exactas y declarar los receptores de emisión y los permisos asociados solo si una función para el usuario requiere acciones sincronizadas con precisión, como en los siguientes casos:

  • La app es una alarma o un temporizador.
  • La app permite que los usuarios programen acciones sincronizadas con precisión, como notificaciones para tareas y eventos.

En Android 12, se considera que las alarmas exactas son interrupciones críticas y urgentes. Por este motivo, las nuevas restricciones para el inicio del servicio en primer plano no afectan a las alarmas exactas.

Solicítale al usuario que otorgue acceso a la app

Si es necesario, puedes enviar al usuario a la pantalla Alarmas y recordatorios en la configuración del sistema, como se muestra en la figura 2. Para ello, completa los siguientes pasos:

  1. En la IU de la app, explícale al usuario por qué la app debe programar alarmas exactas.
  2. Invoca un intent que incluya la acción de intent ACTION_REQUEST_SCHEDULE_EXACT_ALARM.

Cómo habilitar el cambio de comportamiento

Para habilitar el cambio de comportamiento con fines de prueba, realiza una de las siguientes acciones:

  • En la pantalla de configuración Opciones para desarrolladores, selecciona Cambios de compatibilidad con apps. En la pantalla que aparece, presiona el nombre de la app y activa REQUIRE_EXACT_ALARM_PERMISSION.
  • En una ventana de la terminal de la máquina de desarrollo, ejecuta el siguiente comando:

    adb shell am compat enable REQUIRE_EXACT_ALARM_PERMISSION PACKAGE_NAME
    

Restricciones del trampolín de notificaciones

Cuando los usuarios interactúan con las notificaciones, algunas apps responden a los toques en ellas mediante el inicio de un componente de la app que, eventualmente, inicia la actividad que el usuario ve y con la que interactúa. A este componente de app se lo conoce como trampolín de notificaciones.

Para mejorar el rendimiento y la UX de las apps, las apps orientadas a Android 12 no pueden iniciar actividades de servicios o receptores de emisión que se usan como trampolines de notificaciones. En otras palabras, después de que el usuario presiona una notificación o un botón de acción dentro de la notificación, tu app no puede llamar a startActivity() dentro de un servicio o receptor de emisión.

Cuando tu app intenta iniciar una actividad desde un servicio o receptor de emisión que funciona como trampolín de notificaciones, el sistema impide que se inicie la actividad y aparece el siguiente mensaje en Logcat:

Indirect notification activity start (trampoline) from PACKAGE_NAME, \
this should be avoided for performance reasons.

Identifica los componentes de la app que funcionan como trampolines de notificaciones

Cuando pruebas la app, después de presionar una notificación, puedes identificar el servicio o el receptor de emisión que funcionan como el trampolín de notificaciones en la app. Para ello, consulta el resultado del siguiente comando de la terminal:

adb shell dumpsys activity service \
  com.android.systemui/.dump.SystemUIAuxiliaryDumpService

Una sección del resultado incluye el texto "NotifInteractionLog". Esta sección contiene la información necesaria para identificar el componente que se inicia como resultado de presionar una notificación.

Actualiza tu app

Si tu app inicia una actividad desde un servicio o receptor de emisión que funciona como trampolín de notificaciones, completa los siguientes pasos de migración:

  1. Crea un objeto PendingIntent que esté asociado a la actividad que los usuarios ven después de presionar la notificación.
  2. Usa el objeto PendingIntent que creaste en el paso anterior como parte de la compilación de tu notificación

A fin de identificar el origen de la actividad, por ejemplo, para realizar registros, usa valores adicionales cuando publiques la notificación. Para el registro centralizado, usa ActivityLifecycleCallbacks o los observadores del ciclo de vida de Jetpack.

Activa o desactiva el comportamiento

Cuando pruebas tu app durante la Vista previa para desarrolladores, puedes habilitar o inhabilitar esta restricción con la marca de compatibilidad de apps de NOTIFICATION_TRAMPOLINE_BLOCK.

Copia de seguridad y restablecimiento

En Android 12, se cambia la manera en que funcionan la copia de seguridad y el restablecimiento en apps que se ejecutan en Android 12 o versiones posteriores y que se orientan a estas. Para obtener más información, consulta Cambios en copias de seguridad y restablecimiento.

Conectividad

Conexión simultánea a Internet y entre pares

A partir de Android 12, los dispositivos compatibles con conexiones simultáneas a Internet y entre pares pueden mantener conexiones Wi-Fi simultáneas en el dispositivo de intercambio de tráfico y la red principal de Internet, lo que permite que la experiencia del usuario sea más fluida. Esta función se habilita automáticamente para todas las apps que se orientan al nivel de API 31 y versiones posteriores. Las apps que se orientan a niveles de API inferiores todavía experimentan el comportamiento heredado, en el que la red Wi-Fi principal se desconecta antes de conectarse al dispositivo de intercambio de tráfico.

Compatibilidad

WifiManager.getConnectionInfo() puede mostrar WifiInfo para una sola red. Como consecuencia, en Android 12, el comportamiento de la API se modificó de las siguientes maneras:

  • Si solo hay una red Wi-Fi disponible, se mostrará WifiInfo.
  • Si hay más de una red Wi-Fi disponible y la app que realiza la llamada activó una conexión entre pares, se muestra el objeto WifiInfo que corresponde al dispositivo de intercambio de tráfico.
  • Si hay más de una red Wi-Fi disponible y la app que realiza la llamada no activó una conexión entre pares, se muestra el objeto WifiInfo de la conexión principal de Internet.

Con el fin de ofrecer una mejor experiencia del usuario en dispositivos compatibles con redes Wi-Fi simultáneas de doble banda, recomendamos que todas las apps, en especial las que activan conexiones entre pares, migren para evitar llamar a WifiManager.getConnectionInfo(). En su lugar, usa NetworkCallback.onCapabilitiesChanged() a fin de obtener todos los objetos WifiInfo que coincidan con el objeto NetworkRequest que se usa para registrar NetworkCallback. A partir de Android 12, getConnectionInfo() dejó de estar disponible.

En la siguiente muestra de código, se observa cómo obtener WifiInfo en NetworkCallback:

Kotlin

val networkCallback = object : ConnectivityManager.NetworkCallback() {
  ...
  override fun onCapabilitiesChanged(
           network : Network,
           networkCapabilities : NetworkCapabilities) {
    val transportInfo = networkCapabilities.getTransportInfo()
    if (transportInfo !is WifiInfo) return
    val wifiInfo : WifiInfo = transportInfo
    ...
  }
}

Java

final NetworkCallback networkCallback = new NetworkCallback() {
  ...
  @Override
  public void onCapabilitiesChanged(
         Network network,
         NetworkCapabilities networkCapabilities) {
    final TransportInfo transportInfo = networkCapabilities.getTransportInfo();
    if (!(transportInfo instanceof WifiInfo)) return;
    final WifiInfo wifiInfo = (WifiInfo) transportInfo;
    ...
  }
  ...
};

Habilita la pantalla apagada para pagos mediante NFC

En las apps que se orientan a Android 12 y versiones posteriores, puedes habilitar los pagos mediante NFC sin que la pantalla del dispositivo esté encendida. Para ello, configura requireDeviceScreenOn en false. Para obtener más información sobre los pagos mediante NFC con la pantalla apagada o bloqueada, consulta Pantalla apagada y comportamiento de pantalla de bloqueo.

Bibliotecas de proveedores

Bibliotecas nativas compartidas que proporcionan los proveedores

De forma predeterminada, no se puede acceder a las bibliotecas nativas compartidas que no pertenecen al NDK que proporcionan proveedores de silicio o fabricantes de dispositivos si la app se orienta a Android 12 o versiones posteriores. Solo se puede acceder a las bibliotecas cuando se solicitan de manera explícita con la etiqueta <uses-native-library>.

Si la app se orienta a Android 11 o versiones anteriores, no se requiere la etiqueta <uses-native-library>. En ese caso, se puede acceder a cualquier biblioteca nativa compartida, independientemente de si es una biblioteca de NDK.

Actualización de restricciones que no pertenecen al SDK

Android 12 incluye listas actualizadas de este tipo de interfaces que están basadas en la colaboración con desarrolladores de Android y las pruebas internas más recientes. Siempre que sea posible, nos aseguramos de que las alternativas públicas estén disponibles antes de restringir las interfaces que no pertenecen al SDK.

Si tu app no está orientada a Android 12, es posible que algunos de estos cambios no te afecten de inmediato. Sin embargo, aunque actualmente puedes usar algunas interfaces que no pertenecen al SDK (según el nivel de API al que esté orientada la app), utilizar cualquier método o campo que no pertenezca al SDK siempre implica un gran riesgo de error para tu app.

En caso de no saber con certeza si tu app usa este tipo de interfaces, puedes probarla para verificarlo. Si tu app depende de interfaces que no pertenezcan al SDK, deberías planificar una migración hacia otras alternativas que sí lo hagan. Sin embargo, sabemos que algunas apps tienen casos prácticos válidos para usarlas. Si no encuentras una alternativa al uso de una interfaz que no pertenece al SDK para una función de tu app, deberías solicitar una nueva API pública.

Para obtener más información sobre los cambios implementados en esta versión de Android, consulta Actualizaciones a las restricciones de interfaces que no pertenecen al SDK en Android 12. Para obtener más información sobre interfaces que no pertenecen al SDK en general, consulta Restricciones en interfaces que no pertenecen al SDK.