R8 ช่วยให้คุณเพิ่มกฎที่มีผลต่อการเพิ่มประสิทธิภาพแอปได้ นอกเหนือจากกฎ keep
เพิ่มกฎเหล่านี้ในไฟล์ proguard-rules.pro เดียวกันกับที่ใช้ดูแล
กฎการเก็บรักษา
กฎเหล่านี้แบ่งออกเป็นหมวดหมู่ต่อไปนี้
- สมมติฐาน
-assumevalues-assumenosideeffects
- การเพิ่มประสิทธิภาพอื่นๆ
-convertchecknotnull-maximumremovedandroidloglevel
สมมติฐาน
กฎเหล่านี้จะบอก R8 ว่าสามารถทำการสมมติฐานที่เฉพาะเจาะจงเกี่ยวกับลักษณะการทำงานของโค้ดที่เฉพาะเจาะจงได้ในขณะรันไทม์
-assumevalues
กฎ -assumevalues จะบอก R8 ว่าค่าของฟิลด์หรือค่าที่เมธอด
ส่งคืนจะเป็นค่าคงที่ที่เฉพาะเจาะจงเสมอ หรืออยู่ในช่วงที่กำหนดที่
รันไทม์ -assumevalues มีไว้สำหรับสิ่งต่างๆ เช่น ค่าแฟล็ก ซึ่งทราบกันว่ามีค่าที่เฉพาะเจาะจงในขณะรันไทม์ในเวลาบิลด์
การวิเคราะห์แบบคงที่มาตรฐานของ R8 อาจไม่สามารถกำหนดค่ารันไทม์ของสมาชิกได้
เมื่อใช้ -assumevalues คุณจะบอกให้ R8 สันนิษฐานค่าหรือช่วงที่ระบุ
เมื่อเพิ่มประสิทธิภาพโค้ด ซึ่งช่วยให้ R8 ทำการเพิ่มประสิทธิภาพแบบเข้มงวดได้
ไวยากรณ์สำหรับ -assumevalues จะคล้ายกับไวยากรณ์สำหรับการเก็บ member_specification แต่จะมี return clause เพิ่มเติมดังนี้
<member_specification> return <value> | <range>
อาร์กิวเมนต์ <value> และ <range> รองรับค่าและประเภทต่อไปนี้
- ค่าพิเศษ:
true, false, null, @NonNull - ค่าดั้งเดิม:
int - การอ้างอิงฟิลด์แบบคงที่ (รวมถึงฟิลด์ enum)
หากต้องการกำหนดช่วง ให้ใช้รูปแบบ min..max ที่รวมขอบเขต ตัวอย่างเช่น ข้อมูลโค้ดต่อไปนี้แสดงว่าตัวแปร CUSTOM_VAL ยอมรับค่า 26 ถึง
2147483647
-assumevalues public class com.example.Foo {
public static int CUSTOM_VAL return 26..2147483647;
}
คุณใช้กฎนี้ได้ในสถานการณ์ต่อไปนี้
- สำหรับไลบรารี: เพื่อให้แน่ใจว่าเมื่อมีการเพิ่มประสิทธิภาพแอป ระบบจะนำฮุกการแก้ไขข้อบกพร่องในเครื่องทั้งหมดออกจากโค้ดไลบรารีสาธารณะ
- สำหรับแอป: หากต้องการนำสิ่งต่างๆ เช่น โค้ดแก้ไขข้อบกพร่องออกจากแอปที่เผยแพร่แล้ว ขอแนะนำให้ใช้ตัวแปรบิลด์และตัวแปรของชุดแหล่งที่มาหรือค่าคงที่ที่เฉพาะเจาะจง แต่หากชุดแหล่งที่มาของตัวแปรไม่เหมาะกับกรณีของคุณ หรือหากต้องการการรับประกันที่มั่นใจได้มากขึ้นว่าเส้นทางโค้ดถูกนำออกไปอย่างสมบูรณ์ ให้ใช้
-assumevalues
ตัวอย่างต่อไปนี้แสดงคลาสที่ R8 นำเครื่องมือแก้ไขข้อบกพร่องออกจาก แอปเวอร์ชันที่เพิ่มประสิทธิภาพแล้ว
package com.example;
public class MyConfig {
// This field is initialized to false but is overwritten by a resource
// value or other mechanism in the final build process. R8's static analysis
// might see the initial 'false' but the runtime value is known to be
// 'true'.
public static final boolean IS_OPTIMIZED_VERSION = false;
}
// In another class:
public void initFeatures() {
if (MyConfig.IS_OPTIMIZED_VERSION) {
System.out.println("Starting optimized features...");
android.util.Log.d(TAG, "Starting optimized features...");
initOptimizedService();
} else {
android.util.Log.d(TAG, "Starting debug/logging features...");
initDebugTools();
}
}
กฎต่อไปนี้แสดงวิธีบอก R8 ว่าตัวแปร
IS_OPTIMIZED_VERSION คาดว่าจะตั้งค่าเป็น true เสมอ
-assumevalues class com.example.MyConfig {
public static final boolean IS_OPTIMIZED_VERSION return true;
}
-assumenosideeffects
กฎ -assumenosideeffects จะบอก R8 ว่าสามารถถือได้ว่าสมาชิกที่ระบุไม่มีผลข้างเคียง R8 สามารถนำการเรียกไปยังเมธอดดังกล่าวออกได้ทั้งหมด
ซึ่งไม่มีค่าที่ส่งคืนหรือส่งคืนค่าคงที่
ไวยากรณ์สำหรับ -assumenosideeffects จะคล้ายกับไวยากรณ์สำหรับการเก็บ member_specification
ตัวอย่างต่อไปนี้แสดงวิธีบอก R8 ว่าpublic staticเมธอดทั้งหมดที่ชื่อ log ภายในคลาส DebugLogger ไม่ควรมีผลข้างเคียง
ซึ่งจะช่วยให้ R8 นำการเรียกเมธอดเหล่านี้ออกได้
-assumenosideeffects class com.example.DebugLogger {
public static void log(...);
}
การเพิ่มประสิทธิภาพอื่นๆ
การเพิ่มประสิทธิภาพขั้นสูงเพิ่มเติมบางอย่างเหล่านี้ไม่ได้เปิดใช้โดยค่าเริ่มต้น เมื่อเปิดใช้ คุณจะอนุญาตให้ R8 เพิ่มประสิทธิภาพโค้ดตามที่ระบุไว้ นอกเหนือจาก การเพิ่มประสิทธิภาพเริ่มต้น
-convertchecknotnull
คุณใช้กฎ -convertchecknotnull เพื่อเพิ่มประสิทธิภาพการตรวจสอบค่า Null ได้ ซึ่งใช้กับเมธอดที่รับพารามิเตอร์ออบเจ็กต์และส่งข้อยกเว้นหากออบเจ็กต์เป็น Null คล้ายกับการยืนยัน Kotlin มาตรฐาน ประเภทข้อยกเว้นและข้อความ
อาจไม่เหมือนกัน แต่ลักษณะการทำงานที่ทำให้เกิดข้อขัดข้องแบบมีเงื่อนไขจะเหมือนกัน
หาก-convertchecknotnullกฎตรงกับเมธอดที่ระบุ ระบบจะแทนที่การเรียกใช้แต่ละครั้งไปยังเมธอดนั้นด้วยการเรียกใช้ getClass() ในอาร์กิวเมนต์แรก การเรียกใช้
getClass() จะใช้แทนการตรวจสอบค่า Null และช่วยให้ R8 นำอาร์กิวเมนต์พิเศษ
ของการตรวจสอบค่า Null เดิมออกได้ เช่น การจัดสรรสตริงที่มีค่าใช้จ่ายสูง
ไวยากรณ์สำหรับ -convertchecknotnull มีดังนี้
-convertchecknotnull <class_specification> {
<member_specification>;
}
ตัวอย่างเช่น หากคุณมีคลาส Preconditions ที่มีเมธอด checkNotNull ดังนี้
class Preconditions {
fun <T> checkNotNull(value: T?): T {
if (value == null) {
throw NullPointerException()
} else {
return value
}
}
}
ใช้กฎต่อไปนี้
-convertchecknotnull class com.example.package.Preconditions {
void checkNotNull(java.lang.Object);
}
กฎจะแปลงการเรียกใช้ทั้งหมดเป็น checkNotNull() เป็นการเรียกใช้ getClass ในอาร์กิวเมนต์แรก
ในตัวอย่างนี้ ระบบจะแทนที่การเรียกใช้ checkNotNull(bar) ด้วย
bar.getClass() หาก bar เป็น null bar.getClass() จะส่ง NullPointerException ซึ่งให้ผลการตรวจสอบค่า Null ที่คล้ายกันแต่มีประสิทธิภาพมากกว่า
-maximumremovedandroidloglevel
กฎประเภทนี้จะนำคำสั่งการบันทึกของ Android (เช่น
Log.w(...) และ Log.isLoggable(...)) ที่ระดับบันทึกหนึ่งๆ หรือต่ำกว่าออก
ไวยากรณ์สำหรับ maximumremovedandroidloglevel มีดังนี้
-maximumremovedandroidloglevel <log_level> [<class_specification>]
หากคุณไม่ระบุ class_specification ที่ไม่บังคับ R8 จะใช้การนำบันทึกออก
กับทั้งแอป
ระดับบันทึกมีดังนี้
ป้ายกำกับบันทึก |
ระดับบันทึก |
VERBOSE |
2 |
DEBUG |
3 |
ข้อมูล |
4 |
คำเตือน |
5 |
ข้อผิดพลาด |
6 |
ยืนยัน |
7 |
ตัวอย่างเช่น หากคุณมีโค้ดต่อไปนี้
class Foo {
private static final String TAG = "Foo";
void logSomething() {
if (Log.isLoggable(TAG, WARNING)) {
Log.e(TAG, "Won't be logged");
}
Log.w(TAG, "Won't be logged");
Log.e(TAG, "Will be logged");
}
}
โดยมีกฎต่อไปนี้
# A level of 5 corresponds to a log level of WARNING.
-maximumremovedandroidloglevel 5 class Foo { void logSomething(); }
โค้ดที่เพิ่มประสิทธิภาพแล้วมีดังนี้
class Foo {
private static final String TAG = "Foo";
void logSomething() {
Log.e(TAG, "Will be logged");
}
}
หากคุณระบุระดับบันทึกสูงสุดหลายระดับสำหรับเมธอดเดียวกัน R8 จะใช้ ระดับต่ำสุด ตัวอย่างเช่น หากมีกฎต่อไปนี้
-maximumremovedandroidloglevel 7 class ** { void foo(); }
-maximumremovedandroidloglevel 4 class ** { void foo(); }
จากนั้นระดับบันทึกสูงสุดที่นำออกสำหรับ foo() คือ 4