ProGuard — เครื่องมือสำหรับการบีบอัด เพิ่มประสิทธิภาพ และทำให้ Java bytecode สับสน ซึ่งถูกรวมอยู่ใน Android SDK เพื่อป้องกันแอปพลิเคชันจากการ reverse-engineering ตามข้อมูลจาก Google I/O Security Session (2025), การตั้งค่า ProGuard ที่ถูกต้อง ช่วยลดขนาด APK ได้ 15-25% และลดความเสี่ยงในการรั่วไหลของโค้ดลง 60% เครื่องมือนี้กลายเป็นมาตรฐานสำหรับการพัฒนา Android และถูกใช้ในแอปพลิเคชันนับล้านทั่วโลก
สาระสำคัญ
ProGuard — เครื่องมือที่เผยแพร่แบบฟรีสำหรับการประมวลผล Java bytecode พัฒนาโดยบริษัท Guardsquare มันถูกรวมอยู่ใน Android SDK และทำหน้าที่สำคัญสามประการ: การบีบอัด (shrinking) การเพิ่มประสิทธิภาพ (optimization) และการทำให้โค้ดสับสน (obfuscation) ProGuard วิเคราะห์ bytecode ทั้งหมดของแอปพลิเคชันและ dependencies ของมัน ระบุคลาสและเมธอดที่ไม่ได้ใช้งาน ลบทิ้ง จากนั้น ทำให้สับสน โค้ดที่เหลือ
ProGuard ถูกสร้างโดย Eric Lafarge ในปี 2000 โดยเป็นเครื่องมือเพิ่มประสิทธิภาพสำหรับแอปพลิเคชัน Java เมื่อ Android ปรากฏในปี 2008 ProGuard ถูกรวมเข้ากับ Android SDK และกลายเป็นเครื่องมือมาตรฐานสำหรับการป้องกันแอปพลิเคชัน ตามสถิติของ Guardsquare (2024), ProGuard ถูกใช้ใน มากกว่า 80% ของแอปพลิเคชันจาก Google Play รวมถึงแอปพลิเคชันของธนาคารขนาดใหญ่และบริษัทเทคโนโลยี
ProGuard ดำเนินการประมวลผลในสี่ขั้นตอน ในขั้นตอนแรก (shrink) เครื่องมือจะวิเคราะห์จุดเข้าใช้งานของแอปพลิเคชันและระบุว่าคลาส เมธอด และฟิลด์ใดบ้างที่สามารถเข้าถึงได้ระหว่างการทำงาน ในขั้นตอนที่สอง (optimize) ProGuard จะแปลง bytecode เพื่อเพิ่มประสิทธิภาพการทำงาน ขั้นตอนที่สาม (obfuscate) จะเปลี่ยนชื่อตัวระบุ ในขั้นตอนสุดท้าย preverify จะเพิ่ม metadata ที่จำเป็นสำหรับการตรวจสอบ bytecode บนเครื่องเสมือน
มาดูรายละเอียดแต่ละฟังก์ชันหลักทั้งสามของ ProGuard กัน: การบีบอัด การเพิ่มประสิทธิภาพ และการทำให้โค้ดสับสน การเข้าใจกลไกแต่ละอย่างจะช่วยให้ตั้งค่าเครื่องมือได้อย่างเหมาะสมที่สุด
ProGuard วิเคราะห์กราฟการเรียกจากจุดเข้าใช้งาน (main-method, Activity, BroadcastReceiver) และลบโค้ดที่ไม่ได้ใช้งาน ในโปรเจกต์ Android ทั่วไปที่มีไลบรารีอย่าง Retrofit, OkHttp และ Gson การบีบอัดสามารถลบ bytecode ได้ถึง 40% รวมถึงเมธอดของไลบรารีที่ไม่ได้ใช้งาน โค้ด debug และคลาสทดสอบ ซึ่งช่วยลดขนาด APK และลดเวลาในการโหลดแอปพลิเคชันโดยตรง
ในขั้นตอน การเพิ่มประสิทธิภาพ ProGuard ดำเนินการแปลง bytecode มากกว่า 20 รูปแบบ: การ inline เมธอดสั้น ๆ การลบพารามิเตอร์ที่ไม่ได้ใช้งาน การทำให้ expressions ทางตรรกะง่ายขึ้น การรวมบล็อกโค้ดที่เหมือนกัน ตัวอย่างเช่น getter และ setter สั้น ๆ สามารถถูกแทนที่ด้วยการเข้าถึงฟิลด์โดยตรง การเพิ่มประสิทธิภาพสามารถเร่งความเร็วการทำงานของโค้ดได้ 5-15% ขึ้นอยู่กับโครงสร้างของแอปพลิเคชัน
การทำให้โค้ดสับสน ใน ProGuard ทำงานโดยการเปลี่ยนชื่อคลาส เมธอด และฟิลด์เป็นลำดับตัวอักษรสั้น ๆ: a, b, c, a.a, a.b และอื่น ๆ การอ้างอิงทั้งหมดไปยังองค์ประกอบที่ถูกเปลี่ยนชื่อจะถูกอัปเดตโดยอัตโนมัติทั่วทั้งโค้ด สิ่งสำคัญที่ต้องทราบคือ การทำให้โค้ดสับสนไม่ได้เปลี่ยนพฤติกรรมของโปรแกรม แต่เพียงทำให้ การเข้าใจ โค้ดที่ถูก decompile ยากขึ้นเท่านั้น ไลบรารีและ API สาธารณะควรถูกแยกออกจากการทำให้โค้ดสับสนผ่านกฎ keep
// ก่อนการใช้ ProGuard
public class LoginManager {
public User authenticateUser(String username, String password) {
// ตรรกะการตรวจสอบสิทธิ์
}
}
// หลังการใช้ ProGuard
public class a {
public Object a(String b, String c) {
// ตรรกะเดียวกันกับชื่อที่ถูกเปลี่ยนใหม่
}
}
การกำหนดค่า ProGuard — เป็นขั้นตอนสำคัญในการตั้งค่าบิลด์ของแอปพลิเคชัน Android กฎที่ไม่ถูกต้องอาจนำไปสู่การลบคลาสที่จำเป็น และส่งผลให้เกิด crash ในเวอร์ชัน release
การเปิดใช้งาน ProGuard ในโปรเจกต์ Android รวมถึงการตั้งค่า flag minifyEnabled เป็น true สำหรับบิลด์ประเภท release กฎมาตรฐานของ ProGuard มาพร้อมกับ Android SDK ในไฟล์ proguard-android-optimize.txt กฎที่ผู้ใช้กำหนดจะถูกเพิ่มในไฟล์แยกต่างหาก proguard-rules.pro เมื่อบิลด์ ProGuard จะใช้กฎมาตรฐานก่อน จากนั้นจึงใช้กฎที่ผู้ใช้กำหนด ซึ่งช่วยให้ แทนที่ การกำหนดค่าพื้นฐานได้
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(
'proguard-android-optimize.txt'
), 'proguard-rules.pro'
}
}
}
ไฟล์ กฎ ที่ผู้ใช้กำหนดประกอบด้วยคำสั่งเฉพาะสำหรับโปรเจกต์นั้น ๆ กฎทั่วไปรวมถึงการเก็บคลาสที่ใช้ผ่าน reflection โมเดลข้อมูลสำหรับ serialization แบบ Gson/Moshi อินเทอร์เฟซ callback ของไลบรารี และคลาสที่มี annotation เฉพาะ แต่ละคำสั่งเริ่มต้นด้วยคีย์เวิร์ด -keep, -dontwarn หรือ -keepclassmembers และกำหนด รูปแบบ ของคลาสที่ ProGuard ไม่ควรเปลี่ยนแปลง
# เก็บโมเดลข้อมูลสำหรับ Gson
-keep class com.example.data.model.** { *; }
# เก็บคลาสที่ใช้ผ่าน reflection
-keep class * implements com.google.gson.TypeAdapterFactory
# ไม่สนใจคำเตือนของไลบรารี
-dontwarn okhttp3.internal.**
-dontwarn retrofit2.**
# เก็บ enum (ลักษณะเฉพาะของ ProGuard)
-keep class * extends java.lang.Enum { *; }
ไวยากรณ์การกำหนดค่า ProGuard รวมถึงคำสั่งหลายหมวดหมู่ ซึ่งแต่ละหมวดหมู่ควบคุมลักษณะเฉพาะของการประมวลผล มาดูคำสั่งหลักที่จำเป็นสำหรับการตั้งค่าที่ถูกต้องกัน
| คำสั่ง | วัตถุประสงค์ | ตัวอย่าง |
|---|---|---|
| -keep | เก็บคลาสและสมาชิกทั้งหมดไว้ | -keep class com.example.MyClass |
| -keepclassmembers | เก็บเฉพาะสมาชิกของคลาส | -keepclassmembers class * { @Inject *; } |
| -dontwarn | ไม่สนใจคำเตือน | -dontwarn okhttp3.internal.** |
| -keepparameternames | เก็บชื่อพารามิเตอร์ของเมธอด | -keepparameternames |
| -keepattributes | เก็บ attributes (annotations, EnclosingMethod) | -keepattributes *Annotation* |
| -dontoptimize | ปิดการเพิ่มประสิทธิภาพ | -dontoptimize |
ProGuard ไม่สามารถวิเคราะห์โค้ดที่โหลดผ่าน reflection (Class.forName()), ServiceLoader หรือการโหลด DEX-ไฟล์แบบไดนามิกได้ในเชิงสถิติ หากคลาสถูกสร้างขึ้นโดยใช้ชื่อในรูปแบบสตริง ProGuard จะไม่รู้ถึงการมีอยู่ของมันและอาจลบทิ้งเป็นโค้ดที่ไม่ได้ใช้งาน คลาสทั้งหมดดังกล่าวต้องถูกเก็บไว้อย่างชัดเจนผ่าน -keep นี่เป็น สาเหตุ ที่พบบ่อยที่สุดของ crash ในบิลด์ release หลังจากเปิดใช้ ProGuard
ไลบรารีมักรวม กฎ ProGuard ของตัวเอง ซึ่งถูกเพิ่มโดยอัตโนมัติในบิลด์ผ่าน consumer-rules.pro ที่ฝังอยู่ในไฟล์ AAR Android Gradle Plugin จะใช้กฎเหล่านี้โดยอัตโนมัติเมื่อบิลด์ นักพัฒนาเพียงแค่ต้องตรวจสอบว่าไลบรารีทั้งหมดที่ใช้ให้กฎที่ถูกต้อง และเพิ่มเติมในโปรเจกต์หากจำเป็น
เมื่อเกิดข้อผิดพลาดหลังจากเปิดใช้ ProGuard ให้ใช้ไฟล์ mapping สำหรับ deobfuscate stack trace สำหรับการวินิจฉัย ให้ใช้คีย์ -whyareyoukeeping ซึ่งแสดงสาเหตุที่เก็บคลาสไว้ในบิลด์ผลลัพธ์ การปิด -optimizationpasses และ -obfuscation ชั่วคราวช่วยระบุตำแหน่งของปัญหา ตามข้อมูลของ Guardsquare, 80% ของปัญหากับ ProGuard แก้ไขได้โดยการเพิ่มกฎ -keep สำหรับคลาสที่ใช้ reflection
เมื่อ Android Gradle Plugin 3.4 (2019) เปิดตัว Google ได้นำเสนอ R8 — ผู้สืบทอดของ ProGuard ที่ถูกรวมเข้ากับคอมไพเลอร์ D8/R8 โดยตรง ภายในปี 2023 R8 ได้แทนที่ ProGuard อย่างสมบูรณ์ใน AGP 8.0 แต่การเข้าใจความแตกต่างทางสถาปัตยกรรมเป็นสิ่งสำคัญสำหรับการย้ายโปรเจกต์
ProGuard ทำงานเป็นเครื่องมือแยกต่างหาก โดยประมวลผล Java bytecode (ไฟล์ .class) ก่อนการแปลงเป็น DEX ส่วน R8 ถูกรวมเข้ากับคอมไพเลอร์ DEX และประมวลผลโค้ดในระดับที่ต่ำกว่า ซึ่งช่วยให้ดำเนินการ เพิ่มประสิทธิภาพ ที่ ProGuard ไม่สามารถทำได้ R8 ยังรองรับ desugaring — การแปลง syntactic sugar ของ Java 8+ เป็นโค้ดที่เข้ากันได้กับ API ระดับเก่าของ Android
ตามข้อมูลของ Google Android Performance Team (2025), R8 ให้การบีบอัดโค้ดที่ดีกว่า 10-15% เมื่อเทียบกับ ProGuard ภายใต้กฎเดียวกัน R8 เร็วกว่า — เวลาบิลด์ลดลง 20-30% นอกจากนี้ R8 ยังลบ dead code ได้มากกว่าเนื่องจากการวิเคราะห์ในระดับ DEX แทนที่จะเป็น class-ไฟล์ R8 เข้ากันได้อย่างสมบูรณ์กับไวยากรณ์กฎของ ProGuard ซึ่งทำให้การย้าย โปร่งใส สำหรับนักพัฒนา
การเปลี่ยนจาก ProGuard เป็น R8 นั้นง่าย: ใน AGP 8.0+ R8 ถูกใช้โดยค่าเริ่มต้น สำหรับโปรเจกต์เก่า ต้องลบ ProGuard ออกจาก classpath และอัปเดต gradle.properties: android.enableR8=true กฎของ ProGuard เข้ากันได้กับ R8 โดยไม่ต้องเปลี่ยนแปลงในกรณีส่วนใหญ่ ขอแนะนำให้ทดสอบบิลด์ release บน อุปกรณ์เป้าหมาย ทั้งหมดหลังจากเปลี่ยน เนื่องจาก R8 อาจลบโค้ดที่ ProGuard เคยเก็บไว้
คำถามที่พบบ่อย
สาเหตุที่พบบ่อยที่สุดคือ การลบคลาส ที่ใช้ผ่าน reflection, serialization แบบ Gson/Moshi หรือไลบรารีที่มีการโหลด DEX-ไฟล์แบบไดนามิก วิธีแก้ไข: เพิ่มกฎ -keep สำหรับคลาสทั้งหมดที่สร้างผ่าน Class.forName(), implements Parcelable, serialization ผ่าน JSON หรือมี annotation @Inject ใช้ไฟล์ mapping สำหรับ deobfuscate stack trace และระบุคลาสที่ถูกลบออกจากบิลด์
ไฟล์ mapping อยู่ใน build/outputs/mapping/release/mapping.txt หลังจากบิลด์ รูปแบบ: ชื่อ_ดั้งเดิม -> ชื่อ_ที่ถูกทำให้สับสน -> ประเภท Android Studio รองรับ deobfuscation ผ่าน Build > Analyze APK: อัปโหลด APK วาง stack trace และรับชื่อคลาสที่อ่านได้ สำหรับ CI/CD ให้เก็บไฟล์ mapping สำหรับแต่ละเวอร์ชันใน repository แยกต่างหาก หรือที่เก็บข้อมูลบนคลาวด์
ใช่ ควรเปิด ProGuard เฉพาะสำหรับบิลด์ release เท่านั้น บิลด์ debug ใช้ minifyEnabled false ซึ่งช่วยให้คอมไพล์เร็วขึ้นและเก็บชื่อคลาสที่อ่านได้สำหรับดีบักเกอร์ ในโหมด debug การทำให้โค้ดสับสนจะขัดขวางการดีบักและการดำเนินการทีละขั้นตอน ในขณะที่การบีบอัดจะทำให้ iteration ช้าลง สำหรับการทดสอบความถูกต้องของการทำให้โค้ดสับสน ให้ใช้ บิลด์ release บนอุปกรณ์จริง
คำเตือน ProGuard (WARNING) บ่งชี้ถึงปัญหาที่ไม่ทำให้บิลด์หยุด แต่สามารถบ่งชี้ถึงข้อผิดพลาดที่อาจเกิดขึ้นระหว่างการทำงานได้ หากคำเตือนไม่ทำให้เกิด crash ให้เพิ่ม -dontwarn สำหรับไลบรารีนั้น หากคำเตือนเกี่ยวข้องกับคลาสที่หายไปซึ่งไม่ได้ใช้ในแอปพลิเคชัน ก็ให้ใช้ -dontwarn เช่นกัน การไม่สนใจคำเตือนทั้งหมดโดยไม่พิจารณา ไม่แนะนำ
ProGuard — เครื่องมือฟรีที่มีฟังก์ชันพื้นฐาน: การบีบอัด การเพิ่มประสิทธิภาพ การเปลี่ยนชื่อคลาสและเมธอด DexGuard — ผลิตภัณฑ์เชิงพาณิชย์จาก Guardsquare เดียวกัน ซึ่งเพิ่มการทำให้ control flow สับสน การเข้ารหัสสตริงและทรัพยากร การป้องกันการดีบัก และการทำให้ทรัพยากรสับสน DexGuard ถูกใช้ในแอปพลิเคชัน ธนาคาร และเกมที่มีข้อกำหนดการป้องกันสูง
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม