เมื่อคุณเปิดใช้การเพิ่มประสิทธิภาพแอปด้วยการตั้งค่าเริ่มต้น R8 จะเพิ่มประสิทธิภาพอย่างครอบคลุมเพื่อให้คุณได้รับประโยชน์สูงสุดจากประสิทธิภาพ R8 จะทําการแก้ไขโค้ดอย่างมีนัยสําคัญ ซึ่งรวมถึงการเปลี่ยนชื่อ ย้าย และนําฟิลด์และเมธอดของคลาสออก หากเกิดข้อผิดพลาด คุณต้องระบุส่วนใดของโค้ดที่จะไม่เปลี่ยนแปลงโดยเขียนกฎการเก็บรักษา
R8 อาจนำโค้ดออกหรือแก้ไขโค้ดอย่างไม่ถูกต้องในสถานการณ์ต่อไปนี้
- การสะท้อน: โค้ดที่เข้าถึงโดยใช้การสะท้อน เช่น ใช้
Class.forName()
หรือMethod.invoke()
โดยปกติแล้ว R8 จะไม่สามารถบอกได้ว่าคลาสหรือเมธอดใดที่จะเข้าถึงด้วยวิธีนี้ - การจัดรูปแบบข้อมูล: คลาสหรือฟิลด์ที่จําเป็นสําหรับการจัดรูปแบบข้อมูลและการถอดรูปแบบข้อมูลอาจดูเหมือนว่าไม่ได้ใช้งานกับ R8 (นี่คือรูปแบบการสะท้อนอีกรูปแบบหนึ่ง)
- Java Native Interface (JNI): เมธอด Java ที่เรียกจากโค้ดเนทีฟ R8 ไม่วิเคราะห์โค้ดเนทีฟเพื่อดูว่าโค้ดอาจเรียกใช้ Java อย่างไร
หน้านี้จะอธิบายวิธีจํากัดขอบเขตการเพิ่มประสิทธิภาพของ R8 ดูวิธีปรับแต่งทรัพยากรที่จะเก็บไว้ได้ที่เพิ่มกฎการเก็บรักษาสำหรับทรัพยากร
ตําแหน่งที่ควรเพิ่มกฎการเก็บ
คุณควรเพิ่มกฎลงในไฟล์ proguard-rules.pro
ซึ่งอยู่ในไดเรกทอรีรูทของโมดูล (ไฟล์อาจอยู่ในนั้นอยู่แล้ว แต่หากไม่มี ให้สร้างไฟล์) หากต้องการใช้กฎในไฟล์ คุณต้องประกาศไฟล์ในไฟล์ build.gradle.kts
(หรือ build.gradle
) ระดับโมดูลดังที่แสดงในโค้ดต่อไปนี้
Kotlin
android { buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile("proguard-android-optimize.txt"), // File with your custom rules. "proguard-rules.pro" ) ... } } ... }
Groovy
android { buildTypes { release { minifyEnabled true shrinkResources true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile('proguard-android-optimize.txt'), // File with your custom rules. 'proguard-rules.pro' ) } } // ... }
โดยค่าเริ่มต้น สคริปต์บิลด์จะรวมไฟล์ proguard-android-optimize.txt
ด้วย ไฟล์นี้มีกฎที่จำเป็นสำหรับโปรเจ็กต์ Android ส่วนใหญ่ คุณจึงควรเก็บไฟล์นี้ไว้ในสคริปต์การสร้าง
วิธีเขียนกฎการเก็บรักษา
ในระหว่างการคอมไพล์แอป R8 จะตรวจหาโค้ดที่ต้องเก็บไว้ในแอปโดยการวิเคราะห์กราฟการเรียกของแอป ซึ่งเริ่มต้นที่รายการไฟล์ Manifest (เช่น กิจกรรมหรือบริการ) และติดตามการเรียกฟังก์ชันของแอปและไลบรารีทุกรายการ R8 จะนําโค้ดที่ไม่ได้อ้างอิงโดยตรงด้วยวิธีนี้ออก ซึ่งอาจทําให้เกิดปัญหาหากโค้ดที่เรียกใช้ไม่ได้เป็นส่วนหนึ่งของกราฟนี้ เช่น โค้ดที่เรียกใช้โดยรีเฟล็กชัน การเขียนกฎการเก็บรักษาของคุณเองจะช่วยให้คุณแจ้ง R8 เกี่ยวกับโค้ดที่ต้องอยู่ในแอปได้
หากต้องการเพิ่มกฎการเก็บ ให้เพิ่มบรรทัด -keep
ในไฟล์ proguard-rules.pro
เก็บไวยากรณ์ของกฎ
โดยทั่วไปแล้ว กฎของ Keep จะใช้รูปแบบนี้
-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]
ตัวอย่างเช่น หากต้องการเก็บรักษาชั้นเรียนที่เฉพาะเจาะจงและสมาชิกทั้งหมดของชั้นเรียน ให้ใช้คำสั่งต่อไปนี้
-keep class com.myapp.MyClass { *; }
ดูตัวอย่างเพิ่มเติมได้ในส่วนตัวอย่าง
คอมโพเนนต์ของกฎการเก็บรักษาจะทําดังนี้
<KeepOption>
ช่วยให้คุณระบุแง่มุมของชั้นเรียนที่ต้องการเก็บรักษาได้ ดังนี้ตัวเลือก "เก็บ" คำอธิบาย -keep
เก็บรักษาชั้นเรียนและสมาชิกที่ระบุไว้ใน
[{ OptionalMemberSpecification }]
-keepclassmembers
อนุญาตให้เพิ่มประสิทธิภาพชั้นเรียน หากเก็บรักษาชั้นเรียนไว้ ให้เก็บรักษาสมาชิกที่แสดงใน
[{ OptionalMemberSpecification }]
-keepnames
อนุญาตให้นำชั้นเรียนและสมาชิกออก แต่อย่าสร้างความสับสนหรือแก้ไขด้วยวิธีอื่นๆ
-keepclassmembernames
อนุญาตให้นำชั้นเรียนและสมาชิกออก แต่ไม่สร้างความสับสนหรือแก้ไขสมาชิกด้วยวิธีอื่นๆ
-keepclasseswithmembers
ไม่นำชั้นเรียนออกหรือสร้างความสับสนให้กับชั้นเรียนหากสมาชิกตรงกับรูปแบบที่ระบุ
เราขอแนะนำให้ใช้
-keepclassmembers
เป็นหลัก เนื่องจากจะทําให้การเพิ่มประสิทธิภาพมากที่สุด จากนั้นจึงใช้-keepnames
หากจําเป็น-keep
ไม่อนุญาตให้ใช้การเพิ่มประสิทธิภาพใดๆ ดังนั้นโปรดใช้อย่างประหยัด[OptionalModifier],...]
ช่วยให้คุณแสดงตัวแก้ไขภาษา Java ของคลาสได้ตั้งแต่ 0 รายการขึ้นไป เช่นpublic
หรือfinal
<ClassSpecification>
ให้คุณระบุคลาส (หรือซุปเปอร์คลาสหรืออินเทอร์เฟซที่ใช้งาน) ที่กฎเก็บควรมีผล ในกรณีง่ายๆ คลาสนี้จะเป็นคลาสที่มีคุณสมบัติครบถ้วน 1 คลาส[{ OptionalMemberSpecification }]
ช่วยให้คุณกรองลักษณะการทำงาน "เก็บ" ไว้ได้เฉพาะคลาสและเมธอดที่ตรงกับรูปแบบบางอย่าง โดยทั่วไป เราขอแนะนําให้ใช้ตัวเลือกนี้ในกฎการเก็บรักษาส่วนใหญ่เพื่อป้องกันไม่ให้เก็บรักษาไว้มากกว่าที่ต้องการ
เก็บตัวอย่างกฎไว้
ตัวอย่างกฎการเก็บรักษาที่ออกแบบมาอย่างดีมีดังนี้
สร้างคลาสย่อย
กฎการเก็บรักษานี้จะรวมอยู่ใน androidx.room:room-runtime
เพื่อเก็บตัวสร้างฐานข้อมูลที่สร้างขึ้นโดยรีเฟล็กชัน
-keep class * extends androidx.room.RoomDatabase { void <init>(); }
การสะท้อนจากเฟรมเวิร์ก Android ObjectAnimator
กฎการเก็บรักษานี้จะรวมอยู่ใน androidx.vectordrawable:vectordrawable-animated
เพื่อให้ ObjectAnimator
เรียกใช้ getter หรือ setter จากโค้ดเนทีฟด้วย JNI ได้ โปรดทราบว่าระบบภาพเคลื่อนไหวรุ่นใหม่ในเครื่องมือเขียนโค้ดไม่จำเป็นต้องใช้กฎ keep เช่นนี้ เป็นเพียงตัวอย่างโครงสร้างกฎ
-keepclassmembers class androidx.vectordrawable.graphics.drawable.VectorDrawableCompat$* {
void set*(***);
*** get*();
}
การลงทะเบียน JNI
กฎการเก็บรักษานี้จะรวมอยู่ใน androidx.graphics:graphics-path
ใช้เพื่อเก็บเมธอดเดิม ซึ่งอาจจำเป็นหากไลบรารีของคุณลงทะเบียนเมธอดเนทีฟด้วย env->RegisterNatives()
ด้วยตนเอง
-keepclasseswithmembers class androidx.graphics.path.** {
native <methods>;
}