A partir de Android 9 (nivel de API 28), la plataforma restringe las interfaces no pertenecientes al SDK que se pueden usar en tu app. Estas restricciones se aplican cada vez que una app hace referencia a una interfaz que no pertenece al SDK o intenta obtener su controlador mediante reflejo o JNI, y se implementaron para ayudar a mejorar la experiencia del usuario y el desarrollador, lo cual se traduce en menos riesgos de fallas para los usuarios y menos lanzamientos de emergencia para los desarrolladores. Si quieres obtener más información acerca de esta decisión, consulta el artículo sobre cómo reducir el uso de interfaces que no pertenecen al SDK para mejorar la estabilidad.
Cómo diferenciar entre las interfaces que pertenecen al SDK y las que no
En general, las interfaces públicas del SDK son aquellas que están documentadas en el Índice del paquete del framework de Android. El control de las interfaces que no pertenecen al SDK es un detalle de la implementación que abstrae la API, de manera que están sujetas a cambios sin previo aviso.
Para evitar que se produzcan fallas y comportamientos inesperados, las apps deben utilizar únicamente las partes de las clases documentadas oficialmente en el SDK. Esta premisa también significa que no debes acceder a métodos o campos que no aparezcan en el SDK cuando interactúas con una clase usando mecanismos como el reflejo.
Listas de API que no pertenecen al SDK
Con cada versión de Android, se restringen interfaces adicionales que no pertenecen al SDK. Sabemos que estas restricciones pueden afectar el flujo de trabajo de tus actualizaciones y queremos asegurarnos de que poseas las herramientas necesarias para detectar el uso de interfaces que no pertenecen al SDK, tengas la oportunidad de brindarnos comentarios y cuentes con tiempo para planificar y adaptarte a las nuevas políticas.
Con el objetivo de minimizar el impacto de las restricciones para las interfaces que no pertenecen al SDK en el flujo de trabajo de desarrollo, estos tipos de vistas se dividen en listas que definen el grado de restricción de uso en función del nivel de la API al que está orientada tu app. En la siguiente tabla, se describen estas listas:
Lista | Etiquetas de código | Descripción |
---|---|---|
Lista de entidades bloqueadas |
|
Incluye interfaces que no pertenecen al SDK y que no puedes usar, sin importar el nivel de API objetivo de la app. Si tu app intenta acceder a una de estas interfaces, se generará un error en el sistema. |
Entidades bloqueadas de forma condicional |
|
A partir de Android 9 (nivel de API 28), cada nivel de API tiene interfaces que no pertenecen al SDK y se encuentran restringidas cuando una app se segmenta a ese nivel. Estas listas están etiquetadas según el nivel máximo de API ( Si tu app intenta acceder a una interfaz restringida para su nivel de API objetivo, el sistema se comporta como si la API fuera parte de la lista de entidades bloqueadas. |
No compatible |
|
Son interfaces que no pertenecen al SDK y que no tienen restricciones, por lo que la app puede usarlas. Sin embargo, ten en cuenta que estas interfaces no son compatibles y están sujetas a cambios sin previo aviso. Se espera que estas interfaces se bloqueen de forma condicional en versiones futuras de Android en una lista max-target-x . |
SDK |
|
Incluye interfaces que se pueden usar sin restricciones y se admiten como parte del Índice del paquete del framework de Android documentado oficialmente. |
APIs de prueba |
|
Interfaces que se usan para pruebas internas del sistema, como las APIs que facilitan las pruebas a través del Conjunto de pruebas de compatibilidad (CTS). Las APIs de prueba no forman parte del SDK. A partir de Android 11 (nivel de API 30), las APIs de prueba se incluyen en la lista de entidades bloqueadas, por lo que las apps no pueden usarlas, independientemente de su nivel de API objetivo. No todas las APIs de prueba son compatibles y están sujetas a cambios sin previo aviso, sin importar el nivel de API de la plataforma. |
Si bien puedes usar algunas interfaces que no pertenecen al SDK (según el nivel de API objetivo de tu app), usar cualquier método o campo que no pertenece al SDK siempre implica un gran riesgo de error para tu app. Si la app depende de interfaces que no pertenecen al SDK, debes comenzar a planificar una migración hacia interfaces de SDK o cualquier otra alternativa. 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.
Determina a qué lista pertenece una interfaz
Las listas de interfaces que no pertenecen al SDK se compilan como parte de la plataforma. Consulta las siguientes secciones para obtener información sobre cada versión de Android.
Android 15
En el caso de Android 15 (nivel de API 35), puedes descargar el siguiente archivo que describe todas las interfaces que no pertenecen al SDK y sus listas correspondientes:
Archivo: hiddenapi-flags.csv
Suma de comprobación SHA-256:
40134e205e58922a708c453726b279a296e6a1f34a988abd90cec0f3432ea5a9
Para obtener más información sobre los cambios en la lista de API que no pertenecen al SDK en Android 15, consulta Actualizaciones a las restricciones de interfaces que no pertenecen al SDK en Android 15.
Android 14
En el caso de Android 14 (nivel de API 34), puedes descargar el siguiente archivo que describe todas las interfaces que no pertenecen al SDK y sus listas correspondientes:
Archivo: hiddenapi-flags.csv
Suma de comprobación SHA-256:
7e00db074cbe51c51ff4b411f7b48e98692951395c5c17d069c822cc1d0eae0f
Para obtener más información sobre los cambios en la lista de APIs que no pertenecen al SDK en Android 14, consulta Actualizaciones a las restricciones de interfaces que no pertenecen al SDK en Android 14.
Android 13
En el caso de Android 13 (nivel de API 33), puedes descargar el siguiente archivo que describe todas las interfaces que no pertenecen al SDK y sus listas correspondientes:
Archivo: hiddenapi-flags.csv
Suma de comprobación SHA-256
233a277aa8ac475b6df61bffd95665d86aac6eb2ad187b90bf42a98f5f2a11a3
Para obtener más información sobre los cambios en la lista de API que no pertenecen al SDK en Android 13, incluidas las alternativas a la API pública sugeridas para las APIs que se bloquean de forma condicional en esa versión, consulta Actualizaciones a las restricciones de interfaces que no pertenecen al SDK en Android 13.
Android 12
En el caso de Android 12 (nivel de API 31), puedes descargar el siguiente archivo que describe todas las interfaces que no pertenecen al SDK y sus listas correspondientes:
Archivo: hiddenapi-flags.csv
Suma de comprobación SHA-256:
40674ff4291eb268f86561bf687e69dbd013df9ec9531a460404532a4ac9a761
Para obtener más información sobre los cambios en la lista de API que no pertenecen al SDK en Android 12, incluidas las alternativas a la API pública sugeridas para las APIs que se bloquean de forma condicional en esa versión, consulta Cambios de lista para Android 12.
Android 11
En el caso de Android 11 (nivel de API 30), puedes descargar el siguiente archivo que describe todas las interfaces que no pertenecen al SDK y sus listas correspondientes:
Archivo: hiddenapi-flags.csv
Suma de comprobación SHA-256:
a19d839f4f61dc9c94960ae977b2e0f3eb30f880ba1ffe5108e790010b477a56
Para obtener más información sobre los cambios en la lista de API que no pertenecen al SDK en Android 11, incluidas las alternativas a la API pública sugeridas para las APIs que se bloquean de forma condicional en esa versión, consulta Cambios de lista para Android 11.
Android 10
En el caso de Android 10 (nivel de API 29), puedes descargar el siguiente archivo que describe todas las interfaces que no pertenecen al SDK y sus listas correspondientes:
Archivo: hiddenapi-flags.csv
Suma de comprobación SHA-256:
f22a59c215e752777a114bd9b07b0b6b4aedfc8e49e6efca0f99681771c5bfeb
Para obtener más información sobre los cambios en la lista de API que no pertenecen al SDK en Android 10, incluidas las alternativas a la API pública sugeridas para las APIs que se bloquean de forma condicional en esa versión, consulta Cambios de lista para Android 10.
Android 9
En el caso de Android 9 (nivel de API 28), el siguiente archivo de texto contiene la lista de APIs que no pertenecen al SDK y que no están restringidas (incluidas en la lista gris): hiddenapi-light-greylist.txt
.
La lista de elementos bloqueados (blacklist
) y la lista de APIs bloqueadas de forma condicional (lista gris oscuro) se derivan cuando se procesa la compilación.
Cómo generar listas de AOSP
Cuando trabajas con AOSP, puedes generar un archivo hiddenapi-flags.csv
que contenga todas las interfaces que no pertenecen al SDK y sus listas correspondientes. Para ello, descarga la fuente de AOSP y, luego, ejecuta el siguiente comando:
m out/soong/hiddenapi/hiddenapi-flags.csv
Podrás encontrar el archivo en la siguiente ubicación:
out/soong/hiddenapi/hiddenapi-flags.csv
Comportamiento esperado cuando tu app accede a interfaces que no pertenecen al SDK y están restringidas
En la siguiente tabla, se describe el comportamiento que puedes esperar si tu app intenta acceder a una interfaz que no pertenece al SDK y forma parte de la lista de elementos bloqueados.
Método de acceso | Resultado |
---|---|
Instrucción de Dalvik que hace referencia a un campo | Se arroja NoSuchFieldError |
Instrucción de Dalvik que hace referencia a un método | Se arroja NoSuchMethodError |
Reflexión a través de Class.getDeclaredField() o Class.getField() |
Se arroja NoSuchFieldException |
Reflexión a través de Class.getDeclaredMethod() , Class.getMethod() |
Se arroja NoSuchMethodException |
Reflexión a través de Class.getDeclaredFields() , Class.getFields() |
Los miembros que no pertenecen al SDK no aparecen en los resultados |
Reflexión a través de Class.getDeclaredMethods() , Class.getMethods() |
Los miembros que no pertenecen al SDK no aparecen en los resultados |
JNI a través de env->GetFieldID() |
Se muestra NULL , se arroja NoSuchFieldError |
JNI a través de env->GetMethodID() |
Se muestra NULL , se arroja NoSuchMethodError |
Prueba la app para interfaces que no pertenecen al SDK
Existen varios métodos que puedes usar para probar las interfaces de tu app que no pertenecen al SDK.
Realiza pruebas con una app depurable
Puedes realizar pruebas para las interfaces que no pertenecen al SDK. Para ello, debes compilar y ejecutar una app depurable en un dispositivo o emulador que use Android 9 (nivel de API 28) o versiones posteriores. Asegúrate de que coincidan el nivel del dispositivo o emulador y el nivel de la API objetivo al que se orienta la app.
El sistema imprime un mensaje de registro si tu app accede a ciertas interfaces que no pertenecen al SDK mientras se está realizando la prueba. Puedes analizar los mensajes de registro de tu app en busca de los siguientes detalles:
- La clase, el nombre y el tipo de declaración (en el formato que se usa en el tiempo de ejecución de Android)
- El método de acceso, que puede ser a través de vinculación, reflejo o JNI
- La lista de la cual forma parte la interfaz que no pertenece al SDK
Puedes usar adb logcat
para acceder a estos mensajes de registro, que aparecen debajo del
PID de la app que está en ejecución. Por ejemplo, en el registro puede haber una entrada que diga lo siguiente:
Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)
Realiza pruebas con la API de StrictMode
Otra forma de probar las interfaces que no pertenecen al SDK es mediante la API de StrictMode
. Usa el método detectNonSdkApiUsage
para habilitar esa opción. Una vez que hayas habilitado la API de StrictMode
, podrás recibir una devolución de llamada para cada uso de una interfaz que no pertenece al SDK. Para ello, debes emplear un penaltyListener
, donde puedes implementar el control personalizado. El objeto Violation
que se proporciona en la devolución de llamada proviene de Throwable
, y el seguimiento de pila delimitado brinda el contexto de uso.
Realiza pruebas con la herramienta veridex
También puedes ejecutar la herramienta de análisis estático veridex en el APK. Esta utilidad analiza toda la base de código del APK, incluidas las bibliotecas de terceros y, además, informa los usos de las interfaces que no pertenecen al SDK que encuentra.
Estas son algunas de las limitaciones de la herramienta veridex:
- No detecta invocaciones mediante JNI.
- Puede detectar únicamente un subconjunto de invocaciones mediante reflejo.
- El análisis de rutas de acceso de códigos que se encuentren inactivas se limita a las verificaciones del nivel de la API.
- Solo se puede ejecutar en máquinas compatibles con instrucciones SSE4.2 y POPCNT.
Windows
No se proporcionan objetos binarios nativos de Windows, pero puedes utilizar la herramienta veridex en Windows ejecutando los objetos binarios de Linux con el Subsistema de Windows para Linux (WSL). Antes de seguir los pasos de esta sección, instala el WSL y elige Ubuntu como la distribución de Linux.
Después de instalar Ubuntu, inicia una terminal de Ubuntu y sigue estos pasos:
- Descarga la herramienta veridex del repositorio de compilaciones previas de tiempo de ejecución de Android.
- Extrae el contenido del archivo
appcompat.tar.gz
. - En la carpeta extraída, busca el archivo
veridex-linux.zip
y extráelo. Navega a la carpeta descomprimida y ejecuta el siguiente comando, donde
your-app.apk
es el APK que quieres probar:./appcompat.sh --dex-file=your-app.apk
macOS
Para ejecutar la herramienta veridex en macOS, sigue estos pasos:
- Descarga la herramienta veridex del repositorio de compilaciones previas de tiempo de ejecución de Android.
- Extrae el contenido del archivo
appcompat.tar.gz
. - En la carpeta extraída, busca el archivo
veridex-mac.zip
y extráelo. Navega a la carpeta descomprimida y ejecuta el siguiente comando, donde
/path-from-root/your-app.apk
es la ruta de acceso al APK que quieres probar. Comienza en el directorio raíz de tu sistema:./appcompat.sh --dex-file=/path-from-root/your-app.apk
Linux
Para ejecutar la herramienta veridex en Linux, sigue estos pasos:
- Descarga la herramienta veridex del repositorio de compilaciones previas de tiempo de ejecución de Android.
- Extrae el contenido del archivo
appcompat.tar.gz
. - En la carpeta extraída, busca el archivo
veridex-linux.zip
y extráelo. Navega a la carpeta descomprimida y ejecuta el siguiente comando, donde
your-app.apk
es el APK que quieres probar:./appcompat.sh --dex-file=your-app.apk
Realiza pruebas con la herramienta lint de Android Studio
Cada vez que compilas una app en Android Studio, la herramienta lint inspecciona el código para detectar posibles problemas. Si la app usa interfaces que no pertenecen al SDK, es posible que veas advertencias o errores de compilación, según la lista en la que estén incluidas esas interfaces.
También puedes ejecutar la herramienta lint desde la línea de comandos o ejecutar inspecciones de forma manual en un proyecto, carpeta o archivo específicos.
Realiza pruebas con Play Console
Cuando subes la app en un segmento de pruebas en Play Console, se realizan pruebas automáticamente para detectar posibles problemas, y se genera un informe previo al lanzamiento. Si la app usa interfaces que no pertenecen al SDK, se muestra un error o una advertencia en el informe previo al lanzamiento, en función de la lista en la que estén incluidas esas interfaces.
Para obtener más información, consulta la sección "Compatibilidad con Android" en Usa los informes previos al lanzamiento para identificar problemas.
Solicita una nueva API pública
Si no puedes encontrar una alternativa a usar una interfaz que no pertenece al SDK para una función de tu app, puedes crear una solicitud de función en nuestra Herramienta de seguimiento de errores para que se agregue una nueva API pública.
Cuando creas una solicitud de función, debes proporcionar la siguiente información:
- La API no compatible que usas, que incluye el descriptor completo que se ve en el mensaje de logcat
Accessing hidden ...
- El motivo por el cual necesitas usar estas APIs y detalles sobre la función de nivel superior para la cual necesitas la API, no solo los detalles de bajo nivel
- El motivo por el cual las APIs públicas relacionadas del SDK no satisfacen tu propósito
- Otras alternativas que hayas intentado y los motivos por los cuales no dieron buenos resultados
Si incluyes esta información en la solicitud de función, aumentarás las probabilidades de que se otorgue una nueva API pública.
Otras preguntas
En esta sección, se incluyen respuestas a otras preguntas frecuentes de los desarrolladores:
Preguntas generales
¿Cómo puede asegurarse Google de que podrá captar las necesidades de todas las apps a través del seguimiento de problemas?
Creamos listas iniciales para Android 9 (nivel de API 28) a través del análisis estático de las apps, el cual se complementó con los siguientes métodos:
- prueba manual de apps de Google Play y ajenas a esta plataforma
- informes internos
- recopilación automática de datos de los usuarios internos
- informes de vista previa para desarrolladores
- análisis estático adicional que se diseñó para incluir más falsos positivos de manera conservadora
Cuando evaluamos las listas para cada actualización nueva, tenemos en cuenta el uso de la API, así como los comentarios de los desarrolladores a través del seguimiento de problemas.
¿Cómo puedo habilitar el acceso a las interfaces que no pertenecen al SDK?
Puedes habilitar el acceso a estas interfaces en los dispositivos de desarrollo mediante el uso de comandos adb para cambiar la política de aplicación de la API. Los comandos que uses variarán según el nivel de API. Estos comandos no requieren un dispositivo con permisos de administrador.
- Android 10 (nivel de API 29) o una versión posterior
Para habilitar el acceso, usa el siguiente comando adb:
command:
adb shell settings put global hidden_api_policy 1
Para restablecer la política de aplicación de la API a la configuración original, usa el siguiente comando:
adb shell settings delete global hidden_api_policy
- Android 9 (nivel de API 28)
Para habilitar el acceso, usa los siguientes comandos adb:
adb shell settings put global hidden_api_policy_pre_p_apps 1
adb shell settings put global hidden_api_policy_p_apps 1
Para restablecer la configuración predeterminada de la política de aplicación de la API, usa los siguientes comandos:
adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps
Puedes elegir uno de los siguientes valores de número entero para la política de aplicación de la API:
- 0: Inhabilita toda la detección de interfaces que no pertenecen al SDK. Si usas esta configuración, se inhabilitarán todos los mensajes de registro para el uso de interfaces que no pertenecen al SDK y no podrás probar tu app con la API de
StrictMode
. Esta configuración no es recomendable. - 1: Habilita el acceso a todas las interfaces que no pertenecen al SDK, pero imprime mensajes de registro con advertencias para el uso de esas interfaces. El uso de esta configuración también te permite probar tu app con la API de
StrictMode
. - 2: Inhabilita el uso de interfaces que no pertenecen al SDK y forman parte de la lista de elementos bloqueados o que están bloqueadas de forma condicional para el nivel de API objetivo de la app.
Preguntas sobre las listas de interfaces que no pertenecen al SDK
¿Dónde puedo encontrar las listas de las APIs que no pertenecen al SDK en la imagen del sistema?
Están codificadas en el campo y en los bits de marcado de acceso al método en los archivos dex de la plataforma. No hay ningún archivo separado en la imagen del sistema que contenga estas listas.
¿Las listas de las APIs que no pertenecen al SDK son iguales en dispositivos de diferentes OEM que tienen la misma versión de Android?
Los OEM pueden agregar sus propias interfaces a la lista de elementos bloqueados (lista negra), pero no pueden quitar interfaces de las listas de API que no pertenecen al SDK de AOSP. El CDD evita esos cambios y las pruebas del CTS garantizan que el tiempo de ejecución de Android aplique la lista.
Preguntas sobre la compatibilidad de las apps relacionadas
¿Existen restricciones para las interfaces que no pertenecen al SDK en el código nativo?
El SDK de Android incluye interfaces de Java. La plataforma comenzó a restringir el acceso a las interfaces que no pertenecen al SDK para el código nativo C/C++ en Android 7 (nivel de API 26). Si quieres obtener más información, consulta el artículo sobre cómo mejorar la estabilidad con restricciones de símbolos C/C++ privados en Android N.
¿Existe algún plan para restringir la manipulación de archivos dex2oat o DEX?
No contamos con planes activos para restringir el acceso al objeto binario dex2oat, pero no es nuestra intención que el formato de archivo DEX sea estable o una interfaz pública más allá de las partes especificadas públicamente en el formato ejecutable Dalvik. Nos reservamos el derecho a modificar o eliminar dex2oat y las partes no especificadas del formato DEX en cualquier momento. Además, ten en cuenta que los archivos derivados producidos por dex2oat, como ODEX (también conocido como OAT), VDEX y CDEX son formatos no especificados.
¿Qué ocurre si un SDK importante de terceros (por ejemplo, un ofuscador) no puede evitar el uso de interfaces que no pertenecen al SDK, pero se compromete a mantener la compatibilidad con versiones futuras de Android? ¿Android puede hacer una excepción en cuanto a los requisitos de compatibilidad en esos casos?
No está en nuestros planes hacer excepciones relacionadas con los requisitos de compatibilidad por SDK. Si la compatibilidad de la app de un desarrollador de SDK depende únicamente de las interfaces que forman parte de las listas no admitidas (anteriormente "grises"), este deberá pensar en migrar a interfaces de SDK o alguna otra opción y solicitar una nueva API pública en caso de que no encuentre una alternativa al uso de este tipo de interfaz.
¿Las restricciones de las interfaces que no pertenecen al SDK se aplican a todas las apps (incluidas las de sistema y origen) y no solo a las apps de terceros?
Sí. Sin embargo, excluimos las apps firmadas con la clave de la plataforma y algunas apps
de imagen del sistema. Ten en cuenta que estas exenciones solo se aplican a las apps que forman parte de la imagen del sistema
(o a las apps de la imagen del sistema actualizadas). La lista está destinada solo para apps que
que se compilen con las API de plataformas privadas en lugar de las API de SDK (es decir,
LOCAL_PRIVATE_PLATFORM_APIS := true
).