ProGuard/R8: การทำให้สับสนและการปกป้องแอปพลิเคชัน Android

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-02-14 เวลาอ่าน: 8 นาที

ProGuard และ R8 เป็นเครื่องมือทำให้สับสน ย่อขนาด และปรับแต่งประสิทธิภาพสำหรับแอปพลิเคชัน Android ProGuard สร้างขึ้นในปี 2002 เป็นมาตรฐานโดยพฤตินัยสำหรับการปกป้องโค้ด Java มาเป็นเวลานาน R8 เป็นผู้สืบทอด พัฒนาโดย Google และถูกผนวกเข้าใน Android Gradle Plugin ตั้งแต่ AGP 3.4 เครื่องมือทั้งสองลดขนาด APK ลบโค้ดที่ตายแล้ว และทำให้วิศวกรรมย้อนกลับซับซ้อนขึ้น ตาม Android Developers R8 สร้างบิลด์ได้เร็วกว่า ProGuard 2–3 เท่า โดยมีคุณภาพการทำให้สับสนเทียบเท่า

ประเด็นสำคัญ

  • ProGuard — เครื่องมือทำให้สับสนและปรับแต่งประสิทธิภาพ Java bytecode มาตรฐานสำหรับ Android ตั้งแต่ยุค 2000
  • R8 — ผู้สืบทอด ProGuard จาก Google ผนวกใน AGP ดำเนินการทำให้สับสน ย่อขนาด และปรับแต่งประสิทธิภาพในรอบเดียว
  • การทำให้สับสน เปลี่ยนชื่อคลาสและเมธอดเป็นชื่อสั้น ทำให้วิศวกรรมย้อนกลับของแอปซับซ้อนขึ้น
  • การย่อขนาด ลบคลาส เมธอด และฟิลด์ที่ไม่ได้ใช้งาน ลดขนาด APK/AAB สุดท้าย
  • ProGuard rules (ไฟล์ .pro) ควบคุมว่าส่วนใดของโค้ดถูกเก็บรักษา ทำให้สับสน หรือลบทิ้ง

ProGuard คืออะไร?

ProGuard เป็นเครื่องมือโอเพนซอร์ส (Apache 2.0) สำหรับทำให้สับสน ย่อขนาด ปรับแต่งประสิทธิภาพ และตรวจสอบล่วงหน้าของ Java bytecode พัฒนาโดย Eric Lafarge ในปี 2002 โดยเป็นส่วนหนึ่งของโครงการ SourceForge ProGuard รับคลาส Java ที่คอมไพล์แล้ว (.class) หรือคลังเก็บ JAR เป็นอินพุต และสร้างคลาสที่ประมวลผลแล้วในรูปแบบเดียวกัน แต่มีขนาดเล็กกว่าและมีองค์ประกอบที่ถูกเปลี่ยนชื่อ

เป็นเวลานาน ProGuard เป็นมาตรฐานเดียวในการปกป้องแอปพลิเคชัน Android จากวิศวกรรมย้อนกลับ Google แนะนำอย่างเป็นทางการให้ใช้งานใน Android SDK และจัดทำการกำหนดค่าเริ่มต้นในไฟล์ proguard-android-optimize.txt ภายในเครื่องมือ SDK ProGuard ทำงานเป็นเครื่องมือแยกต่างหาก ซึ่งทำงานหลังจากการคอมไพล์โค้ด Java เป็น bytecode และก่อนการบรรจุลงใน DEX

สถาปัตยกรรม ProGuard

ProGuard ประกอบด้วยสี่ขั้นตอนตามลำดับ: shrink (การลบคลาสที่ไม่ได้ใช้งาน), optimize (การปรับแต่ง bytecode — การแทรก, การลบโค้ดที่ตายแล้ว), obfuscate (การเปลี่ยนชื่อคลาส เมธอด และฟิลด์เป็นชื่อสั้น), preverify (การตรวจสอบความเข้ากันได้กับ JVM) แต่ละขั้นตอนถูกควบคุมโดยกฎแยกจากไฟล์กำหนดค่า

ในขั้นตอนการทำให้สับสน ProGuard สร้าง ไฟล์แมปปิง (mapping.txt) ที่จับคู่ชื่อดั้งเดิมกับชื่อที่ทำให้สับสน ไฟล์นี้มีความสำคัญอย่างยิ่งสำหรับการถอดรหัสบันทึกข้อขัดข้องจากบิลด์เผยแพร่ผ่านยูทิลิตี้ retrace หากไม่มีไฟล์แมปปิง รอยทางสแต็กจะกลายเป็นชุดตัวอักษร a(), b(), c() โดยไม่มีวิธีในการกู้คืนบริบทดั้งเดิม

ขั้นตอน ProGuardวัตถุประสงค์ผลลัพธ์
Shrinkการวิเคราะห์กราฟเรียกและการลบโค้ดที่ตายแล้วคลาสใน APK น้อยลง
Optimizeการแทรกเมธอด การลบพารามิเตอร์ที่ไม่ได้ใช้งานการทำงานของโค้ดเร็วขึ้น
Obfuscateการเปลี่ยนชื่อคลาส ฟิลด์ และเมธอดการป้องกันวิศวกรรมย้อนกลับ
Preverifyการเพิ่มแอตทริบิวต์ StackMap สำหรับ JVMความเข้ากันได้กับ Java 6+

R8 คืออะไร?

R8 เป็นเครื่องมือทำให้สับสนและย่อขนาดรุ่นถัดไปจาก Google เปิดตัวครั้งแรกใน Android Studio 3.3 (พฤศจิกายน 2018) และกลายเป็นมาตรฐานใน AGP 3.4 (สิงหาคม 2019) แตกต่างจาก ProGuard ตรงที่ R8 เป็นส่วนหนึ่งของคอมไพเลอร์ D8/R8 ซึ่งแปลง Java bytecode เป็นรูปแบบ DEX R8 ดำเนินการทุกขั้นตอน — การทำให้สับสน การย่อขนาด และการปรับแต่งประสิทธิภาพ — ในรอบเดียว โดยไม่ต้องส่งไฟล์กลางระหว่างเครื่องมือ

Google พัฒนา R8 ด้วยสองเป้าหมาย: เร่งความเร็วบิลด์ (ProGuard ทำงานเป็นเครื่องมือภายนอก) และให้การผสานรวมที่ราบรื่นกับสแต็ก Android สมัยใหม่ (Desugar, Core Library Desugaring, D8) R8 เขียนด้วย Kotlin และ Java และเป็นส่วนหนึ่งของพื้นที่เก็บ R8/Desugar บน AOSP (โครงการโอเพนซอร์ส Android)

ข้อได้เปรียบที่สำคัญของ R8 คือความเข้ากันได้ย้อนหลังอย่างสมบูรณ์กับกฎ ProGuard ไฟล์ .pro ที่มีอยู่ทำงานได้โดยไม่ต้องเปลี่ยนแปลง R8 ยังรองรับคำสั่ง ProGuard เฉพาะ รวมถึง -whyareyoukeeping, -printconfiguration และ -printmapping ซึ่งหมายความว่าการเปลี่ยนจาก ProGuard เป็น R8 นั้นโปร่งใส: เพียงอัปเดต AGP

kotlin
// build.gradle.kts — การเปิดใช้งาน R8 ผ่าน minifyEnabled
android {
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            isShrinkResources = true

            proguardFiles(
                // การกำหนดค่าพื้นฐานจาก Android SDK
                getDefaultProguardFile("proguard-android-optimize.txt"),
                // กฎโครงการที่กำหนดเอง
                "proguard-rules.pro"
            )
        }
    }
}

โค้ดแสดงการกำหนดค่าบิลด์เผยแพร่มาตรฐาน แฟล็ก isMinifyEnabled = true เปิดใช้งาน R8 สำหรับการทำให้สับสนและการปรับแต่งประสิทธิภาพ isShrinkResources = true ลบทรัพยากรที่ไม่ได้ใช้งานเพิ่มเติม getDefaultProguardFile โหลดกฎเริ่มต้นจาก SDK ในขณะที่ proguard-rules.pro มีการตั้งค่าเฉพาะโครงการ

การทำให้สับสนโค้ดใน Android

การทำให้สับสน เป็นกระบวนการแปลงโค้ดต้นฉบับเป็นรูปแบบที่มนุษย์วิเคราะห์ได้ยากแต่ยังคงฟังก์ชันการทำงานไว้อย่างสมบูรณ์ ในบริบท Android การทำให้สับสนหมายถึงการเปลี่ยนชื่อคลาส เมธอด และฟิลด์เป็นชื่อสั้นที่ไม่มีความหมาย: com.example.app.auth.LoginManager กลายเป็น a.a.a, เมธอด authenticateUser กลายเป็น a, ฟิลด์ userToken กลายเป็น b

ทำไมต้องทำให้สับสน

ไฟล์ APK Android เป็นคลังเก็บที่สามารถเปิดได้ด้วยโปรแกรมคลังเก็บใดๆ (ZIP, 7z, WinRAR) หากไม่มีการทำให้สับสน ผู้โจมตีจะได้รับแผนที่สมบูรณ์ของแอปพลิเคชัน: ชื่อแพ็กเกจ คลาส เมธอด และฟิลด์ เครื่องมืออย่าง jadx หรือ Bytecode Viewer สามารถกู้คืนโค้ด Java ที่เกือบเหมือนต้นฉบับจากไฟล์ DEX ได้ในไม่กี่วินาที การทำให้สับสนไม่ได้ทำให้โค้ดคงกระพัน แต่เพิ่มอุปสรรคในการเข้าถึงอย่างมาก: แทนที่จะเป็นชื่อที่มีความหมาย ผู้อ่านจะเห็น a(), b(), c()

เป้าหมายทั่วไปของการทำให้สับสน: ปกป้องตรรกะทางการค้า (อัลกอริทึม สูตรคำนวณ) ขัดขวางการขโมยคีย์ API และโทเคน ป้องกันการแทนที่คลาสผ่าน reflection และป้องกันการแก้ไขและการบรรจุซ้ำ APK (การโจมตีแบบ repackage) ในทางปฏิบัติ 70% ของงานแก้ไขได้ด้วยการเปลี่ยนชื่อเพียงอย่างเดียว — นี่คือเหตุผลที่ใช้ ProGuard/R8

ตัวอย่างกฎ ProGuard

ด้านล่างคือไฟล์ proguard-rules.pro ทั่วไปสำหรับโครงการ Android ที่ใช้ Retrofit, Gson และ Parcelable กฎ -keep เก็บรักษาคลาสและเมธอดที่จำเป็นสำหรับการทำงานของไลบรารีผ่าน reflection หากไม่มีกฎเหล่านี้ R8 จะลบหรือเปลี่ยนชื่อคลาสที่ไลบรารีเข้าถึงด้วยชื่อสตริง

pro
# =====================
# Retrofit — การเก็บรักษาอินเทอร์เฟส
# =====================
-keep,allowobfuscation,allowshrinking interface retrofit2.** { *; }
-keepattributes Signature, Exceptions

# =====================
# Gson — การทำให้เป็นอนุกรม JSON
# =====================
-keepclassmembers class * {
    @com.google.gson.annotations.SerializedName <fields>;
}
-keep class *.serialization.** {
    <fields>;
}

# =====================
# Parcelable — Creator
# =====================
-keepclassmembers class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator CREATOR;
}

# =====================
# Logging — การลบบันทึกจากรุ่นเผยแพร่
# =====================
-assumenosideeffects class android.util.Log {
    public static boolean isLoggable(String, int);
    public static int v(...);
    public static int d(...);
    public static int i(...);
    public static int w(...);
    public static int e(...);
}

# =====================
# คลาสข้อมูล Kotlin — การเก็บรักษาคอนสตรัคเตอร์
# =====================
-keepclassmembers class * {
    @kotlin.Metadata <fields>;
}

# =====================
# Activity — จุดเข้า
# =====================
-keep class * extends android.app.Activity {
    @android.annotation.SuppressLint <methods>;
}

แต่ละคำสั่งในไฟล์ .pro แก้ปัญหางานเฉพาะ -keep ป้องกันไม่ให้คลาสทั้งหมดถูกลบหรือเปลี่ยนชื่อ -keepclassmembers ปกป้องเฉพาะสมาชิกคลาส (ฟิลด์และเมธอด) แต่อนุญาตให้ลบคลาสเองได้หากไม่ได้ใช้งาน -assumenosideeffects บอก R8 ว่าการเรียกเมธอดไม่มีผลข้างเคียงและสามารถลบได้อย่างปลอดภัย คำสั่ง -keepattributes เก็บรักษาข้อมูลเมตาใน bytecode — คำอธิบายประกอบ ลายเซ็น ข้อยกเว้น

กฎ -keep,allowobfuscation,allowshrinking สำหรับ Retrofit อนุญาตให้ R8 เปลี่ยนชื่ออินเทอร์เฟสแต่ไม่ลบทิ้ง นี่เป็นสิ่งจำเป็นเพราะ Retrofit เข้าถึงอินเทอร์เฟสผ่านพร็อกซีไดนามิก (java.lang.reflect.Proxy) และการลบจะทำให้เกิด ClassNotFoundException ในรันไทม์ เช่นเดียวกัน Gson ใช้ reflection เพื่อเข้าถึงฟิลด์ที่มีคำอธิบายประกอบ @SerializedName — หากไม่มี -keepclassmembers ฟิลด์จะถูกลบว่าไม่ได้ใช้งาน

การย่อขนาดและ ShrinkResources

การย่อขนาด (shrinking) เป็นกระบวนการลบโค้ดและทรัพยากรที่ไม่ได้ใช้งานออกจากบิลด์สุดท้าย ProGuard และ R8 วิเคราะห์กราฟเรียกเริ่มต้นจากจุดเข้า (Activity, Service, BroadcastReceiver) และลบคลาสและเมธอดที่ไม่สามารถเข้าถึงได้ผ่านห่วงโซ่การเรียก ShrinkResources เป็นขั้นตอนเพิ่มเติมที่ลบทรัพยากรที่ไม่ได้ใช้งานจาก res/ (layout, drawable, string, color)

การย่อขนาดให้ประโยชน์มากที่สุดในโครงการขนาดใหญ่ที่มีไลบรารี สถานการณ์ทั่วไป: โครงการใช้โค้ด 10% จากไลบรารีที่เชื่อมต่อ (เช่น Google Play Services) หากไม่มีการย่อขนาด โค้ดไลบรารีทั้งหมดจะเข้าไปใน APK ด้วยการย่อขนาด R8 จะลบโค้ดไลบรารี 70–90% เหลือเพียงคลาสและเมธอดที่ใช้งานจริง สิ่งนี้ส่งผลโดยตรงต่อขนาด APK เวลาโหลด และการใช้หน่วยความจำ

ShrinkResources ในการทำงาน

กลไก ShrinkResources ทำงานร่วมกับการย่อขนาดโค้ด หลังจากที่ R8 กำหนดว่าคลาสใดถูกใช้งาน การย่อทรัพยากรจะวิเคราะห์การอ้างอิงทรัพยากรจากโค้ด: R.layout.main, R.drawable.icon, getString(R.string.title) ทรัพยากรทั้งหมดที่ไม่มีการอ้างอิงโดยตรงหรือโดยอ้อมจะถูกลบออกจาก APK หรือ AAB สุดท้าย ซึ่งทำได้โดยใช้ไฟล์ทรัพยากร resources.arsc และโฟลเดอร์ res/

ความละเอียดอ่อนที่สำคัญ: ทรัพยากรสามารถเข้าถึงได้ผ่าน getIdentifier() หรือ Resources.getResourceName() ด้วยชื่อสตริง โดยข้ามคลาส R ในกรณีดังกล่าว R8 จะไม่เห็นการเชื่อมโยงโดยตรงและอาจลบทรัพยากรที่ใช้งานจริง เพื่อป้องกันทรัพยากรดังกล่าว มีคำสั่ง -keep class **.R$* { *; } — มันเก็บรักษาตัวระบุทั้งหมดของคลาส R

xml
<!-- ตัวอย่าง: ทรัพยากรที่ใช้ผ่าน getIdentifier() เท่านั้น -->
<string name="dynamic_title_welcome">ยินดีต้อนรับ</string>
<string name="dynamic_title_share">แชร์</string>

<!-- โค้ด Kotlin ที่เข้าถึงโดยสตริง -->
<!-- val title = getString(resources.getIdentifier( -->
<!--     \"dynamic_title_${type}\", \"string\", packageName)) -->

ในกรณีนี้ R8 ไม่เห็นการอ้างอิงแบบคงที่ไปยัง dynamic_title_welcome ในคลาส R เนื่องจากการเข้าถึงผ่าน getIdentifier ด้วยชื่อไดนามิก เพื่อรักษาทรัพยากรดังกล่าว ให้เพิ่มคำสั่ง -keepclassmembers class **.R$string { *; } ลงใน proguard-rules.pro — มันป้องกันการลบฟิลด์ใดๆ จากคลาส R$string ทั้งหมด

คำสั่งวัตถุประสงค์ตัวอย่าง
-keepเก็บรักษาคลาสและสมาชิกทั้งหมด-keep class com.example.api.** { *; }
-keepclassmembersเก็บรักษาเฉพาะสมาชิกคลาส-keepclassmembers class * { @SerializedName <fields>; }
-keepattributesเก็บรักษาข้อมูลเมตา bytecode-keepattributes *Annotation*, Signature
-assumenosideeffectsลบการเรียกที่ไม่มีผลข้างเคียง-assumenosideeffects class Log { d(...); }
-dontwarnระงับคำเตือน-dontwarn com.example.legacy.**

R8 vs ProGuard: ความแตกต่างหลัก

แม้ว่า R8 จะเป็นผู้สืบทอดของ ProGuard แต่ก็มีความแตกต่างพื้นฐานระหว่างเครื่องมือในด้านสถาปัตยกรรม ประสิทธิภาพ และพฤติกรรม Google ยุติการสนับสนุน ProGuard ใน Android Gradle Plugin อย่างเป็นทางการตั้งแต่ AGP 7.0 แต่ ProGuard ยังคงใช้ในโครงการที่ต้องการพฤติกรรมการปรับแต่งประสิทธิภาพเฉพาะที่ไม่มีใน R8

ตารางเปรียบเทียบ

คุณลักษณะProGuardR8
ผู้พัฒนาGuardSquare (Eric Lafarge)Google
ปีที่เปิดตัว20022018 (เสถียรในปี 2019)
สถาปัตยกรรม4 ขั้นตอนแยก (shrink → optimize → obfuscate → preverify)รอบเดียว: shrink + optimize + obfuscate พร้อมกัน
การผสานรวม AGPเครื่องมือภายนอก ทำงานหลัง javacผนวกในคอมไพเลอร์ D8 DEX
ความเร็วบิลด์ช้ากว่า 2–3 เท่าเร็วกว่าเนื่องจากรอบเดียวและการผสานรวมแบบเนทีฟ
การสนับสนุน Kotlinจำกัด (ปัญหากับ inline, lambdas, coroutines)สมบูรณ์: coroutines, ฟังก์ชัน inline, data class
ไฟล์แมปปิงmapping.txt (เข้ากันได้กับ retrace)mapping.txt (รูปแบบเดียวกัน)
การปรับแต่งประสิทธิภาพ60+ ตัวเลือก -optimizationpasses, -optimizationsจำกัด: การปรับแต่งส่วนใหญ่เปิดใช้งานโดยค่าเริ่มต้น
สถานะการสนับสนุนถูกแทนที่โดย R8 (AGP 7.0+ ไม่ใช้)การพัฒนาที่กำลังดำเนินการ ส่วนหนึ่งของ AOSP

เมื่อ R8 อาจทำให้บิลด์เสีย

R8 ดำเนินการลบโค้ดที่คิดว่าตายแล้วอย่างก้าวร้าวกว่า ProGuard ซึ่งนำไปสู่สถานการณ์ที่บิลด์ดีบักทำงานแต่บิลด์เผยแพร่ล้มเหลวด้วย ClassNotFoundException หรือ NoSuchMethodException กรณีทั่วไป: ไลบรารีที่ใช้ reflection ตามชื่อคลาส (Gson, Moshi, Retrofit, Room, Dagger); การเรียก ServiceLoader หรือ java.util.ServiceLoader; พร็อกซีไดนามิก (java.lang.reflect.Proxy); เมธอดเนทีฟ (JNI) วิธีแก้ไขคือเพิ่ม -keep สำหรับคลาสทั้งหมดที่ถูกเรียกผ่าน reflection

pro
# ปัญหา reflection ทั่วไป — R8 ไม่เห็นการเชื่อมโยงแบบคงที่

# Room — การเก็บรักษา DAO และการโยกย้าย
-keep class * extends androidx.room.RoomDatabase { *; }
-keep class *.DatabaseMigrations { *; }

# Dagger / Hilt — การเก็บรักษาคอมโพเนนต์
-keep class * extends dagger.hilt.android.components.** { *; }

# JNI — ไม่เปลี่ยนชื่อเมธอดเนทีฟ
-keepclasseswithmembernames class * {
    native <methods>;
}

# Data Binding — การเก็บรักษาคลาส Binding
-keep class *.databinding.** { *; }

หากหลังจากเพิ่มกฎแล้วบิลด์ยังคงล้มเหลว ให้ใช้แฟล็ก -printconfiguration full-config.txt ใน proguard-rules.pro R8 จะสร้างไฟล์กำหนดค่าที่สมบูรณ์ซึ่งแสดงกฎที่ใช้และคลาสที่ถูกเก็บรักษา คำสั่ง -whyareyoukeeping class com.example.MyClass ก็มีประโยชน์เช่นกัน — มันแสดงเหตุผลที่ R8 ตัดสินใจเก็บรักษาคลาสที่กำหนด

การกำหนดค่า ProGuard Rules

การกำหนดค่า ProGuard rules ที่เหมาะสมเป็นกุญแจสำคัญสำหรับการทำให้สับสนที่เสถียรโดยไม่มีบักในรันไทม์ ด้านล่างคือกระบวนการตั้งค่าทีละขั้นตอนสำหรับโครงการใหม่หรือสำหรับโครงการที่การทำให้สับสนทำให้เกิดข้อผิดพลาด

ขั้นตอนที่ 1: การกำหนดค่าพื้นฐาน

เริ่มต้นด้วยการรวมไฟล์ Android SDK มาตรฐาน — proguard-android-optimize.txt ซึ่งมีกฎสำหรับส่วนประกอบพื้นฐาน Android: Activity, Service, BroadcastReceiver, ContentProvider, View, Fragment ไฟล์นี้อยู่ในโฟลเดอร์ SDK: $ANDROID_HOME/tools/proguard/proguard-android-optimize.txt หากคุณใช้ AGP getDefaultProguardFile จะโหลดโดยอัตโนมัติ

ขั้นตอนที่ 2: ไลบรารี

ไลบรารียอดนิยมแต่ละแห่งมีกฎ ProGuard ที่แนะนำ Retrofit, OkHttp, Glide, Fresco, Coil, Room, Dagger/Hilt, Kotlin Coroutines — ทั้งหมดต้องการกฎ -keep เฉพาะ โดยปกติกฎจะรวมอยู่ในไลบรารี AAR และเชื่อมโยงโดยอัตโนมัติผ่านกฎผู้บริโภค ตรวจสอบว่าไลบรารีมีไฟล์ proguard.txt ภายใน AAR หรือไม่ — ซึ่งบ่งชี้ว่ากฎได้ถูกนำมาพิจารณาแล้ว

ขั้นตอนที่ 3: การทดสอบบิลด์เผยแพร่

ก่อนเผยแพร่ ต้องทดสอบบิลด์เผยแพร่บนอุปกรณ์จริงหรืออีมูเลเตอร์ ปัญหาการทำให้สับสนจะปรากฏเฉพาะในรันไทม์ ตรวจสอบ: การรับรองความถูกต้อง (เข้าสู่ระบบ/ลงทะเบียน), การโหลดข้อมูลจากเครือข่าย, การนำทางระหว่างหน้าจอ, กล้องและแกลเลอรี, การแจ้งเตือนแบบพุช, Deeplinks, WebView แต่ละข้อขัดข้องในบิลด์เผยแพร่ต้องถอดรหัสโดยใช้ retrace ด้วยไฟล์แมปปิง และเพิ่มกฎ -keep ที่ขาดหายไป

ขั้นตอนที่ 4: ไฟล์แมปปิงและ CI

ไฟล์แมปปิงถูกสร้างขึ้นที่ build/outputs/mapping/release/mapping.txt ไฟล์นี้ต้องเก็บรักษาไว้: หากไม่มีจะไม่สามารถถอดรหัสบันทึกข้อขัดข้องจาก Google Play Console รวม mapping.txt ในระบบควบคุมเวอร์ชันของคุณหรืออัปโหลดเป็นสิ่งประดิษฐ์ CI Google Play Console ยอมรับไฟล์แมปปิงโดยอัตโนมัติเมื่ออัปโหลด AAB โดยเปิดใช้งาน uploading mapping.txt

ด้านล่างคือเวิร์กโฟลว์การตั้งค่าการทำให้สับสนที่สมบูรณ์ในไฟล์ proguard-rules.pro พร้อมความคิดเห็นสำหรับกฎแต่ละกลุ่ม

pro
# ===========================================
# proguard-rules.pro — ตัวอย่างที่สมบูรณ์
# ===========================================

# --- การตั้งค่าทั่วไป ---
-keepattributes *Annotation*, Signature, Exceptions, InnerClasses, EnclosingMethod
-dontpreverify

# --- คอมโพเนนต์ Android ---
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.Fragment
-keep public class * extends androidx.fragment.app.Fragment
-keep public class * extends android.view.View

# --- OkHttp / Retrofit ---
-dontwarn okhttp3.**
-dontwarn okio.**
-keep class retrofit2.** { *; }
-keepattributes Exceptions

# --- Gson / Moshi ---
-keepclassmembers class * {
    @com.google.gson.annotations.SerializedName <fields>;
}
-keep class com.google.gson.** { *; }

# --- Firebase ---
-keep class com.google.firebase.** { *; }
-keep class com.google.android.gms.** { *; }

# --- Kotlin Coroutines ---
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}

# --- การทำให้เป็นอนุกรม ---
-keepclassmembers class * implements java.io.Serializable {
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# --- เฉพาะ R8: การเก็บรักษาแบบบังคับ ---
# (ProGuard ไม่สนใจคำสั่งนี้)
-keep,allowobfuscation class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator CREATOR;
}

หลังจากการกำหนดค่า ให้รันบิลด์: ./gradlew assembleRelease ตรวจสอบว่าไฟล์ปรากฏใน build/outputs/mapping/release/: mapping.txt (การจับคู่ชื่อดั้งเดิมกับชื่อที่ทำให้สับสน), seeds.txt (คลาสที่เก็บรักษาโดยกฎ -keep), usage.txt (คลาสที่ถูกลบระหว่างการย่อขนาด) ขนาด APK หลังการทำให้สับสนควรลดลง 20–50% ขึ้นอยู่กับจำนวนไลบรารีที่เชื่อมต่อ

คำถามที่พบบ่อย

R8 แตกต่างจาก ProGuard อย่างไร?

R8 เป็นผู้สืบทอดของ ProGuard พัฒนาโดย Google R8 ดำเนินการทำให้สับสน ย่อขนาด และปรับแต่งประสิทธิภาพในรอบเดียว ทำงานเร็วกว่า ProGuard 2–3 เท่า และผสานรวมโดยตรงใน Android Gradle Plugin ProGuard ใช้สี่ขั้นตอนแยกและต้องการการทำงานภายนอก ตั้งแต่ AGP 7.0 ProGuard ไม่ถูกใช้ — R8 ทำงานโดยค่าเริ่มต้น

ฉันต้องเขียน ProGuard rules เมื่อใช้ R8 หรือไม่?

ใช่ R8 ใช้ ProGuard rules เดียวกัน (ไฟล์ .pro) คำสั่ง -keep, -keepclassmembers, -keepattributes, -assumenosideeffects ทำงานเหมือนกัน กฎพื้นฐานมาใน proguard-android-optimize.txt จาก Android SDK ในขณะที่กฎเฉพาะไลบรารี (Retrofit, Room, Gson) จะถูกเพิ่มใน proguard-rules.pro ของโครงการ หากไม่มีกฎเหล่านี้ R8 อาจลบคลาสที่จำเป็นสำหรับไลบรารีที่ทำงานผ่าน reflection

วิธีเปิดใช้งาน R8 ในโครงการ Android?

R8 เปิดใช้งานโดยค่าเริ่มต้นใน Android Gradle Plugin ตั้งแต่ AGP 3.4 เปิดใช้งานการย่อขนาดโดยตั้งค่า isMinifyEnabled = true ในบล็อก release buildType ของไฟล์ build.gradle.kts แฟล็กเพิ่มเติม isShrinkResources = true เปิดใช้งานการลบทรัพยากรที่ไม่ได้ใช้งาน ใน gradle.properties คุณสามารถปิด R8 แบบบังคับผ่าน android.enableR8=false แต่ไม่แนะนำ — R8 เร็วกว่าและเสถียรกว่า

การทำให้สับสนโค้ดใน Android คืออะไร?

การทำให้สับสน — การเปลี่ยนชื่อคลาส เมธอด และฟิลด์เป็นชื่อสั้นที่ไม่มีความหมาย (a, b, c) คลาส com.example.app.auth.LoginManager กลายเป็น a.a.a เมธอด authenticateUser กลายเป็น a สิ่งนี้ทำให้วิศวกรรมย้อนกลับของแอปพลิเคชันซับซ้อนขึ้นแต่ไม่ส่งผลต่อตรรกะการทำงาน ProGuard และ R8 เปลี่ยนชื่อเฉพาะองค์ประกอบที่ไม่ได้รับการปกป้องโดยกฎ -keep ไฟล์แมปปิงเก็บรักษาความสอดคล้องของชื่อดั้งเดิมและชื่อที่ทำให้สับสนสำหรับการถอดรหัสบันทึกข้อขัดข้อง

วิธีดีบักบันทึกข้อขัดข้องจากแอปพลิเคชันที่ทำให้สับสน?

ในการถอดรหัสรอยทางส택 ให้ใช้ยูทิลิตี้ retrace (ส่วนหนึ่งของ ProGuard/R8 SDK) คำสั่ง: retrace mapping.txt crash-stacktrace.txt ไฟล์แมปปิงอยู่ที่ build/outputs/mapping/release/mapping.txt Google Play Console รองรับการอัปโหลด mapping.txt เมื่อเผยแพร่ AAB — บันทึกข้อขัดข้องจะถูกถอดรหัสโดยอัตโนมัติในคอนโซล หากไม่มีไฟล์แมปปิง รอยทางสแต็กจะมีเพียงชื่อที่ทำให้สับสน เช่น a.b.c() ซึ่งไม่มีประโยชน์สำหรับการดีบัก

สรุป

  • ProGuard — เครื่องมือทำให้สับสนและปรับแต่งประสิทธิภาพ Java bytecode แบบคลาสสิก ประกอบด้วยสี่ขั้นตอนตามลำดับ
  • R8 — ผู้สืบทอดสมัยใหม่จาก Google ผนวกใน AGP ดำเนินการทุกขั้นตอนในรอบเดียวด้วยประสิทธิภาพสูงกว่า 2–3 เท่า
  • การทำให้สับสน เปลี่ยนชื่อคลาส เมธอด และฟิลด์เป็นชื่อสั้น ทำให้วิศวกรรมย้อนกลับซับซ้อนและปกป้องตรรกะทางการค้าของแอปพลิเคชัน
  • การย่อขนาด ลบโค้ดและทรัพยากรที่ไม่ได้ใช้งาน ลดขนาด APK 20–50% ในโครงการทั่วไป
  • ProGuard rules (ไฟล์ .pro) ควบคุมพฤติกรรมการทำให้สับสน — คำสั่ง -keep, -keepclassmembers, -assumenosideeffects ระบุว่าองค์ประกอบใดถูกเก็บรักษา ลบ หรือเปลี่ยนชื่อ
  • ไฟล์แมปปิง (mapping.txt) เป็นสิ่งประดิษฐ์บิลด์ที่สำคัญอย่างยิ่งสำหรับการถอดรหัสบันทึกข้อขัดข้องจากบิลด์เผยแพร่ผ่าน retrace
  • การทดสอบ บิลด์เผยแพร่บนอุปกรณ์จริงเป็นสิ่งจำเป็น — ปัญหาการทำให้สับสนจะปรากฏเฉพาะในรันไทม์และต้องการการเพิ่มกฎ -keep ที่ขาดหายไป

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม