Los errores ANR de Unity ocurren por varios motivos. Los errores de ANR más comunes se deben al uso inadecuado de los componentes de Android y Unity, y a la falta de comunicación entre ellos.
WebView
WebView
es una clase de Android que muestra páginas web. Los SDKs de terceros (como los de anuncios) usan WebView
para mostrar contenido web dinámico en actividades que no sean UnityPlayerActivity
. Los errores de ANR se producen cuando los SDKs de terceros usan de forma incorrecta WebView
.
Seguimiento de pila
El seguimiento de pila es el primer recurso que tienes para comprender la causa del error ANR.
/data/app/~~p-0ksfCD6bF6Sdq6kpVePg==/com.google.android.webview-5YQZOqKbbqp-uoLY6WYnTw==/base.apk!libmonochrome.so
at J.N.Mhc_M_H$ (Native method)
at org.chromium.components.viz.service.frame_sinks.ExternalBeginFrameSourceAndroid.doFrame (chromium-TrichromeWebViewGoogle.aab-stable-579013831:60)
at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1054)
at android.view.Choreographer.doCallbacks (Choreographer.java:878)
at android.view.Choreographer.doFrame (Choreographer.java:807)
at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1041)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:223)
at android.app.ActivityThread.main (ActivityThread.java:7721)
at java.lang.reflect.Method.invoke (Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:952)
Figura 1: Seguimiento de pila de ANR causado por una espera de futex
Causa
Hasta el momento, no está clara la causa raíz de este problema. Estas son algunas causas posibles:
- Implementación de anuncios inapropiada
- Una versión desactualizada de
WebView
, ya que es posible que el usuario haya optado por no actualizar la app automáticamente. - Uso alto de recursos del sistema (CPU, GPU, etcétera), lo que puede requerir una gran cantidad de generación de perfiles
- Se producen fallas en la compilación de sombreadores, lo que podría indicar que el contenido tiene un sombreador incompatible o que el usuario tiene instalada una versión anterior de
WebView
.
Solución
- Para determinar qué tipo de contenido está provocando que
WebView
bloquee el subproceso principal, agrega registros a tu juego cada vez que se cargue, muestre o cierre una página web.- Puedes usar los servicios de informes de Backtrace o Crashlytics.
- Luego, después de analizar los datos y encontrar el problema, intenta inhabilitar los proveedores de anuncios problemáticos.
- Incluye registros de memoria para asegurarte de que el problema no esté relacionado con la memoria.
- Alerta al usuario para que actualice
WebView
desde Google Play. A partir de Android 5.0 (nivel de API 21) y versiones posteriores,WebView
se trasladó a un APK. Por lo tanto, se puede actualizar por separado de la plataforma de Android. Para ver qué versión deWebView
se usa en un dispositivo, ve a Configuración > Apps > Android System WebView y busca la versión en la parte inferior de la página.

WebView
.Pausa de Unity
Cuando UnityPlayerActivity
recibe una llamada a onPause()
, se inicia la siguiente cadena de operaciones:
UnityPlayerActivity
notifica al motor de tiempo de ejecución de Unity que la actividad se pausó.- Unity llama a cada
MonoBehaviour
que implementa el eventoOnApplicationPause
. - Unity detiene sus componentes y módulos, como la reproducción de sonido, la renderización, el bucle de juego y la animación.
- Para asegurarse de que tanto
Unity Android Player
(UAP) como el motor estén sincronizados, el UAP espera 4 segundos a que se detenga el motor. - Si esa operación tarda más de 5 segundos, el sistema activa un ANR.
Seguimiento de pila
"main" tid=1 Timed Waiting
jdk.internal.misc.Unsafe.park (Native method)
java.util.concurrent.locks.LockSupport.parkNanos (LockSupport.java:234)
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos (AbstractQueuedSynchronizer.java:1079)
java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos (AbstractQueuedSynchronizer.java:1369)
java.util.concurrent.Semaphore.tryAcquire (Semaphore.java:415)
com.unity3d.player.UnityPlayer.pauseUnity (UnityPlayer.java:833)
com.unity3d.player.UnityPlayer.pause (UnityPlayer.java:796)
com.unity3d.player.UnityPlayerActivity.onPause (UnityPlayerActivity.java:117)
android.app.Activity.performPause (Activity.java:8517)
android.app.Instrumentation.callActivityOnPause (Instrumentation.java:1618)
android.app.ActivityThread.performPauseActivityIfNeeded (ActivityThread.java:5061)
android.app.ActivityThread.performPauseActivity (ActivityThread.java:5022)
android.app.ActivityThread.handlePauseActivity (ActivityThread.java:4974)
android.app.servertransaction.PauseActivityItem.execute (PauseActivityItem.java:48)
android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
android.app.servertransaction.TransactionExecutor.executeLifecycleState (TransactionExecutor.java:179)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:97)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2303)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:201)
android.os.Looper.loop (Looper.java:288)
android.app.ActivityThread.main (ActivityThread.java:7884)
java.lang.reflect.Method.invoke (Native method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:936)
Figura 3: La ANR se debe a un semáforo que nunca se libera.
Solución
Asegúrate de que el código del juego en C# no tarde demasiado en finalizar la ejecución durante un evento de pausa o reanudación.
- Crea un perfil de tu juego y verifica si
OnApplicationPause
es una operación costosa. Puedes usar un objetoStopwatch
. - Evita las operaciones de E/S o las solicitudes de red síncronas.
- Mueve las operaciones a otro
Thread
conTask
. Unity 2023.1 admite un modelo de programación asíncrona simplificado con las palabras claveasync
yawait
de C#.
Se bloqueó UnitySendMessage
Los complementos y SDKs de Java Unity envían datos a la capa de juego de C# con JNI. Sin embargo, esta comunicación podría bloquear el subproceso principal debido a una rutina de sincronización nativa, como una exclusión mutua, lo que provocaría un error de ANR debido a la contención de bloqueo.
Seguimiento de pila
El ANR de la figura 4 se debió a una operación prolongada en el código C# llamado por un complemento de Java. El motor de Unity usa un mutex de herencia sin prioridad para garantizar una ejecución correcta.
libc.so NonPI::MutexLockWithTimeout(pthread_mutex_internal_t*, bool, timespec const*) + 604
com.unity3d.player.UnityPlayer.nativeUnitySendMessage (Native method)
com.unity3d.player.UnityPlayer.UnitySendMessage (UnityPlayer.java:665)
Figura 4 ANR causada por una contención de bloqueo.
Causa
El problema es que se envían varios mensajes cuando se reanuda la aplicación. Los mensajes se ponen en cola porque no se pueden enviar mientras el juego se ejecuta en segundo plano. Todos los mensajes se envían simultáneamente cuando se reanuda la app.
Durante un período de pausa, generalmente almacenas la información del juego en el servidor. Por ejemplo, registras la posición de un jugador en el juego para que pueda volver al mismo lugar cuando se reanude.
Esta carga de trabajo, combinada con otro código de terceros que crea su propia carga de trabajo, puede sobrecargar los recursos del dispositivo, en particular el subproceso principal. El subproceso principal ejecuta la interfaz de usuario de una app y, a menudo, es la ubicación principal de los errores de ANR. Por lo tanto, cualquier carga de trabajo adicional en el subproceso principal aumenta la posibilidad de que se produzca un error de ANR.
Solución
Durante una pausa de la aplicación, asegúrate de que todas las acciones de código sean necesarias o intenta guardar el estado del usuario en la memoria local del dispositivo. Y, por supuesto, ver si también puedes completar estas acciones fuera del período de pausa.
Algunos enfoques:
- Mueve la operación en C# que controla un mensaje a un subproceso que no sea el principal.
- Si tu código no depende del contexto del subproceso principal de Unity, usa
Task
para la comunicación en lugar de un mensaje.
- Si tu código no depende del contexto del subproceso principal de Unity, usa
- No envíes varios mensajes desde tu complemento cuando el juego esté en pausa.
- El motor no puede enviar mensajes mientras el juego se ejecuta en segundo plano.
- Solo envía el último estado de los datos a tu juego si eso no afecta su funcionalidad.
Referente de instalación
Play Install Referrer es una cadena única que se envía a Play Store cada vez que un usuario hace clic en un anuncio. Es un identificador de seguimiento de anuncios específico para Android. Una vez instalada, la app envía el referente de instalación al socio de atribución, que correlaciona la fuente con la instalación (atribuyendo la conversión).
Seguimiento de pila
En la figura 5, se muestra un registro de seguimiento de la pila de un ANR de un juego que usa el SDK de Facebook para recuperar la atribución de la instalación.

Causa
El error de ANR se debió a una llamada a Binder lenta. Sin embargo, no se puede determinar la causa raíz sin acceso al código fuente del SDK.
Solución
Resolver este tipo de problemas implica comunicarse con el desarrollador del SDK o buscar mucho en línea una posible solución, verificar si una versión más reciente del SDK resuelve el error de ANR para otros o incluso experimentar con una pequeña estrategia de lanzamiento.
Google proporciona una página del Índice SDK que combina los datos de uso de las apps de Google Play con la información recopilada a través de la detección de código para proporcionar indicadores y atributos diseñados con el objetivo de ayudarte a decidir entre adoptar, mantener o quitar un SDK de tu app.
Recursos adicionales
Para obtener más información sobre los ANR, consulta los siguientes recursos:
- Cómo depurar errores de ANR: Desarrollo de juegos para Android
- ANR: Calidad de la app