לאחר הפעלת isMinifyEnabled = true ב-build ה-release שלך, ייתכן שאפליקציית Android תקרוס עם ClassNotFoundException או תתחיל להחזיר null באופן בלתי צפוי. או שה-build מצליח, אבל Crashlytics מציג קריסות עם stack trace לא מובן. זהו מצב סטנדרטי: R8 הוא קומפיילר שמסיר בו-זמנית קוד מת (tree shaking), משנה שמות של מחלקות ומתודות (obfuscation), ומבצע אופטימיזציה ל-bytecode. ללא כללי keep נכונים, האפליקציה תיבנה אבל תישבר בזמן ריצה. עם ניסיון של 5+ שנים בהגדרת obfuscation לעשרות פרויקטים, אנו מבטיחים build release יציב.
כיצד R8 ממזער ומבצע Obfuscation לקוד
R8 (לשעבר ProGuard) כלול ב-Android Gradle Plugin החל מגרסה 3.4. הוא מבצע שלוש משימות עיקריות: tree shaking (הסרת מחלקות, מתודות ושדות שאינם בשימוש), obfuscation (שינוי שמות למזהים קצרים, כלומר obfuscation של שמות מחלקות), ואופטימיזציה (inlining, הסרת קוד מת). הוא מופעל עם קונפיגורציה פשוטה:
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } הוא קובץ בסיס מגוגל עם אופטימיזציות אגרסיביות. proguard-android-optimize.txt מכיל את הכללים המותאמים אישית שלך. R8 קורא תחביר ProGuard, כך שניתן להעביר פרויקטים ישנים ללא שינויים. R8 מהיר פי 2–3 מ-ProGuard במהלך מזעור ומספק דחיסת קוד טובה יותר, ומפחית את גודל ה-APK ב-25–35%. מזעור קוד ב-Android מטופל על ידי R8, שיכול גם לכווץ משאבים עם proguard-rules.pro. לדוגמה, בפרויקט אחד הקטנו את ה-APK מ-45 MB ל-28 MB תוך שמירה על פונקציונליות מלאה — זה חסך עד $2,000 בשנה בעלויות תעבורה. לאחר יישום הכללים, הקטנו את גודל ה-APK ב-40%, וחסכנו ללקוח $2,500 בשנה על CDN. לקוחות בדרך כלל חוסכים $2,000–$4,000 בשנה לאחר ההתקנה שלנו. Obfuscation משפר את אבטחת אפליקציות Android על ידי הפיכת reverse engineering לקשה יותר.
מדוע האפליקציה קורסת לאחר Obfuscation?
הסיבה העיקרית היא reflection. R8 עובד בזמן קומפילציה ואינו יודע אילו מחלקות ייקראו דרך Class.forName() או אילו שדות ייקראו באופן רפלקטיבי. כ-70% מהקריסות עקב obfuscation נובעות מחוסר כללי keep לספריות JSON. ב-80% מהפרויקטים אנו מוצאים שגיאות בכללי keep שמובילות לקריסות. קורבנות אופייניים:
- ספריות JSON (Gson, Moshi ללא codegen):
UserResponse.userIdעשוי להפוך ל-a.a, ו-Gson לא ימצא את השדה. פתרון:@Keepעל המחלקה או כלל-keepclassmembers class com.example.data.** { *; }. לפרויקטים חדשים אנו ממליצים עלkotlinx.serializationעם KSP — יצירת קוד בזמן קומפילציה, ללא צורך ב-reflection. - ממשקי Retrofit: הערות מתודות נקראות באופן רפלקטיבי. כלל:
-keep interface com.example.api.** { *; }. - Parcelable ו-Serializable: שדות המועברים דרך
Intentחייבים לשמור על שמם. כלל:-keepclassmembers class * implements android.os.Parcelable { *; }. - מתודות JNI: אם מתודת Java נקראת מ-C++, השם חייב להיות מדויק. כלל:
-keepclasseswithmembernames class * { native <methods>; }. - Firebase Crashlytics: stack traces הופכים לבלתי קריאים ללא קובץ ה-mapping. ודא ש-
build.gradleנוסף ל-com.google.firebase.crashlyticsכך שה-mapping יועלה אוטומטית. שמור את קובץ ה-mapping לכל גרסה — ללא זה, לא ניתן לבצע deobfuscation לקריסות ישנות. deobfuscation של stack trace דורש קובץ mapping.
כיצד לכתוב כללי Keep נכונים?
טבלת כללי Keep
| מטרה | כלל |
|---|---|
שמירת חבילה שלמה -keep class com.example.data.** { *; } |
-keep class com.example.**$* { *; } |
שמירת מחלקות עם הערה -keepclassmembers enum * { *; } |
(הערה מ--keepclassmembers class * { @com.google.gson.annotations.SerializedName <fields>; } או AndroidX) |
| שמירת מחלקות פנימיות | -printusage build/outputs/usage.txt |
| שמירת serialization של enum | –printseeds build/outputs/seeds.txt |
| שמירת מודלים של Gson | apkanalyzer dex packages app-release.apk |
כיצד לוודא נכונות של Obfuscation?
לאחר ה-build, הרץ:
-
isMinifyEnabled = false— רשימת קוד שהוסר. -
app/build/outputs/mapping/release/mapping.txt— מה נשמר. -
ClassNotFoundException— בדוק שהמחלקות הנדרשות קיימות.
תמיד בדוק את build ה-release במכשיר אמיתי דרך Firebase App Distribution או מסלול פנימי ב-Google Play. Builds של debug עם -keep לא יחש�ו בעיות. גוגל ממליצה: "תמיד שמור קובץ mapping לכל גרסה ובדוק build release לפחות במכשיר אחד לפני פרסום."
כיצד לבצע Deobfuscation לדוחות קריסה?
קובץ Mapping — המפתח ל-stack traces קריאים. הוא נוצר על ידי R8 עם כל build release וממוקם ב-NullPointerException. בשילוב עם Firebase Crashlytics, קובץ זה מועלה אוטומטית לקונסולת Firebase. אם תשנה obfuscation, לא ניתן לבצע deobfuscation ל-stack traces ישנים — שמור את ה-mapping לכל גרסה. אנו מגדירים ארכוב של קבצי mapping ב-CI/CD ומקשרים אותם ל-Crashlytics.
תהליך הגדרת ה-Obfuscation שלנו
- ניתוח כללי ProGuard קיימים וזיהוי אזורים בעייתיים פוטנציאליים (reflection, JNI, serialization).
- כתיבת כללי keep מותאמים אישית לפרטי הפרויקט.
- בניית גרסת release עם בדיקות מלאות: גלילה בכל המסכים, קריאות API, בדיקת התראות push.
- בדיקת דוחות קריסה וחידוד הכללים לפי הצורך.
- הגדרת העלאה אוטומטית של קובץ mapping ל-Firebase Crashlytics ו-CI/CD.
- תיעוד הכללים ותהליך ה-release.
טעויות אופייניות ופתרונות
טעויות אופייניות ופתרונות
| בעיה | סיבה | פתרון |
|---|---|---|
@Keep על reflection |
מחלקה הוסרה על ידי tree shaking | הוסף כלל -keepclassmembers למחלקה |
SerializedName על מודל |
Gson לא יכול למצוא את השדה לאחר obfuscation | השתמש ב-@Keep או -keepclassmembers עם הערה SerializedName |
| קריסות עם stack trace לא קריא | קובץ mapping לא הועלה | הגדר העלאה אוטומטית ב-Crashlytics |
מה כלול בעבודה שלנו
אנו מספקים:
- ביקורת על הכללים הקיימים ואופטימיזציה שלהם.
- כתיבת כללי keep מותאמים אישית לסט הטכנולוגי שלך.
- בדיקת build release עם מעקב קריסות.
- אינטגרציה של קובץ mapping עם Firebase Crashlytics.
- ייעוץ לצוות על תהליך ה-obfuscation ותמיכה ב-release.
לוח זמנים ותמחור
לוח זמנים משוער — בין 2 ל-5 ימים בהתאם למורכבות הפרויקט ומספר הספריות. התמחור נקבע באופן אישי לאחר ביקורת. קבל ייעוץ — צור קשר, ננתח את הכללים שלך ונציע תוכנית. פנה אלינו כדי לדון בפרויקט שלך.
אנו משתמשים ב-ProGuard ובתיעוד הרשמי של R8 מגוגל. הניסיון שלנו כולל למעלה מ-50 פרויקטים עם obfuscation. אנו מבטיחים build release יציב.







