ANRs in Unity können verschiedene Ursachen haben. Die häufigsten ANRs werden durch die falsche Verwendung von Android- und Unity-Komponenten und deren falsche Kommunikation verursacht.
WebView
WebView
ist eine Android-Klasse, mit der Webseiten angezeigt werden. Drittanbieter-SDKs (z. B. für Anzeigen) verwenden WebView
, um dynamische Webinhalte in anderen Aktivitäten als der UnityPlayerActivity
anzuzeigen. ANRs treten auf, wenn Drittanbieter-SDKs WebView
missbrauchen.
Stacktrace
Der Stacktrace ist Ihre erste Anlaufstelle, um die Ursache des ANR-Fehlers zu ermitteln.
/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)
Abbildung 1. ANR-Stacktrace, der durch einen futex-Wartevorgang verursacht wurde.
Ursache
Bisher ist die Ursache dieses Problems unklar. Mögliche Ursachen:
- Schlechte Anzeigenimplementierung
- Eine veraltete Version von
WebView
, da der Nutzer die automatische Aktualisierung der App möglicherweise deaktiviert hat. - Hohe Nutzung von Systemressourcen (CPU, GPU usw.), die möglicherweise viel Profiling erfordert.
- Shader-Kompilierung stürzt ab. Das kann darauf hindeuten, dass der Inhalt einen inkompatiblen Shader enthält oder dass der Nutzer eine alte
WebView
-Version installiert hat.
Lösung
- Um herauszufinden, welche Art von Inhalten dazu führt, dass
WebView
den Hauptthread blockiert, fügen Sie Ihrem Spiel Logs hinzu, wenn eine Webseite geladen, angezeigt oder geschlossen wird.- Sie können die Berichterstellungsdienste Backtrace oder Crashlytics verwenden.
- Nachdem Sie die Daten analysiert und das Problem gefunden haben, deaktivieren Sie die betreffenden Anzeigenanbieter.
- Fügen Sie Arbeitsspeicherprotokolle hinzu, um sicherzustellen, dass das Problem nicht mit dem Arbeitsspeicher zusammenhängt.
- Den Nutzer auffordern, die
WebView
über Google Play zu aktualisieren. Ab Android 5.0 (API-Level 21) istWebView
in ein APK verschoben worden. Daher kann sie unabhängig von der Android-Plattform aktualisiert werden. Wenn Sie sehen möchten, welche Version vonWebView
auf einem Gerät verwendet wird, rufen Sie Einstellungen > Apps > Android System WebView auf und sehen Sie sich die Version unten auf der Seite an.

WebView
-Version.Unity-Pause
Wenn UnityPlayerActivity
einen onPause()
-Aufruf empfängt, wird die folgende Kette von Vorgängen gestartet:
UnityPlayerActivity
benachrichtigt die Unity-Laufzeit-Engine, dass die Aktivität pausiert wurde.- Unity ruft jedes
MonoBehaviour
auf, das das EreignisOnApplicationPause
implementiert. - Unity stoppt seine Komponenten und Module, z. B. die Soundwiedergabe, das Rendern, die Spielschleife und die Animation.
- Damit sowohl
Unity Android Player
(UAP) als auch die Engine synchronisiert werden, wartet das UAP 4 Sekunden, bis die Engine stoppt. - Wenn dieser Vorgang länger als 5 Sekunden dauert, löst das System einen ANR aus.
Stacktrace
"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)
Abbildung 3: ANR, der durch ein Semaphor verursacht wird, das nie freigegeben wird.
Lösung
Achten Sie darauf, dass die Ausführung Ihres C#-Spielcodes bei einem Pausen- oder Fortsetzungsereignis nicht zu lange dauert.
- Profilieren Sie Ihr Spiel und prüfen Sie, ob
OnApplicationPause
ein ressourcenintensiver Vorgang ist. Sie können einenStopwatch
verwenden. - Vermeiden Sie E/A-Vorgänge oder synchrone Netzwerkanfragen.
- Verschieben Sie die Vorgänge mit
Task
in eine andereThread
. Unity 2023.1 unterstützt ein vereinfachtes asynchrones Programmiermodell mit den C#-Schlüsselwörternasync
undawait
.
„UnitySendMessage“ blockiert
Java-Unity-Plug-ins und ‑SDKs senden Daten über JNI an die C#-Spielebene. Diese Kommunikation kann jedoch den Hauptthread aufgrund einer nativen Synchronisierungsroutine wie einem Mutex blockieren und so einen ANR-Fehler aufgrund von Sperrenkonflikten verursachen.
Stacktrace
Die ANR in Abbildung 4 wurde durch einen langen Vorgang im C#-Code verursacht, der von einem Java-Plug-in aufgerufen wurde. Die Unity-Engine verwendet einen Mutex ohne Prioritätsvererbung, um die korrekte Ausführung zu gewährleisten.
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)
Abbildung 4: ANR verursacht durch einen Konflikt um eine Sperre.
Ursache
Das Problem besteht darin, dass beim Fortsetzen der Anwendung mehrere Nachrichten gesendet werden. Die Nachrichten werden in die Warteschlange gestellt, da sie nicht gesendet werden können, während das Spiel im Hintergrund läuft. Die Nachrichten werden alle gleichzeitig gesendet, wenn die App fortgesetzt wird.
Während einer Pause werden die Informationen Ihres Spiels in der Regel auf dem Server gespeichert. So wird beispielsweise die Position eines Spielers im Spiel aufgezeichnet, damit er nach der Fortsetzung des Spiels an dieselbe Stelle zurückkehren kann.
Diese Arbeitslast kann in Kombination mit anderem Drittanbietercode, der eine eigene Arbeitslast erstellt, die Ressourcen des Geräts überlasten, insbesondere den Hauptthread. Im Hauptthread wird die Benutzeroberfläche einer App ausgeführt. ANR-Fehler treten häufig dort auf. Jede zusätzliche Arbeitslast im Hauptthread erhöht also das Risiko für einen ANR.
Lösung
Achten Sie während einer App-Pause darauf, dass alle Ihre Codeaktionen erforderlich sind, oder versuchen Sie, den Status des Nutzers im lokalen Gerätespeicher zu speichern. Prüfen Sie natürlich auch, ob Sie diese Aktionen außerhalb des Pausenzeitraums ausführen können.
Einige Ansätze:
- Verschieben Sie den C#-Vorgang, der eine Nachricht verarbeitet, in einen anderen Thread als den Hauptthread.
- Wenn Ihr Code nicht vom Hauptthread-Kontext von Unity abhängt, verwenden Sie
Task
anstelle von „message“ für die Kommunikation.
- Wenn Ihr Code nicht vom Hauptthread-Kontext von Unity abhängt, verwenden Sie
- Senden Sie nicht mehrere Nachrichten von Ihrem Plug-in, wenn das Spiel pausiert ist.
- Die Engine kann keine Nachrichten senden, während das Spiel im Hintergrund läuft.
- Senden Sie nur den letzten Datenstatus an Ihr Spiel, wenn dies die Spielfunktionalität nicht beeinträchtigt.
Install Referrer
Play Install Referrer ist ein eindeutiger String, der an den Play Store gesendet wird, wenn ein Nutzer auf eine Anzeige klickt. Es handelt sich um eine Android-spezifische Kennung für das Anzeigen-Tracking. Nach der Installation sendet die App den Installations-Referrer an den Attributionspartner, der die Quelle mit der Installation abgleicht und die Conversion zuordnet.
Stacktrace
Abbildung 5 zeigt einen ANR-Stacktrace aus einem Spiel, in dem das Facebook-SDK verwendet wird, um die Installationszuordnung abzurufen.

Ursache
Der ANR wurde durch einen langsamen Binder-Aufruf verursacht. Die Ursache kann jedoch nicht ohne Zugriff auf den SDK-Quellcode ermittelt werden.
Lösung
Um diese Art von Problem zu beheben, müssen Sie sich mit dem SDK-Entwickler in Verbindung setzen oder im Internet nach einer möglichen Lösung suchen. Außerdem sollten Sie prüfen, ob eine neuere Version des SDKs den ANR-Fehler für andere behebt, oder sogar eine kleine Einführung durchführen.
Google bietet eine SDK Index-Seite, auf der Nutzungsdaten aus Google Play-Apps mit per Codeerkennung erfassten Informationen kombiniert werden. So werden Ihnen Attribute und Signale geboten, mit deren Hilfe Sie entscheiden können, ob Sie ein SDK einführen, behalten oder aus Ihrer App entfernen möchten.
Zusätzliche Ressourcen
Weitere Informationen zu ANRs finden Sie in den folgenden Ressourcen:
- ANR-Fehler beheben – Android-Spiele entwickeln
- ANRs – App-Qualität