Unity-ANR-Fehler können aus verschiedenen Gründen auftreten. Die häufigsten ANR-Fehler werden durch den Missbrauch von Android- und Unity-Komponenten und deren Missverständnisse verursacht.
WebView
WebView
ist eine Android-Klasse, in der Webseiten angezeigt werden. Drittanbieter-SDKs (z. B. Anzeigen) verwenden WebView
, um dynamische Webinhalte in anderen Aktivitäten als UnityPlayerActivity
anzuzeigen. ANR-Fehler treten auf, wenn WebView
von Drittanbieter-SDKs missbraucht wird.
Stacktrace
Der Stacktrace ist Ihre erste Möglichkeit, die Ursache des ANR-Fehlers zu verstehen.
/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 eine Futex-Wartezeit verursacht wird.
Ursache
Bislang ist die Ursache dieses Problems unklar. Mögliche Ursachen sind:
- Schlechte Anzeigenimplementierung
- Eine veraltete Version von
WebView
, da der Nutzer sich möglicherweise dafür entschieden hat, die App nicht automatisch zu aktualisieren. - Hohe Nutzung von Systemressourcen (CPU, GPU usw.), die möglicherweise ein hohes Maß an Profilerstellung erfordert.
- Die Shader-Kompilierung stürzt ab. Dies kann darauf hindeuten, dass der Inhalt einen inkompatiblen Shader hat oder der Nutzer eine alte
WebView
-Version installiert hat.
Die Lösung
- Wenn Sie eingrenzen möchten, welche Inhaltstypen dazu führen, dass
WebView
den Hauptthread blockiert, fügen Sie Ihrem Spiel immer dann Logs hinzu, wenn eine Webseite geladen, angezeigt oder geschlossen wird.- Sie können die Berichtsdienste Backtrace oder Crashlytics verwenden.
- Wenn Sie die Daten analysiert und das Problem gefunden haben, können Sie versuchen, die betroffenen Anzeigenanbieter zu deaktivieren.
- Fügen Sie Arbeitsspeicherprotokolle hinzu, um sicherzustellen, dass das Problem nicht mit dem Arbeitsspeicher zusammenhängt.
- Benachrichtigen Sie den Nutzer, die
WebView
in Google Play zu aktualisieren.WebView
wurde von Android 5.0 (API-Level 21) und höher in ein APK verschoben. Daher kann es unabhängig von der Android-Plattform aktualisiert werden. Wenn du wissen möchtest, welche Version vonWebView
auf einem Gerät verwendet wird, gehe zu Einstellungen > Apps > Android-System-WebView und sieh dir unten auf der Seite die Version an.
![App-Infobildschirm mit den WebView-Versionen](https://cdn.statically.io/img/developer.android.com/static/images/games/engines/unity/unity-anrs-list-webview-version.png?hl=de)
WebView
-Version.Unity-Pause
Wenn UnityPlayerActivity
einen onPause()
-Aufruf empfängt, wird die folgende Vorgangskette gestartet:
UnityPlayerActivity
benachrichtigt die Unity-Laufzeit-Engine, dass die Aktivität angehalten wurde.- Unity ruft alle
MonoBehaviour
auf, in denen das EreignisOnApplicationPause
implementiert ist. - Unity stoppt seine Komponenten und Module wie die Tonwiedergabe, das Rendering, die Spielschleife und die Animation.
- Damit sowohl
Unity Android Player
(UAP) als auch die Suchmaschine synchronisiert werden, wartet das UAP 4 Sekunden, bis die Suchmaschine abgeschaltet wird. - Wenn dieser Vorgang länger als 5 Sekunden dauert, löst das System einen ANR-Fehler 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-Fehler aufgrund einer nie veröffentlichten Semaphore.
Die Lösung
Achten Sie darauf, dass die Ausführung des C#-Spielcodes während eines Pausen- oder Fortsetzungsereignisses nicht zu lange dauert.
- Erstellen Sie ein Profil für Ihr Spiel und prüfen Sie, ob
OnApplicationPause
ein teurer Vorgang ist. Sie können einenStopwatch
verwenden. - Vermeiden Sie E/A-Vorgänge oder synchrone Netzwerkanfragen.
- Verschieben Sie die Vorgänge mithilfe von
Task
in ein anderesThread
. Unity 2023.1 unterstützt ein vereinfachtes asynchrones Programmiermodell mit den C#-Keywordsasync
undawait
.
UnitySendMessage blockiert
Java Unity-Plug-ins und -SDKs senden Daten mithilfe von JNI an die C#-Spieleebene. Diese Kommunikation kann jedoch den Hauptthread aufgrund einer nativen Synchronisierungsroutine wie einem Mutex blockieren, was zu einem ANR-Fehler aufgrund von Sperrkonflikten führt.
Stacktrace
Der ANR-Fehler in Abbildung 4 wurde durch einen langen Vorgang im C#-Code verursacht, der von einem Java-Plug-in aufgerufen wird. Die Unity-Engine verwendet einen Vererbungs-Mutex ohne Priorität, 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-Fehler aufgrund eines Sperrkonflikts.
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 Anwendung fortgesetzt wird.
Während einer Pause speichern Sie in der Regel die Informationen zu Ihrem Spiel auf dem Server. Zum Beispiel erfassen Sie die Position eines Spielers im Spiel, damit der Spieler wieder dorthin zurückkehren kann, wenn das Spiel fortgesetzt wird.
Diese Arbeitslast kann in Kombination mit anderem Drittanbietercode, der eine eigene Arbeitslast erstellt, die Ressourcen des Geräts, insbesondere den Hauptthread, überlasten. Der Hauptthread führt die Benutzeroberfläche einer Anwendung aus und ist oft der Hauptort von ANR-Fehlern. Jede zusätzliche Arbeitslast im Hauptthread erhöht also das Risiko eines ANR-Fehlers.
Die Lösung
Prüfe, ob während einer App-Pause alle Codeaktionen erforderlich sind, oder versuche, den Status des Nutzers im lokalen Gerätespeicher zu speichern. Und natürlich prüfen Sie, ob Sie diese Aktionen auch 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 Kontext des Hauptthreads von Unity abhängt, verwenden Sie
Task
für die Kommunikation anstelle von Nachrichten.
- Wenn Ihr Code nicht vom Kontext des Hauptthreads von Unity abhängt, verwenden Sie
- Senden Sie nicht mehrere Nachrichten über Ihr Plug-in, wenn das Spiel pausiert ist.
- Während das Spiel im Hintergrund läuft, kann die Engine keine Nachrichten senden.
- Senden Sie den letzten Datenstatus nur dann an Ihr Spiel, wenn dies keine Auswirkungen auf die Funktionalität Ihres Spiels hat.
Verweis-URL installieren
Die Play Install Referrer ist ein eindeutiger String, der jedes Mal an den Play Store gesendet wird, wenn ein Nutzer auf eine Anzeige klickt. Es ist eine Android-spezifische ID für das Anzeigen-Tracking. Nach der Installation sendet die App die Installationsreferenz an den Attributionspartner, der die Quelle mit der Installation (und der Conversion zuordnet) gleicht.
Stacktrace
Abbildung 5 zeigt einen ANR-Stacktrace eines Spiels, das das Facebook SDK zum Abrufen der Attribution der Installationen verwendet.
![](https://cdn.statically.io/img/developer.android.com/static/images/games/engines/unity/unity-anrs-list-binder.png?hl=de)
Ursache
Der ANR-Fehler wurde durch einen langsamen Binder-Aufruf verursacht. Die Ursache kann jedoch nicht ohne Zugriff auf den SDK-Quellcode ermittelt werden.
Die Lösung
Um diese Art von Problem zu lösen, müssen Sie mit dem SDK-Entwickler kommunizieren oder online nach einer potenziellen Lösung suchen, prüfen, ob eine neuere Version des SDK den ANR-Fehler für andere behebt, oder sogar mit einer kleinen Rollout-Strategie experimentieren.
Google bietet eine SDK-Index-Seite, auf der Nutzungsdaten aus Google Play-Apps mit Informationen kombiniert werden, die durch die Codeerkennung erfasst wurden. Sie enthalten Attribute und Signale, die Ihnen bei der Entscheidung helfen, ob Sie ein SDK verwenden, behalten oder aus Ihrer App entfernen möchten.
Zusätzliche Ressourcen
Weitere Informationen zu ANR-Fehlern finden Sie in den folgenden Ressourcen:
- ANR-Fehler beheben – Android-Spieleentwicklung
- ANRs – App-Qualität