ลดขนาดและเพิ่มประสิทธิภาพโค้ด Unity ด้วย R8

แม้ว่าตรรกะหลักของเกมใน Unity จะเขียนด้วย C# (คอมไพล์ด้วย IL2CPP) แต่บิลด์ Android จะมีไบต์โค้ด Java และ Kotlin (classes.dex) จำนวนมากเพื่อจัดการเหตุการณ์ในวงจรของ UnityPlayerActivity, บริการ Google Play, การเรียกเก็บเงิน, โฆษณา และ SDK โซเชียล

การเปิดใช้ R8 ซึ่งเป็นเครื่องมือลดขนาดและเพิ่มประสิทธิภาพโค้ดเริ่มต้นในปลั๊กอิน Android Gradle (AGP) จะนำคลาสและเมธอดที่ไม่ได้ใช้ออก รวมถึงเพิ่มประสิทธิภาพไบต์โค้ด ซึ่งไม่เพียงช่วยลดขนาดการดาวน์โหลดแอปเท่านั้น แต่ยังช่วยลดหน่วยความจำที่ใช้ขณะรันไทม์ของหน้า DEX ที่แมปหน่วยความจำ (mmap) และโอเวอร์เฮดของกระบวนการ Java พื้นฐานด้วย ซึ่งจะช่วยลดแรงกดดันต่อหน่วยความจำจริงและการสิ้นสุดการทำงานของ Low Memory Killer (LMK) นอกจากนี้ Google Play ยังตรวจสอบระดับการเพิ่มประสิทธิภาพ DEX ของเกมผ่านเมตริกการเพิ่มประสิทธิภาพโค้ด DEX ใน Android Vitals ด้วย

ลักษณะการทำงานเริ่มต้นและการรองรับเวอร์ชัน Unity

ใน Unity การลดขนาดโค้ดจะปิดใช้อยู่โดยค่าเริ่มต้น (false) สำหรับทั้งบิลด์รุ่นและบิลด์การแก้ไขข้อบกพร่องเมื่อสร้างโปรเจ็กต์ใหม่

Unity เปิดตัว R8 เป็นครั้งแรกในรูปแบบปุ่มเปิด/ปิดที่ไม่บังคับใน Unity 2020.1.0f1 ตั้งแต่ Unity 2022.2.0f1 (และพอร์ตย้อนกลับไปยัง Unity 2021.3.41f1 LTS) Unity ได้อัปเกรด Toolchain ที่รวมมาเป็น AGP 7.1.2 ขึ้นไป นำการรองรับ ProGuard เดิมออก และเรียกใช้ R8 โดยเฉพาะเมื่อเปิดใช้การลดขนาด

เวอร์ชัน Unity AGP แบบรวม ค่าเริ่มต้นของรุ่น การรองรับ R8 และการกำหนดค่าที่จำเป็น
2019.4 LTS และเวอร์ชันก่อนหน้า ก่อนเวอร์ชัน 3.4 ปิดใช้อยู่ (false) ไม่รองรับ (ProGuard เดิมเท่านั้น)
2020.1.0f1 ถึง 2021.3.40f1 3.4 ถึง 4.0 ปิดใช้อยู่ (false) ไม่บังคับ (ค่าเริ่มต้นคือ ProGuard) เปิดใช้ทั้งลดขนาด > เผยแพร่และใช้ R8
2021.3.41f1 ขึ้นไป (2021 LTS) 7.1+ ปิดใช้อยู่ (false) R8 เท่านั้น เปิดใช้ Minify > Release เพื่อเรียกใช้ R8 โดยอัตโนมัติ
2022.2.0f1 ถึง Unity 6 ขึ้นไป 7.1 ถึง 8.x ปิดใช้อยู่ (false) R8 เท่านั้น เปิดใช้ Minify > Release เพื่อเรียกใช้ R8 โดยอัตโนมัติ

เปิดใช้ R8 ในการตั้งค่าเพลเยอร์

วิธีเปิดใช้การลดขนาดโค้ดและการเพิ่มประสิทธิภาพ R8 สำหรับบิลด์ที่เผยแพร่

  1. ใน Unity Editor ให้เปิดแก้ไข > การตั้งค่าโปรเจ็กต์ แล้วเลือกเพลเยอร์
  2. เลือกแท็บ Android แล้วขยายการตั้งค่าการเผยแพร่ > บิลด์
  3. ในส่วนลดขนาด ให้กำหนดค่าตัวเลือกสำหรับเวอร์ชัน Unity ดังนี้
    • Unity 2021.3.41f1 ขึ้นไปและ 2022.2.0f1 ขึ้นไป: เลือกรุ่น Unity จะเรียกใช้ R8 โดยอัตโนมัติระหว่างงาน minifyReleaseWithR8 Gradle
    • Unity 2020.1.0f1 ถึง 2021.3.40f1: เลือกทั้งรุ่นและใช้ R8

หากคุณสร้างโดยอัตโนมัติโดยใช้สคริปต์ C# Editor ให้กำหนดค่าพร็อพเพอร์ตี้เหล่านี้ผ่าน PlayerSettings.Android ดังนี้

using UnityEditor;

public static class AndroidBuildConfig
{
    public static void EnableR8ForRelease()
    {
        PlayerSettings.Android.minifyRelease = true;

        // Required only in Unity 2020.1.0f1 to 2021.3.40f1 and 2022.1 or earlier
        // (In Unity 2021.3.41f1+ and 2022.2+, R8 is always used when minification is enabled)
#if !UNITY_2022_2_OR_NEWER
        PlayerSettings.Android.minifyWithR8 = true;
#endif
    }
}

เพิ่มกฎการเก็บรักษาสำหรับ JNI และการสะท้อน

คลาสและเมธอด Java ที่เรียกใช้แบบไดนามิกจากสคริปต์ C# โดยใช้ AndroidJavaClass หรือ AndroidJavaObject ไม่มี Call Site ของ Java แบบคงที่ หากไม่มีกฎการเก็บรักษาที่ชัดเจน R8 อาจถือว่าคลาสเหล่านี้ไม่ได้ใช้และนำออกหรือเปลี่ยนชื่อ

วิธีคง Java Bridge ที่กำหนดเองไว้

  1. ในการตั้งค่าโปรเจ็กต์ > Player > Android > การตั้งค่าการเผยแพร่ > บิลด์ ให้เปิดใช้ไฟล์ Proguard ที่กำหนดเอง
  2. เปิดไฟล์ Assets/Plugins/Android/proguard-user.txt ที่สร้างขึ้น
  3. เพิ่มกฎ -keep สำหรับคลาสที่เข้าถึงผ่าน JNI หรือที่ปลั๊กอินของบุคคลที่สามกำหนดให้มี:
# Keep custom Java classes invoked from C# using JNI bridges
-keep class com.example.yourgame.** { *; }

# Keep callback interfaces passed between C# and Java
-keep interface com.example.yourgame.IPluginCallback { *; }

แก้ไขปัญหาทั่วไป

ส่วนนี้จะอธิบายวิธีแก้ไขปัญหาทั่วไปเกี่ยวกับบิลด์และรันไทม์เมื่อใช้ R8 ใน Unity

ข้อผิดพลาดในการบิลด์ Missing classes detected while running R8 รายการ

ใน Unity เวอร์ชันที่ใช้ AGP 7.0 ขึ้นไป (2021.3.41f1+ และ 2022.2+) R8 จะบังคับใช้การตรวจสอบคลาสที่ขาดหายไปอย่างเข้มงวด หากบิลด์ไม่สำเร็จเนื่องจากข้อผิดพลาดนี้ ให้ตรวจสอบไฟล์ missing_rules.txt ที่สร้างขึ้นในไดเรกทอรีเอาต์พุตของบิลด์ (ในส่วน Library/Bee/Android/Prj/.../build/outputs/mapping/release/missing_rules.txt หรือ Temp/gradleOut/...) แล้วเพิ่มทรัพยากร Dependency หรือกฎที่จำเป็นลงใน proguard-user.txt ดูข้อมูลเพิ่มเติมเกี่ยวกับการเขียนกฎ Keep ได้ที่หัวข้อปรับแต่งโค้ดที่จะเก็บไว้

ความเข้ากันได้ของโหมดเต็มรูปแบบ R8 กับปลั๊กอินของบุคคลที่สาม

ใน AGP 8.0 ขึ้นไป (Unity 6+) โหมดเต็มรูปแบบ R8 จะเปิดใช้โดยค่าเริ่มต้นเพื่อทำการเพิ่มประสิทธิภาพที่เข้มงวดมากขึ้น หากปลั๊กอิน Android เดิมทำงานไม่สำเร็จที่รันไทม์เนื่องจากปัญหาการสะท้อน ให้ปรับปรุงกฎ ProGuard ของปลั๊กอินหรือเปลี่ยน R8 กลับไปเป็นโหมดความเข้ากันได้ โดยทำดังนี้

  1. ในการตั้งค่าการเผยแพร่ > บิลด์ ให้เปิดใช้เทมเพลตพร็อพเพอร์ตี้ Gradle ที่กำหนดเอง
  2. เปิด Assets/Plugins/Android/gradleTemplate.properties และเพิ่มพร็อพเพอร์ตี้ต่อไปนี้
android.enableR8.fullMode=false