การเพิ่มประสิทธิภาพสำหรับผู้เขียนคลัง

ในฐานะผู้เขียนไลบรารี คุณควรตรวจสอบว่านักพัฒนาแอปสามารถผสานรวมไลบรารีของคุณเข้ากับแอปได้อย่างง่ายดาย ขณะเดียวกันก็รักษาประสบการณ์การใช้งานที่มีคุณภาพสูงให้แก่ผู้ใช้ คุณควรตรวจสอบว่าไลบรารีของคุณเข้ากันได้กับการเพิ่มประสิทธิภาพ Android โดยไม่ต้องตั้งค่าเพิ่มเติม หรือระบุในเอกสารว่าไลบรารีอาจไม่เหมาะสำหรับการใช้งานใน Android

เอกสารประกอบนี้มีไว้สำหรับนักพัฒนาไลบรารีที่เผยแพร่แล้ว แต่ก็อาจเป็นประโยชน์สำหรับนักพัฒนาโมดูลไลบรารีภายในในแอปขนาดใหญ่ที่แบ่งออกเป็นโมดูล

หากคุณเป็นนักพัฒนาแอปและต้องการดูข้อมูลเกี่ยวกับการเพิ่มประสิทธิภาพแอป Android โปรดดูเปิดใช้การเพิ่มประสิทธิภาพแอป หากต้องการดูข้อมูลเกี่ยวกับว่าควรใช้ไลบรารีใดบ้าง โปรดดูหัวข้อเลือกไลบรารีอย่างชาญฉลาด

ใช้ codegen แทนการสะท้อน

หากเป็นไปได้ ให้ใช้การสร้างโค้ด (codegen) แทนการสะท้อน ทั้ง Codegen และ Reflection เป็นแนวทางทั่วไปในการหลีกเลี่ยงโค้ดที่ซ้ำกันเมื่อเขียนโปรแกรม แต่ codegen เข้ากันได้กับเครื่องมือเพิ่มประสิทธิภาพแอปอย่าง R8 มากกว่า

  • เมื่อใช้ codegen ระบบจะวิเคราะห์และแก้ไขโค้ดในระหว่างกระบวนการบิลด์ เนื่องจากไม่มีการเปลี่ยนแปลงที่สำคัญหลังจากเวลาคอมไพล์ เครื่องมือเพิ่มประสิทธิภาพจึงรู้ว่าโค้ดใดบ้างที่จำเป็นต่อการใช้งานในท้ายที่สุดและโค้ดใดบ้างที่สามารถนำออกได้อย่างปลอดภัย
  • เมื่อใช้การสะท้อนกลับ ระบบจะวิเคราะห์และจัดการโค้ดขณะรันไทม์ เนื่องจากโค้ดยังไม่เสร็จสมบูรณ์จนกว่าจะเรียกใช้ เครื่องมือเพิ่มประสิทธิภาพจึงไม่ทราบว่าจะนําโค้ดใดออกได้ เนื่องจากมีแนวโน้มที่จะนําโค้ดที่ใช้แบบไดนามิกผ่านรีเฟล็กชันออกในระหว่างรันไทม์ ซึ่งทําให้แอปขัดข้องสําหรับผู้ใช้

ไลบรารีสมัยใหม่จำนวนมากใช้ codegen แทนการสะท้อน ดูKSP สำหรับจุดแรกเข้าทั่วไปที่ใช้โดย Room, Dagger2 และอื่นๆ อีกมากมาย

กรณีที่สะท้อนแสงได้

หากจำเป็นต้องใช้ภาพสะท้อน คุณควรสะท้อนไปยังอย่างใดอย่างหนึ่งต่อไปนี้เท่านั้น

  • ประเภทที่กําหนดเป้าหมายที่เฉพาะเจาะจง (ผู้ใช้งานหรือคลาสย่อยของอินเทอร์เฟซที่เฉพาะเจาะจง)
  • โค้ดที่ใช้คําอธิบายประกอบรันไทม์ที่เฉพาะเจาะจง

การใช้การสะท้อนกลับด้วยวิธีนี้จะช่วยจำกัดต้นทุนรันไทม์และช่วยให้เขียนกฎการเก็บรักษาผู้บริโภคเป้าหมายได้

การสะท้อนกลับรูปแบบที่เฉพาะเจาะจงและมุ่งเน้นนี้เป็นรูปแบบที่คุณจะพบได้ทั้งในเฟรมเวิร์ก Android (เช่น เมื่อสร้างกิจกรรม มุมมอง และ Drawable) และไลบรารี AndroidX (เช่น เมื่อสร้าง WorkManager, ListenableWorker หรือ RoomDatabase) ในทางตรงกันข้าม การสะท้อนกลับแบบเปิดของ Gson ไม่เหมาะสําหรับการใช้งานในแอป Android

เขียนกฎการเก็บรักษาของผู้บริโภค

ไลบรารีควรจัดแพ็กเกจกฎการเก็บ "ผู้บริโภค" ซึ่งใช้รูปแบบเดียวกับกฎการเก็บของแอป ระบบจะรวมกฎเหล่านี้ไว้ในอาร์ติแฟกต์ไลบรารี (AAR หรือ JAR) และนำไปใช้โดยอัตโนมัติในระหว่างการเพิ่มประสิทธิภาพแอป Android เมื่อใช้ไลบรารี

ไลบรารี AAR

หากต้องการเพิ่มกฎของผู้บริโภคสำหรับไลบรารี AAR ให้ใช้ตัวเลือก consumerProguardFiles ในสคริปต์บิลด์ของโมดูลไลบรารี Android ดูข้อมูลเพิ่มเติมได้ที่คำแนะนำเกี่ยวกับการสร้างโมดูลไลบรารี

Kotlin

android {
    defaultConfig {
        consumerProguardFiles("consumer-proguard-rules.pro")
    }
    ...
}

Groovy

android {
    defaultConfig {
        consumerProguardFiles 'consumer-proguard-rules.pro'
    }
    ...
}

ไลบรารี JAR

หากต้องการรวมกฎกับไลบรารี Kotlin/Java ที่จัดส่งเป็น JAR ให้ใส่ไฟล์กฎในไดเรกทอรี META-INF/proguard/ ของ JAR สุดท้ายพร้อมชื่อไฟล์ใดก็ได้ เช่น หากโค้ดของคุณอยู่ใน <libraryroot>/src/main/kotlin ให้ใส่ไฟล์กฎของผู้บริโภคที่ <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro แล้วระบบจะรวมกฎไว้ในตำแหน่งที่ถูกต้องใน JAR เอาต์พุต

ยืนยันว่า JAR สุดท้ายรวมกฎอย่างถูกต้องโดยตรวจสอบว่ากฎอยู่ในไดเรกทอรี META-INF/proguard

เพิ่มประสิทธิภาพการสร้างไลบรารี AAR (ขั้นสูง)

โดยทั่วไปแล้ว คุณไม่ควรเพิ่มประสิทธิภาพการสร้างคลังโดยตรง เนื่องจากการเพิ่มประสิทธิภาพที่เป็นไปได้ในเวลาที่สร้างคลังมีจํากัดมาก เฉพาะในระหว่างการสร้างแอปพลิเคชันเมื่อรวมไลบรารีเป็นส่วนหนึ่งของแอปพลิเคชันเท่านั้นที่ R8 จะทราบวิธีใช้เมธอดทั้งหมดของไลบรารีและพารามิเตอร์ที่ส่ง ในฐานะนักพัฒนาไลบรารี คุณต้องพิจารณาหลายขั้นตอนของการเพิ่มประสิทธิภาพและคงลักษณะการทำงานไว้ ทั้งในช่วงที่สร้างไลบรารีและสร้างแอป ก่อนที่จะเพิ่มประสิทธิภาพไลบรารีนั้น

หากยังต้องการเพิ่มประสิทธิภาพไลบรารีเมื่อสร้าง โปรดทราบว่า Android Gradle Plugin รองรับการดำเนินการนี้

Kotlin

android {
    buildTypes {
        release {
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
        configureEach {
            consumerProguardFiles("consumer-rules.pro")
        }
    }
}

Groovy

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles
                getDefaultProguardFile('proguard-android-optimize.txt'),
                'proguard-rules.pro'
        }
        configureEach {
            consumerProguardFiles "consumer-rules.pro"
        }
    }
}

โปรดทราบว่าลักษณะการทํางานของ proguardFiles แตกต่างจาก consumerProguardFiles อย่างมาก

  • proguardFiles จะใช้เมื่อสร้าง ซึ่งมักจะใช้ร่วมกับ getDefaultProguardFile("proguard-android-optimize.txt") เพื่อกำหนดว่าควรเก็บส่วนใดของไลบรารีไว้ในระหว่างการสร้าง อย่างน้อยที่สุด นี่เป็น API สาธารณะของคุณ
  • consumerProguardFiles ในทางตรงกันข้ามจะได้รับการแพ็กเกจไว้ในไลบรารีเพื่อส่งผลต่อการเพิ่มประสิทธิภาพที่จะเกิดขึ้นในภายหลัง ระหว่างการสร้างแอปที่ใช้ไลบรารีของคุณ

เช่น หากไลบรารีใช้การแสดงผลเพื่อสร้างคลาสภายใน คุณอาจต้องกำหนดกฎการเก็บทั้งในส่วน proguardFiles และ consumerProguardFiles

หากคุณใช้ -repackageclasses ในบิลด์ของไลบรารี ให้จัดแพ็กเกจคลาสใหม่เป็นแพ็กเกจย่อยภายในแพ็กเกจของไลบรารี เช่น ใช้ -repackageclasses 'com.example.mylibrary.internal' แทน -repackageclasses 'internal'

รองรับ R8 เวอร์ชันต่างๆ (ขั้นสูง)

คุณปรับแต่งกฎเพื่อกําหนดเป้าหมาย R8 เวอร์ชันที่เฉพาะเจาะจงได้ วิธีนี้จะช่วยให้ไลบรารีทํางานได้อย่างมีประสิทธิภาพสูงสุดในโปรเจ็กต์ที่ใช้ R8 เวอร์ชันใหม่ ในขณะที่ยังใช้กฎที่มีอยู่ต่อไปในโปรเจ็กต์ที่ใช้ R8 เวอร์ชันเก่าได้

หากต้องการระบุกฎ R8 ที่กำหนดเป้าหมาย คุณต้องใส่กฎเหล่านั้นในไดเรกทอรี META-INF/com.android.tools ภายใน classes.jar ของ AAR หรือในไดเรกทอรี META-INF/com.android.tools ของ JAR

In an AAR library:
    proguard.txt (legacy location, the file name must be "proguard.txt")
    classes.jar
    └── META-INF
        └── com.android.tools (location of targeted R8 rules)
            ├── r8-from-<X>-upto-<Y>/<R8-rule-files>
            └── ... (more directories with the same name format)

In a JAR library:
    META-INF
    ├── proguard/<ProGuard-rule-files> (legacy location)
    └── com.android.tools (location of targeted R8 rules)
        ├── r8-from-<X>-upto-<Y>/<R8-rule-files>
        └── ... (more directories with the same name format)

ในไดเรกทอรี META-INF/com.android.tools อาจมีไดเรกทอรีย่อยหลายรายการที่มีชื่อในรูปแบบ r8-from-<X>-upto-<Y> เพื่อระบุเวอร์ชัน R8 ที่เขียนกฎ โฟลเดอร์ย่อยแต่ละโฟลเดอร์อาจมีไฟล์ที่มีกฎ R8 อย่างน้อย 1 ไฟล์ โดยมีชื่อและนามสกุลไฟล์ใดก็ได้

โปรดทราบว่าส่วน -from-<X> และ -upto-<Y> ไม่บังคับ ส่วนเวอร์ชัน <Y> ต้องระบุ และช่วงเวอร์ชันมักจะต่อเนื่องกัน แต่ก็ทับซ้อนกันได้

เช่น r8, r8-upto-8.0.0, r8-from-8.0.0-upto-8.2.0 และ r8-from-8.2.0 คือชื่อไดเรกทอรีที่แสดงชุดกฎ R8 ที่กำหนดเป้าหมาย กฎที่อยู่ในไดเรกทอรี r8 สามารถใช้กับ R8 เวอร์ชันใดก็ได้ กฎที่อยู่ในไดเรกทอรี r8-from-8.0.0-upto-8.2.0 สามารถใช้กับ R8 ตั้งแต่เวอร์ชัน 8.0.0 ขึ้นไป แต่ไม่รวมเวอร์ชัน 8.2.0

ปลั๊กอิน Android Gradle จะใช้ข้อมูลดังกล่าวเพื่อเลือกกฎทั้งหมดที่ R8 เวอร์ชันปัจจุบันใช้ได้ หากไลบรารีไม่ได้ระบุกฎ R8 เป้าหมาย ปลั๊กอิน Gradle ของ Android จะเลือกกฎจากตำแหน่งเดิม (proguard.txt สำหรับ AAR หรือ META-INF/proguard/<ProGuard-rule-files> สำหรับ JAR)