Rút gọn và tối ưu hoá mã Unity bằng R8

Mặc dù logic trò chơi cốt lõi trong Unity được viết bằng C# (được biên dịch bằng IL2CPP), nhưng các bản dựng Android bao gồm mã byte Java và Kotlin (classes.dex) đáng kể để xử lý các sự kiện trong vòng đời UnityPlayerActivity, Dịch vụ Google Play, thanh toán, quảng cáo và SDK mạng xã hội.

Khi bạn bật R8 (trình rút gọn và tối ưu hoá mã mặc định trong Trình bổ trợ Android cho Gradle (AGP)), các lớp và phương thức không dùng đến sẽ bị xoá và mã byte sẽ được tối ưu hoá. Việc này không chỉ làm giảm kích thước tải ứng dụng xuống mà còn giảm mức sử dụng bộ nhớ trong thời gian chạy của các trang DEX được ánh xạ bộ nhớ (mmap) và mức hao tổn của quy trình Java cơ sở, giảm áp lực lên bộ nhớ vật lý và giảm tình trạng chấm dứt do trình chấm dứt ứng dụng khi bộ nhớ thấp (LMK). Google Play cũng giám sát mức độ tối ưu hoá DEX của trò chơi thông qua chỉ số Tối ưu hoá mã DEX trong Android vitals.

Hành vi mặc định và hỗ trợ phiên bản Unity

Trong Unity, tính năng rút gọn mã bị tắt theo mặc định (false) cho cả bản phát hành và bản gỡ lỗi khi tạo dự án mới.

Unity lần đầu ra mắt R8 dưới dạng nút bật/tắt không bắt buộc trong Unity 2020.1.0f1. Kể từ Unity 2022.2.0f1 (và được chuyển ngược sang Unity 2021.3.41f1 LTS), Unity đã nâng cấp chuỗi công cụ đi kèm lên AGP 7.1.2 trở lên, xoá tính năng hỗ trợ ProGuard cũ và chỉ chạy R8 bất cứ khi nào tính năng rút gọn được bật.

Phiên bản Unity AGP đi kèm Bản phát hành mặc định Hỗ trợ R8 và cấu hình bắt buộc
2019.4 LTS trở xuống Trước phiên bản 3.4 Đã tắt (false) Không được hỗ trợ (chỉ ProGuard cũ).
2020.1.0f1 đến 2021.3.40f1 3,4 đến 4 Đã tắt (false) Không bắt buộc (mặc định là ProGuard). Bật cả Minify > Release (Thu nhỏ > Bản phát hành) và Use R8 (Sử dụng R8).
2021.3.41f1 trở lên (2021 LTS) 7.1 trở lên Đã tắt (false) Chỉ R8. Bật Minify > Release (Rút gọn > Phát hành) để tự động chạy R8.
2022.2.0f1 đến Unity 6 trở lên 7.1 đến 8.x Đã tắt (false) Chỉ R8. Bật Minify > Release (Rút gọn > Phát hành) để tự động chạy R8.

Bật R8 trong phần Cài đặt trình phát

Cách bật tính năng rút gọn mã và tối ưu hoá mã R8 cho Bản phát hành:

  1. Trong Trình chỉnh sửa Unity, hãy mở Edit > Project Settings (Chỉnh sửa > Cài đặt dự án) rồi chọn Player (Trình phát).
  2. Chọn thẻ Android rồi mở rộng Publishing Settings > Build (Cài đặt phát hành > Bản dựng).
  3. Trong phần Minify (Rút gọn), hãy định cấu hình các tuỳ chọn cho phiên bản Unity của bạn:
    • Unity 2021.3.41f1 trở lên và 2022.2.0f1 trở lên: Chọn Release (Bản phát hành). Unity tự động chạy R8 trong tác vụ Gradle minifyReleaseWithR8.
    • Unity 2020.1.0f1 đến 2021.3.40f1: Chọn cả Release (Bản phát hành) và Use R8 (Sử dụng R8).

Nếu bạn tự động hoá các bản dựng bằng tập lệnh Trình chỉnh sửa C#, hãy định cấu hình các thuộc tính này thông qua 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
    }
}

Thêm quy tắc giữ lại cho JNI và phản chiếu

Các lớp và phương thức Java được gọi linh động từ tập lệnh C# bằng cách sử dụng AndroidJavaClass hoặc AndroidJavaObject không có trang web gọi Java tĩnh. Nếu không có quy tắc giữ lại rõ ràng, R8 có thể coi các lớp này là không được sử dụng và xoá hoặc đổi tên chúng.

Cách giữ lại các cầu nối Java tuỳ chỉnh:

  1. Trong phần Project Settings > Player > Android > Publishing Settings > Build (Cài đặt dự án > Trình phát > Android > Cài đặt phát hành > Bản dựng), hãy bật Custom Proguard File (Tệp Proguard tuỳ chỉnh).
  2. Mở tệp Assets/Plugins/Android/proguard-user.txt đã tạo.
  3. Thêm quy tắc -keep cho các lớp được truy cập qua JNI hoặc theo yêu cầu của trình bổ trợ bên thứ ba:
# 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 { *; }

Khắc phục các vấn đề thường gặp

Phần này mô tả cách giải quyết các vấn đề thường gặp về bản dựng và thời gian chạy khi sử dụng R8 trong Unity.

Missing classes detected while running R8 lỗi bản dựng

Trong các phiên bản Unity sử dụng AGP 7.0 trở lên (2021.3.41f1+ và 2022.2+), R8 thực thi các quy trình kiểm tra nghiêm ngặt về lớp bị thiếu. Nếu một bản dựng không thành công do lỗi này, hãy kiểm tra tệp missing_rules.txt được tạo trong thư mục đầu ra của bản dựng (trong Library/Bee/Android/Prj/.../build/outputs/mapping/release/missing_rules.txt hoặc Temp/gradleOut/...) rồi thêm các phần phụ thuộc hoặc quy tắc bắt buộc vào proguard-user.txt. Để biết thêm thông tin về cách viết quy tắc giữ lại, hãy xem bài viết Tuỳ chỉnh mã cần giữ lại.

Khả năng tương thích của chế độ đầy đủ R8 với trình bổ trợ của bên thứ ba

Trong AGP 8.0 trở lên (Unity 6 trở lên), chế độ đầy đủ của R8 được bật theo mặc định để thực hiện các hoạt động tối ưu hoá mạnh mẽ hơn. Nếu một trình bổ trợ Android cũ không hoạt động trong thời gian chạy do các vấn đề về phản chiếu, hãy cập nhật quy tắc ProGuard của trình bổ trợ hoặc chuyển R8 về chế độ tương thích:

  1. Trong phần Publishing Settings > Build (Cài đặt phát hành > Bản dựng), hãy bật Custom Gradle Properties Template (Mẫu thuộc tính Gradle tuỳ chỉnh).
  2. Mở Assets/Plugins/Android/gradleTemplate.properties và thêm thuộc tính sau:
android.enableR8.fullMode=false