ANR ของ Unity เกิดขึ้นด้วยเหตุผลหลายประการ ANR ที่พบบ่อยที่สุดเกิดจาก การใช้คอมโพเนนต์ Android และ Unity ในทางที่ผิด รวมถึงการสื่อสารที่ไม่ถูกต้อง
WebView
WebView
คือคลาส Android ที่แสดงหน้าเว็บ บุคคลที่สาม
SDK (เช่น โฆษณา) ใช้ WebView
เพื่อแสดงเนื้อหาเว็บแบบไดนามิก
ในกิจกรรมอื่นๆ นอกเหนือจาก UnityPlayerActivity
ANR เกิดขึ้นเมื่อบุคคลที่สาม
SDK ใช้ WebView
ในทางที่ผิด
สแต็กเทรซ
สแต็กเทรซคือทรัพยากรแรกที่คุณใช้เพื่อทำความเข้าใจสาเหตุของ 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)
รูปที่ 1 สแต็กเทรซ ANR ที่เกิดจากการรอของ futex
สาเหตุ
ขณะนี้ยังไม่ทราบสาเหตุที่แท้จริงของปัญหานี้ สาเหตุที่เป็นไปได้บางอย่างอาจ รวมข้อมูลต่อไปนี้
- การติดตั้งโฆษณาที่ไม่ดี
WebView
เวอร์ชันเก่าเนื่องจากผู้ใช้อาจเลือกที่จะไม่อัปเดต แอปโดยอัตโนมัติ- มีการใช้ทรัพยากรระบบสูง (CPU, GPU ฯลฯ) ซึ่งอาจต้องใช้ทรัพยากรจำนวนมาก การสร้างโปรไฟล์
- การคอมไพล์ Shader ขัดข้อง ซึ่งอาจชี้ให้เห็นว่า
เนื้อหามีตัวปรับแสงเงาที่ใช้ร่วมกันไม่ได้ หรือผู้ใช้มี
WebView
แบบเก่า เวอร์ชันที่ติดตั้ง
โซลูชัน
- หากต้องการจำกัดขอบเขตเนื้อหาที่ทําให้
WebView
บล็อก เทรดหลัก เพิ่มบันทึกในเกม เมื่อมีการโหลดหน้าเว็บ แสดง หรือปิดไป- คุณสามารถใช้ Backtrace หรือ Crashlytics บริการรายงาน
- จากนั้น เมื่อวิเคราะห์ข้อมูลและค้นหาปัญหาแล้ว ให้ลองปิดใช้ ผู้ให้บริการโฆษณาที่ไม่เหมาะสม
- แนบบันทึกหน่วยความจำเพื่อให้แน่ใจว่าปัญหานั้นไม่เกี่ยวข้องกับหน่วยความจำ
- แจ้งเตือนผู้ใช้ให้อัปเดต
WebView
จาก Google Play จาก Android 5.0 (API ระดับ 21) ขึ้นไปWebView
ได้ย้ายไปยัง APK แล้ว ดังนั้นจึงอาจ และได้รับการอัปเดตแยกจากแพลตฟอร์ม Android หากต้องการดูเวอร์ชันของWebView
กำลังใช้งานอยู่บนอุปกรณ์ ให้ไปที่การตั้งค่า > แอป > ระบบ Android WebView และดูเวอร์ชันที่ด้านล่างของหน้า
Unity หยุดชั่วคราว
เมื่อ UnityPlayerActivity
ได้รับการโทร onPause()
สายต่อไปนี้
เริ่มดำเนินการ:
UnityPlayerActivity
แจ้งเครื่องมือรันไทม์ของ Unity ว่ากิจกรรมดังกล่าว หยุดชั่วคราวแล้ว- Unity เรียกใช้
MonoBehaviour
ทุกรายการที่ติดตั้งใช้งานOnApplicationPause
กิจกรรม - Unity จะหยุดคอมโพเนนต์และโมดูล เช่น การเล่นเสียง การแสดงภาพ Game Loop และภาพเคลื่อนไหว
- เพื่อให้ทั้ง
Unity Android Player
(UAP) และเครื่องมือค้นหา ซิงค์แล้ว UAP จะรอ 4 วินาทีเพื่อให้เครื่องยนต์หยุด - หากการดำเนินการดังกล่าวใช้เวลานานกว่า 5 วินาที ระบบจะทริกเกอร์ ANR
สแต็กเทรซ
"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)
รูปที่ 3 ANR เกิดจากการเกิดสัญญาณที่ไม่ปล่อยว่าง
โซลูชัน
ตรวจสอบให้แน่ใจว่าโค้ดเกม C# ของคุณไม่ใช้เวลานานเกินไปในการดำเนินการให้เสร็จสิ้นระหว่าง หยุดชั่วคราวหรือดำเนินเหตุการณ์ต่อ
- ทำโปรไฟล์เกมของคุณและดูว่า
OnApplicationPause
เป็นราคาแพงหรือไม่ คุณสามารถใช้Stopwatch
- หลีกเลี่ยงการดำเนินการ I/O หรือคำขอเครือข่ายแบบซิงโครนัส
- ย้ายการดำเนินการไปที่
Thread
อื่นโดยใช้Task
Unity 2023.1 รองรับ โมเดลการเขียนโปรแกรมแบบไม่พร้อมกันโดยใช้ C# คีย์เวิร์ดasync
และawait
รายการ
UnitySendMessage ถูกบล็อก
ปลั๊กอินและ SDK ของ Java Unity จะส่งข้อมูลไปยังเลเยอร์เกม C# โดยใช้ JNI แต่การสื่อสารนี้อาจบล็อกเทรดหลักเนื่องจากโฆษณาเนทีฟ กิจวัตรการซิงค์ข้อมูล เช่น Mutex ที่ทําให้เกิด ANR เนื่องจากการช่วงชิงล็อก
สแต็กเทรซ
ANR ในรูปที่ 4 เกิดจากการทำงานที่ยาวนานในรหัส C# ที่ถูกเรียกโดย ปลั๊กอิน Java เครื่องมือ Unity ใช้การรับค่าที่ไม่สำคัญ hidex เพื่อให้แน่ใจว่ามีการเรียกใช้อย่างถูกต้อง
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)
รูปที่ 4 ANR เกิดจากการช่วงชิงล็อก
สาเหตุ
ปัญหาคือมีการส่งข้อความหลายข้อความเมื่อแอปพลิเคชัน ทำงานต่อ ข้อความอยู่ในคิวเนื่องจากไม่สามารถส่งขณะเล่นเกมได้ อยู่ในเบื้องหลัง ข้อความทั้งหมดจะถูกจัดส่งพร้อมกันเมื่อ ที่กลับมาทำงานอีกครั้ง
ในระหว่างช่วงการหยุดชั่วคราว โดยทั่วไปคุณจะจัดเก็บข้อมูลของเกมบน เซิร์ฟเวอร์; ตัวอย่างเช่น คุณบันทึกตำแหน่งของผู้เล่นในเกมเพื่อให้ผู้เล่นบันทึก จะสามารถกลับมาอยู่ในตำแหน่งเดิมเมื่อเกมกลับมาเล่นต่อ
ภาระงานนี้รวมกับโค้ดของบุคคลที่สามอื่นๆ ที่สร้างภาระงานของตัวเอง ทำให้ทรัพยากรของอุปกรณ์มากเกินไป โดยเฉพาะเทรดหลัก องค์ประกอบหลัก เทรดเรียกใช้อินเทอร์เฟซผู้ใช้ของแอปและมักเป็นตำแหน่งหลักของ ANR ดังนั้น ภาระงานที่เพิ่มขึ้นในเทรดหลักจะเพิ่มโอกาสในการเกิด ANR
โซลูชัน
ในระหว่างที่หยุดแอปพลิเคชันชั่วคราว ให้ตรวจดูว่าการดำเนินการโค้ดทั้งหมดเป็นสิ่งจำเป็น หรือ ให้ลองบันทึกสถานะของผู้ใช้ในหน่วยความจำของอุปกรณ์ และแน่นอนว่าจะเห็น คุณสามารถดำเนินการเหล่านี้ให้เสร็จสมบูรณ์นอกระยะเวลาหยุดชั่วคราวได้หรือไม่
วิธีการมีดังนี้
- ย้ายการดำเนินการ C# ที่จัดการข้อความไปยังชุดข้อความ
นอกเหนือจากเทรดหลัก
- หากโค้ดของคุณไม่ขึ้นอยู่กับบริบทเทรดหลักของ Unity ให้ใช้
Task
สำหรับการสื่อสารแทนการส่งข้อความ
- หากโค้ดของคุณไม่ขึ้นอยู่กับบริบทเทรดหลักของ Unity ให้ใช้
- อย่าส่งหลายข้อความจากปลั๊กอินเมื่อเกมหยุดชั่วคราว
- โปรแกรมไม่สามารถส่งข้อความในขณะที่เกมอยู่ในเบื้องหลัง
- ส่งสถานะข้อมูลล่าสุดให้เกมเฉพาะเมื่อไม่ส่งผลต่อเกมเท่านั้น
ติดตั้งผู้อ้างอิง
URL สำหรับการติดตั้ง Play คือสตริงที่ไม่ซ้ำกันซึ่งส่งไปยัง Play Store เมื่อใดก็ตามที่ ผู้ใช้คลิกโฆษณา เป็นตัวระบุการติดตามโฆษณาเฉพาะของ Android ครั้งเดียว ติดตั้งแล้ว แอปจะส่ง URL ที่มาการติดตั้งไปยังพาร์ทเนอร์ระบุแหล่งที่มา จับคู่แหล่งที่มาที่มีการติดตั้ง (ที่ระบุแหล่งที่มาของ Conversion)
สแต็กเทรซ
รูปที่ 5 แสดงสแต็กเทรซ ANR จากเกมที่ใช้ Facebook SDK เพื่อ ดึงข้อมูลการระบุแหล่งที่มาของการติดตั้ง
สาเหตุ
ANR เกิดจากการเรียกใช้ Binder ที่ช้า แต่สาเหตุที่แท้จริงไม่สามารถ ถูกกำหนดโดยไม่มีการเข้าถึงซอร์สโค้ด SDK
โซลูชัน
การแก้ไขปัญหาประเภทนี้ต้องสื่อสารกับนักพัฒนาซอฟต์แวร์ SDK หรือ ทางออนไลน์ได้มากมาย เพื่อหาทางแก้ไข การตรวจสอบว่าไซต์ ของ SDK แก้ไข ANR สำหรับผู้อื่น หรือแม้แต่ทดสอบกับ กลยุทธ์การเปิดตัว
Google มีหน้าดัชนี SDK ที่รวมข้อมูลการใช้งาน จากแอป Google Play ที่มีข้อมูลที่รวบรวมผ่านการตรวจหาโค้ดไปยัง ระบุแอตทริบิวต์และสัญญาณที่ออกแบบมาเพื่อช่วยคุณตัดสินใจว่าจะนำไปใช้หรือไม่ เก็บหรือนำ SDK ออกจากแอป
แหล่งข้อมูลเพิ่มเติม
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับ ANR โปรดดูแหล่งข้อมูลต่อไปนี้
- แก้ไขข้อบกพร่อง ANR — การพัฒนาเกม Android
- ANR — คุณภาพแอป