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

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

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

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

ทำความเข้าใจประเภทกฎการเก็บรักษา

กฎการเก็บรักษาในไลบรารีมี 2 ประเภทที่แตกต่างกัน ได้แก่

  • กฎการเก็บรักษาสำหรับผู้ใช้ ต้องระบุกฎที่เก็บรักษาทุกสิ่งที่ไลบรารีอ้างอิง หากไลบรารีใช้การอ้างอิงหรือ JNI เพื่อเรียกใช้โค้ดของตนเองหรือโค้ดที่กำหนดโดยแอปไคลเอ็นต์ กฎเหล่านี้ต้องอธิบายว่าโค้ดใดที่ต้องเก็บรักษาไว้ ไลบรารีควรแพ็กเกจกฎการเก็บรักษาสำหรับผู้ใช้ซึ่งใช้รูปแบบเดียวกับกฎการเก็บรักษาของแอป กฎเหล่านี้จะรวมอยู่ในอาร์ติแฟกต์ของไลบรารี (AAR หรือ JAR) และระบบจะใช้กฎเหล่านี้โดยอัตโนมัติระหว่างการเพิ่มประสิทธิภาพแอป Android เมื่อมีการใช้ไลบรารี กฎเหล่านี้จะได้รับการเก็บรักษาไว้ในไฟล์ที่ระบุด้วยพร็อพเพอร์ตี้ consumerProguardFiles ในไฟล์ build.gradle.kts (หรือ build.gradle) ดูข้อมูลเพิ่มเติมได้ที่คำแนะนำเพิ่มเติม
  • กฎการเก็บรักษาสำหรับการสร้างไลบรารี จะมีผลเมื่อมีการสร้างไลบรารี กฎเหล่านี้จำเป็นก็ต่อเมื่อคุณตัดสินใจเพิ่มประสิทธิภาพไลบรารีบางส่วนในระหว่างการสร้าง กฎเหล่านี้ต้องเก็บรักษา API สาธารณะของไลบรารีไว้ไม่ให้ถูกนำออก ไม่เช่นนั้น API สาธารณะจะไม่อยู่ในการเผยแพร่ไลบรารี ซึ่งหมายความว่านักพัฒนาแอปจะใช้ไลบรารีไม่ได้ กฎเหล่านี้จะได้รับการเก็บรักษาไว้ในไฟล์ ที่ระบุด้วยพร็อพเพอร์ตี้ proguardFiles ในไฟล์ build.gradle.kts (หรือ build.gradle) ดูข้อมูลเพิ่มเติมได้ที่ เพิ่มประสิทธิภาพการสร้างไลบรารี AAR

ข้อกำหนดและหลักเกณฑ์ของการเพิ่มประสิทธิภาพ

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

ปฏิบัติตามข้อกำหนดของการเพิ่มประสิทธิภาพ

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

คำแนะนำเพิ่มเติม

นอกเหนือจากข้อกำหนดของการเพิ่มประสิทธิภาพแล้ว เรายังมีคำแนะนำเพิ่มเติมดังนี้

  • อย่าใช้ -repackageclasses ในไฟล์กฎการเก็บรักษาสำหรับผู้ใช้ของไลบรารี อย่างไรก็ตาม หากต้องการเพิ่มประสิทธิภาพการสร้างไลบรารี คุณสามารถใช้ -repackageclasses กับชื่อแพ็กเกจภายใน เช่น <your.library.package>.internal ใน ไฟล์กฎการเก็บรักษาสำหรับการสร้างไลบรารี ซึ่งจะช่วยเพิ่มประสิทธิภาพของไลบรารีในแอปที่ไม่ได้เพิ่มประสิทธิภาพ แต่โดยทั่วไปแล้วไม่จำเป็น เนื่องจากแอปควรได้รับการเพิ่มประสิทธิภาพด้วย
  • ประกาศแอตทริบิวต์ใดก็ตามที่ไลบรารีต้องใช้เพื่อให้ทำงานได้ในไฟล์กฎการเก็บรักษาของไลบรารี แม้ว่าอาจมีการทับซ้อนกับแอตทริบิวต์ที่กำหนดไว้ใน proguard-android-optimize.txt
  • หากคุณต้องการแอตทริบิวต์ต่อไปนี้ในการเผยแพร่ไลบรารี ให้เก็บรักษาแอตทริบิวต์เหล่านี้ไว้ในไฟล์กฎการเก็บรักษาสำหรับการสร้างไลบรารี ไม่ใช่ ในไฟล์กฎการเก็บรักษาสำหรับผู้ใช้ของไลบรารี
    • AnnotationDefault
    • EnclosingMethod
    • Exceptions
    • InnerClasses
    • RuntimeInvisibleAnnotations
    • RuntimeInvisibleParameterAnnotations
    • RuntimeInvisibleTypeAnnotations
    • RuntimeVisibleAnnotations
    • RuntimeVisibleParameterAnnotations
    • RuntimeVisibleTypeAnnotations
    • Signature
  • ผู้เขียนไลบรารีควรเก็บรักษาแอตทริบิวต์ RuntimeVisibleAnnotations ไว้ในกฎการเก็บรักษาสำหรับผู้ใช้ หากมีการใช้คำอธิบายประกอบในรันไทม์
  • ผู้เขียนไลบรารีไม่ควรใช้ตัวเลือกส่วนกลางต่อไปนี้ในกฎการเก็บรักษาสำหรับผู้ใช้
    • -include
    • -basedirectory
    • -injars
    • -outjars
    • -libraryjars
    • -repackageclasses
    • -flattenpackagehierarchy
    • -allowaccessmodification
    • -renamesourcefileattribute
    • -ignorewarnings
    • -addconfigurationdebugging
    • -printconfiguration
    • -printmapping
    • -printusage
    • -printseeds
    • -applymapping
    • -obfuscationdictionary
    • -classobfuscationdictionary
    • -packageobfuscationdictionary

กรณีที่ใช้การอ้างอิงได้

หากต้องใช้การอ้างอิง คุณควรอ้างอิงเฉพาะสิ่งใดสิ่งหนึ่งต่อไปนี้

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

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

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

ความเข้าใจผิดที่พบบ่อย

ความเข้าใจผิดที่พบบ่อยบางอย่างอาจทำให้คุณกำหนดค่า R8 ไม่ถูกต้อง ซึ่งรวมถึงความเข้าใจผิดต่อไปนี้

  • ความเข้าใจผิดเกี่ยวกับการเพิ่มประสิทธิภาพของ R8: ตรงกันข้ามกับความเข้าใจทั่วไป การเพิ่มประสิทธิภาพของ R8 ไม่ได้จำกัดอยู่แค่การปรับโค้ดให้ยากต่อการอ่านเท่านั้น แต่ ยังรวมถึงการลดขนาดโค้ดและการเพิ่มประสิทธิภาพเชิงตรรกะด้วยเทคนิคการแทรกเมธอด และการผสานคลาส ดูข้อมูลเพิ่มเติมได้ที่ ภาพรวม การเพิ่มประสิทธิภาพ R8

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

  • ความเข้าใจผิดเกี่ยวกับตัวเลือก -keep กฎ -keep จะป้องกันไม่ให้ R8 เรียกใช้ การเพิ่มประสิทธิภาพ ใดๆ ดูข้อมูลเพิ่มเติมได้ที่ ดู เลือกตัวเลือกการเก็บรักษาที่เหมาะสม

ตรวจสอบคุณภาพกฎการเก็บรักษาสำหรับผู้ใช้

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

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

กำหนดค่าการแพ็กเกจกฎ

หากต้องการให้กฎการเก็บรักษาสำหรับผู้ใช้มีผลอย่างถูกต้อง คุณต้องแพ็กเกจกฎเหล่านี้อย่างเหมาะสมตามรูปแบบไลบรารี

ไลบรารี AAR

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

Kotlin

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

ดึงดูด

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 (ขั้นสูง)

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

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

Kotlin

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

ดึงดูด

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'

เพิ่มประสิทธิภาพ UI ของ Compose

หากไลบรารีมีคอมโพเนนต์ UI ของ Compose ให้เพิ่มประสิทธิภาพทั้งการลดขนาดไบนารีด้วย R8 (ตามที่อธิบายไว้ก่อนหน้านี้) และประสิทธิภาพการจัดองค์ประกอบใหม่

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

รองรับ 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 เวอร์ชันที่เขียนกฎไว้ ไดเรกทอรีย่อยแต่ละรายการอาจมีไฟล์อย่างน้อย 1 ไฟล์ที่มีกฎ R8 โดยใช้ชื่อไฟล์และนามสกุลใดก็ได้

โปรดทราบว่าส่วน -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 เวอร์ชัน 8.0.0 ขึ้นไป แต่ไม่รวม เวอร์ชัน 8.2.0 สามารถใช้กฎในไดเรกทอรี r8-from-8.0.0-upto-8.2.0 ได้

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