ประเภทกฎเพิ่มเติม

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