ในฐานะผู้เขียนไลบรารี คุณควรตรวจสอบว่านักพัฒนาแอปสามารถรวมไลบรารีของคุณเข้ากับแอปของตนได้อย่างง่ายดาย พร้อมทั้งรักษาประสบการณ์การใช้งานของผู้ใช้ปลายทางที่มีคุณภาพสูง คุณควรตรวจสอบว่าไลบรารีเข้ากันได้กับการเพิ่มประสิทธิภาพ Android โดยไม่ต้องตั้งค่าเพิ่มเติม หรือระบุว่าไลบรารีอาจไม่เหมาะสมสำหรับการใช้งานใน Android
เอกสารนี้มีไว้สำหรับนักพัฒนาไลบรารีที่เผยแพร่แล้ว แต่ก็อาจเป็นประโยชน์สำหรับนักพัฒนาโมดูลไลบรารีภายในในแอปขนาดใหญ่ที่แยกเป็นโมดูลด้วย
หากคุณเป็นนักพัฒนาแอปและต้องการดูข้อมูลเกี่ยวกับการเพิ่มประสิทธิภาพแอป Android โปรดดูเปิดใช้การเพิ่มประสิทธิภาพแอป ดูข้อมูลเกี่ยวกับไลบรารีที่เหมาะสม ที่จะใช้ได้ที่หัวข้อเลือกไลบรารีอย่างชาญฉลาด
ใช้ Codegen แทนการสะท้อน
หากเป็นไปได้ ให้ใช้การสร้างโค้ด (codegen) แทนการใช้การสะท้อน ทั้ง Codegen และ Reflection เป็นแนวทางทั่วไปในการหลีกเลี่ยง โค้ดบอยเลอร์เพลตเมื่อเขียนโปรแกรม แต่ Codegen จะเข้ากันได้ดีกว่ากับเครื่องมือเพิ่มประสิทธิภาพแอป อย่าง R8
- เมื่อใช้ Codegen ระบบจะวิเคราะห์และแก้ไขโค้ดในระหว่างกระบวนการบิลด์ เนื่องจากไม่มีการแก้ไขที่สำคัญหลังจากเวลาคอมไพล์ เครื่องมือเพิ่มประสิทธิภาพจึงทราบว่าโค้ดใดที่จำเป็นในท้ายที่สุดและโค้ดใดที่สามารถนำออกได้อย่างปลอดภัย
- การสะท้อนจะวิเคราะห์และจัดการโค้ดที่รันไทม์ เนื่องจากโค้ดจะยังไม่เสร็จสมบูรณ์จนกว่าจะมีการเรียกใช้ ตัวเพิ่มประสิทธิภาพจึงไม่ทราบว่าโค้ดใดที่นำออกได้อย่างปลอดภัย ซึ่งมีแนวโน้มที่จะนำโค้ดที่ใช้ แบบไดนามิกผ่านการสะท้อนในระหว่างรันไทม์ออก ซึ่งจะทำให้แอปขัดข้องสำหรับ ผู้ใช้
ไลบรารีที่ทันสมัยหลายแห่งใช้ Codegen แทนการสะท้อน ดู KSP สำหรับจุดแรกเข้าทั่วไปที่ใช้โดย Room Dagger2 และอื่นๆ อีกมากมาย
เมื่อการสะท้อนแสงเป็นเรื่องปกติ
หากจำเป็นต้องใช้การสะท้อน คุณควรสะท้อนเฉพาะในรายการใดรายการหนึ่งต่อไปนี้
- ประเภทเป้าหมายที่เฉพาะเจาะจง (ผู้ใช้ที่เฉพาะเจาะจงหรือคลาสย่อย)
- โค้ดที่ใช้คำอธิบายประกอบรันไทม์ที่เฉพาะเจาะจง
การใช้การสะท้อนในลักษณะนี้จะจำกัดต้นทุนรันไทม์ และช่วยให้เขียนกฎการเก็บรักษาที่กำหนดเป้าหมายผู้บริโภคได้
รูปแบบการสะท้อนที่เฉพาะเจาะจงและตรงเป้าหมายนี้เป็นรูปแบบที่คุณเห็นได้ทั้งในเฟรมเวิร์ก Android (เช่น เมื่อขยายกิจกรรม มุมมอง และ Drawable) และไลบรารี AndroidX (เช่น เมื่อสร้าง WorkManager
ListenableWorkers
หรือ RoomDatabases
) ในทางตรงกันข้าม การสะท้อนแบบเปิดของ Gson ไม่เหมาะสำหรับการใช้งานในแอป Android
ประเภทของกฎการเก็บในคลัง
กฎการเก็บมี 2 ประเภทที่แตกต่างกันซึ่งคุณใช้ได้ในคลัง
- กฎการเก็บรักษาของผู้บริโภคต้องระบุกฎที่เก็บรักษาทุกอย่างที่ไลบรารีแสดง หากไลบรารีใช้การสะท้อนหรือ JNI เพื่อเรียกใช้โค้ดของตัวเอง หรือ
โค้ดที่กำหนดโดยแอปไคลเอ็นต์ กฎเหล่านี้จะต้องอธิบายว่าต้องเก็บโค้ดใดไว้
ห้องสมุดควรจัดแพ็กเกจกฎการเก็บรักษาสำหรับผู้บริโภค ซึ่งใช้รูปแบบเดียวกับกฎการเก็บรักษาแอป กฎเหล่านี้จะรวมอยู่ในอาร์ติแฟกต์ของไลบรารี
(AAR หรือ JAR) และจะใช้โดยอัตโนมัติในระหว่างการเพิ่มประสิทธิภาพแอป Android
เมื่อมีการใช้ไลบรารี กฎเหล่านี้จะได้รับการดูแลในไฟล์ที่ระบุด้วยพร็อพเพอร์ตี้
consumerProguardFiles
ในไฟล์build.gradle.kts
(หรือbuild.gradle
) ดูข้อมูลเพิ่มเติมได้ที่เขียนกฎการเก็บรักษาสำหรับผู้บริโภค - ระบบจะใช้กฎการเก็บรักษาของบิลด์ไลบรารีเมื่อสร้างไลบรารี โดยจะจำเป็นก็ต่อเมื่อคุณตัดสินใจที่จะเพิ่มประสิทธิภาพไลบรารีบางส่วนในเวลาบิลด์เท่านั้น
โดยจะต้องป้องกันไม่ให้มีการนำ API สาธารณะของไลบรารีออก ไม่เช่นนั้น
API สาธารณะจะไม่ปรากฏในการเผยแพร่ไลบรารี ซึ่งหมายความว่านักพัฒนาแอป
จะใช้ไลบรารีไม่ได้ กฎเหล่านี้จะได้รับการดูแลในไฟล์ที่ระบุด้วยพร็อพเพอร์ตี้
proguardFiles
ในไฟล์build.gradle.kts
(หรือbuild.gradle
) ดูข้อมูลเพิ่มเติมได้ที่เพิ่มประสิทธิภาพการสร้างไลบรารี AAR
เขียนกฎการเก็บรักษาของผู้บริโภค
นอกเหนือจากคำแนะนำเกี่ยวกับกฎการเก็บรักษาทั่วไปแล้ว คำแนะนำต่อไปนี้เป็นคำแนะนำสำหรับผู้เขียนไลบรารีโดยเฉพาะ
- อย่าใช้กฎส่วนกลางที่ไม่เหมาะสม โดยหลีกเลี่ยงการใส่การตั้งค่าส่วนกลาง เช่น
-dontobfuscate
หรือ-allowaccessmodification
ในไฟล์กฎการเก็บรักษาสำหรับผู้บริโภคของไลบรารี เนื่องจากจะส่งผลต่อแอปทั้งหมดที่ใช้ไลบรารีของคุณ - อย่าใช้
-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
-overloadaggressively
-renamesourcefileattribute
-ignorewarnings
-addconfigurationdebugging
-printconfiguration
-printmapping
-printusage
-printseeds
-applymapping
-obfuscationdictionary
-classobfuscationdictionary
-packageobfuscationdictionary
ไลบรารี 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 สามารถใช้กฎในไดเรกทอรี
r8-from-8.0.0-upto-8.2.0
ได้ตั้งแต่เวอร์ชัน
8.0.0 จนถึงเวอร์ชัน 8.2.0 แต่ไม่รวมเวอร์ชัน 8.2.0
ปลั๊กอิน Android Gradle ใช้ข้อมูลดังกล่าวเพื่อเลือกกฎทั้งหมดที่เวอร์ชัน R8 ปัจจุบันใช้ได้ หากไลบรารีไม่ได้ระบุกฎ R8 ที่กำหนดเป้าหมายไว้ ปลั๊กอิน Android Gradle จะเลือกกฎจากตำแหน่งเดิม
(proguard.txt
สำหรับ AAR หรือ META-INF/proguard/<ProGuard-rule-files>
สำหรับ
JAR)