ناوین

R8 vs ProGuard در اندروید؛ تفاوت چیست و کدام را انتخاب کنیم؟

6 دقیقه مطالعه
اپلیکیشن موبایلاپلیکیشن
R8 vs ProGuard در اندروید؛ تفاوت چیست و کدام را انتخاب کنیم؟

در سال‌های اخیر، R8 به ابزار پیش‌فرض Android برای Code Shrinking و Obfuscation در Release Buildها تبدیل شده است

اگر در توسعه اپلیکیشن‌های Android فعالیت می‌کنید، احتمالاً با نام‌های R8 و ProGuard مواجه شده‌اید. هر دو ابزار در زمینه کوچک‌سازی، بهینه‌سازی و Obfuscation کدهای Android استفاده می‌شوند، اما تفاوت‌هایی در نحوه عملکرد و جایگاه آن‌ها در فرآیند Build وجود دارد.

در سال‌های اخیر، R8 به ابزار پیش‌فرض Android برای Code Shrinking و Obfuscation در Release Buildها تبدیل شده است و در بسیاری از پروژه‌های جدید دیگر نیازی به استفاده مستقیم از ProGuard وجود ندارد.

در این مقاله از ناوین، R8 و ProGuard را بررسی می‌کنیم و می‌بینیم چه تفاوتی با یکدیگر دارند، چه زمانی باید از آن‌ها استفاده کنیم و چگونه تنظیمات آن‌ها را در یک پروژه Android مدیریت کنیم.

R8 چیست؟

R8 ابزاری است که در فرآیند Build اپلیکیشن Android برای کاهش حجم برنامه، حذف کدهای غیرضروری، بهینه‌سازی و Obfuscation استفاده می‌شود.

به‌صورت ساده:

Source Code

Compile

R8

Shrink
Optimize
Obfuscate

APK / AAB

R8 می‌تواند بخش‌هایی از کد را که در اپلیکیشن استفاده نمی‌شوند شناسایی و حذف کند.

همچنین نام کلاس‌ها و متدها را می‌تواند تغییر دهد تا Reverse Engineering دشوارتر شود.

ProGuard چیست؟

ProGuard یکی از ابزارهای قدیمی و شناخته‌شده در اکوسیستم Java و Android برای:

  • Shrinking
  • Optimization
  • Obfuscation
  • حذف کدهای غیرضروری

است.

ProGuard قبل از ظهور R8 برای بسیاری از پروژه‌های Android مورد استفاده قرار می‌گرفت.

برای مثال ممکن است در پروژه‌های قدیمی فایل‌هایی مانند:

proguard-rules.pro

را مشاهده کنید.

نکته مهم این است که وجود نام proguard-rules.pro به این معنی نیست که حتماً ProGuard در حال اجرا است؛ پروژه‌های Android امروزی ممکن است همین فایل را برای Ruleهای R8 نیز استفاده کنند.

تفاوت اصلی R8 و ProGuard

تفاوت اصلی این است که R8 ابزار مدرن‌تری است که برای Build اپلیکیشن‌های Android طراحی شده و می‌تواند عملیات Shrinking و Optimization را به شکل یکپارچه‌تر در فرآیند Build انجام دهد.

مقایسه کلی:

ویژگیR8ProGuard

Shrinking

Obfuscation

Optimization

مناسب برای پروژه‌های جدید Android

معمولاً خیر

یکپارچه با Android Build

قدیمی‌تر

Performance در Build

معمولاً بهتر

معمولاً کندتر

ابزار پیش‌فرض مدرن Android

چرا R8 جایگزین ProGuard شد؟

یکی از دلایل اصلی توسعه R8 این بود که فرآیند کوچک‌سازی و بهینه‌سازی کد برای Android به شکل بهتری با Build System و ساختار اپلیکیشن‌های مدرن هماهنگ شود.

R8 در فرآیند Build می‌تواند مراحل مختلف را با یکدیگر ترکیب کند.

در یک نگاه:

ProGuard:

Bytecode

ProGuard

Processed Bytecode

در مقابل:

R8:

Bytecode

R8

Shrink
Optimize
Obfuscate

DEX

این یک تصویر ساده‌شده از فرآیند است، اما برای درک تفاوت کلی مناسب است.

R8 چه کارهایی انجام می‌دهد؟

R8 را می‌توان مجموعه‌ای از قابلیت‌های مهم برای Release Build در نظر گرفت.

1. Code Shrinking

کدهایی که در برنامه مورد استفاده قرار نمی‌گیرند می‌توانند حذف شوند.

فرض کنید یک کلاس دارید:

class OldFeature {
fun unusedFunction() {
// ...
}
}

اگر این کد هیچ مسیری در برنامه نداشته باشد که به آن نیاز داشته باشد، R8 می‌تواند آن را حذف کند.

نتیجه:

Unused Code

Removed

Smaller App

2. Obfuscation

R8 می‌تواند نام کلاس‌ها، متدها و فیلدهای مختلف را تغییر دهد.

مثلاً کد:

class PaymentManager {

fun processPayment() {
// ...
}
}

ممکن است در خروجی Obfuscated به چیزی شبیه:

a.b()

تبدیل شود.

هدف این کار، سخت‌تر کردن تحلیل و Reverse Engineering کد است.

البته Obfuscation به معنی غیرقابل نفوذ شدن اپلیکیشن نیست.

3. Optimization

R8 می‌تواند برخی قسمت‌های Bytecode را بهینه کند.

هدف این است که کد خروجی تا حد امکان بهینه‌تر باشد.

به‌عنوان مثال، برخی کدهای غیرضروری می‌توانند حذف یا بعضی عملیات قابل بهینه‌سازی شوند.

R8 و کاهش حجم APK

یکی از مهم‌ترین مزایای فعال کردن Code Shrinking، کاهش حجم خروجی برنامه است.

فرض کنید بدون Shrinking:

App Size = 50 MB

باشد.

پس از حذف کدها و Resourceهای غیرضروری ممکن است حجم خروجی کاهش پیدا کند.

البته مقدار کاهش حجم کاملاً به پروژه بستگی دارد و نمی‌توان یک درصد ثابت برای همه اپلیکیشن‌ها تعیین کرد.

R8 و امنیت اپلیکیشن

یکی از دلایلی که توسعه‌دهندگان R8 را فعال می‌کنند، سخت‌تر کردن Reverse Engineering است.

بدون Obfuscation ممکن است ساختار کلاس‌ها و نام متدها واضح‌تر باشند.

با Obfuscation:

PaymentService
UserRepository
AuthenticationManager

می‌توانند به نام‌هایی کوتاه و غیرمعنادار تبدیل شوند.

اما باید توجه داشت:

R8 یک ابزار امنیتی کامل نیست.

اگر اپلیکیشن اطلاعات حساس، API Key یا Secret داشته باشد، نباید صرفاً به Obfuscation اعتماد کرد.

R8 چگونه در پروژه Android فعال می‌شود؟

در پروژه‌های Android معمولاً Code Shrinking را برای Release Build فعال می‌کنیم.

در فایل Gradle مربوط به App می‌توان تنظیماتی شبیه زیر داشت:

android {
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
}
}
}

در برخی پروژه‌ها نام‌گذاری یا ساختار فایل Gradle ممکن است با توجه به نسخه Android Gradle Plugin متفاوت باشد.

isMinifyEnabled برای فعال کردن فرآیند کوچک‌سازی و بهینه‌سازی کد استفاده می‌شود.

isShrinkResources نیز برای حذف Resourceهای غیرضروری کاربرد دارد.


proguard-rules.pro چیست؟

ممکن است در پروژه فایل زیر را ببینید:

proguard-rules.pro

این فایل برای تعریف Ruleهایی استفاده می‌شود که به ابزار Shrinker می‌گویند چه چیزهایی باید حفظ شوند یا چگونه پردازش شوند.

در پروژه‌های مدرن، این Ruleها معمولاً توسط R8 پردازش می‌شوند.

مثلاً:

-keep class com.example.models.** { *; }

یعنی کلاس‌های مشخص‌شده را از حذف یا Obfuscation حفظ کنید.

چرا به Keep Rule نیاز داریم؟

R8 باید بتواند تشخیص دهد کدام کد واقعاً استفاده می‌شود.

اما همیشه تمام Dependencyها و Frameworkها به شکل مستقیم از یک کلاس استفاده نمی‌کنند.

مثلاً ممکن است یک Framework با استفاده از:

  • Reflection
  • Serialization
  • Dependency Injection
  • JNI
  • Dynamic Loading

به کلاس خاصی دسترسی داشته باشد.

در این شرایط ممکن است R8 تصور کند کلاس استفاده نمی‌شود.

در نتیجه:

Runtime Dependency

R8 doesn't detect it

Class removed/renamed

Runtime Error

برای جلوگیری از این مشکل ممکن است به Keep Rule نیاز داشته باشیم.

یک مثال ساده از Keep Rule

فرض کنید کلاس‌هایی دارید که توسط Reflection استفاده می‌شوند:

data class User(
val id: Int,
val name: String
)

ممکن است بسته به کتابخانه و نحوه استفاده، لازم باشد برخی کلاس‌ها یا اعضا را از Shrinking یا Obfuscation مستثنی کنید.

برای نمونه:

-keep class com.example.model.** { *; }

اما نباید بدون دلیل از Ruleهای بسیار گسترده استفاده کنید.

آیا باید همه چیز را Keep کنیم؟

خیر.

یکی از اشتباهات رایج این است که توسعه‌دهنده برای برطرف کردن یک Crash، Rule بسیار گسترده‌ای اضافه کند:

-keep class ** { *; }

این کار می‌تواند بخش بزرگی از مزایای R8 را از بین ببرد.

بهتر است Ruleها تا حد امکان دقیق باشند:

Bad:
Keep Everything

Better:
Keep Required Classes

R8 و Third-Party Libraries

یکی از چالش‌های رایج، استفاده از Libraryهای مختلف است.

مثلاً اپلیکیشن ممکن است از:

Retrofit
Gson
Room
Firebase
Hilt

یا کتابخانه‌های دیگر استفاده کند.

بعضی Libraryها Ruleهای موردنیاز خود را همراه با Library ارائه می‌کنند.

به همین دلیل قبل از اضافه کردن Keep Rule دستی، ابتدا Documentation و Configuration خود Library را بررسی کنید.

R8 و Reflection

Reflection یکی از مواردی است که می‌تواند کار Shrinker را پیچیده کند.

فرض کنید کدی دارید که کلاس را با نام آن پیدا می‌کند:

Class.forName("com.example.User")

R8 ممکن است نتواند به‌سادگی تشخیص دهد که کلاس User از طریق Reflection استفاده می‌شود.

در چنین شرایطی ممکن است به Rule مناسب نیاز داشته باشید.

R8 و Serialization

Serialization نیز می‌تواند نیازمند توجه ویژه باشد.

برای مثال اگر از JSON Mapping استفاده می‌کنید، باید مطمئن شوید که کلاس‌ها و اطلاعات موردنیاز در Release Build همچنان قابل دسترسی هستند.

این موضوع به Library مورد استفاده بستگی دارد.

بنابراین همیشه قبل از اضافه کردن Ruleهای عمومی، Configuration رسمی کتابخانه را بررسی کنید.

R8 و Debug Build

در بیشتر پروژه‌ها Shrinking و Obfuscation را برای Debug Build فعال نمی‌کنند.

چرا؟

چون Debugging کد Obfuscated بسیار دشوارتر است.

معمولاً:

Debug

Readable Code

Easy Debugging

و:

Release

R8

Shrinking + Obfuscation

استفاده می‌شود.

R8 و Release Build

Release Build جایی است که R8 اهمیت بیشتری پیدا می‌کند.

یک فرآیند معمول:

Developer Code

Gradle Build

R8

Shrink

Optimize

Obfuscate

AAB

در نهایت فایل Release برای انتشار آماده می‌شود.

Mapping File چیست؟

هنگامی که Obfuscation فعال باشد، نام‌های اصلی کلاس‌ها و متدها تغییر می‌کنند.

برای مثال:

PaymentManager

a.b

اگر Crash در Production رخ دهد، بدون اطلاعات Mapping تحلیل Stack Trace بسیار دشوارتر خواهد بود.

R8 یک Mapping File تولید می‌کند که ارتباط بین نام‌های اصلی و نام‌های Obfuscated را مشخص می‌کند.

به‌صورت مفهومی:

Original Obfuscated

PaymentManager → a
processPayment → b
UserRepository → c

چرا باید Mapping File را نگه داریم؟

فرض کنید کاربر نسخه Release را نصب کرده و Crash رخ داده است.

Stack Trace ممکن است شامل نام‌هایی مانند:

a.b()
c.d()

باشد.

با Mapping File می‌توان این اطلاعات را به نام‌های اصلی تبدیل کرد.

بنابراین برای Releaseهای واقعی باید Mapping Fileها را با دقت نگهداری و مدیریت کنید.

R8 و Resource Shrinking

R8 عمدتاً روی کد تمرکز دارد، اما Android Build System می‌تواند Resourceهای استفاده‌نشده را نیز حذف کند.

با فعال کردن:

isShrinkResources = true

ممکن است Resourceهایی مانند:

Unused Images
Unused XML
Unused Resources

حذف شوند.

این قابلیت می‌تواند در کاهش حجم نهایی App مفید باشد.

R8 و App Bundle

اگر اپلیکیشن را برای Google Play منتشر می‌کنید، معمولاً خروجی Android App Bundle یا AAB اهمیت زیادی دارد.

ساختار کلی:

Source

Gradle

R8

AAB

Google Play

Optimized APK

Google Play می‌تواند بر اساس دستگاه کاربر، APK مناسب را از App Bundle تولید و ارائه کند.

آیا R8 بهتر از ProGuard است؟

برای پروژه‌های مدرن Android، R8 معمولاً انتخاب مناسب‌تری است.

دلیل آن:

  • یکپارچگی بهتر با Android Build
  • مناسب بودن برای Android مدرن
  • Shrinking
  • Optimization
  • Obfuscation
  • Workflow مدرن‌تر

بنابراین اگر پروژه جدیدی ایجاد می‌کنید، معمولاً دلیلی برای انتخاب ProGuard به‌عنوان ابزار اصلی به جای R8 ندارید.

آیا هنوز باید ProGuard را یاد بگیریم؟

تا حدی بله.

اگر با پروژه‌های قدیمی Android کار می‌کنید، احتمالاً با اصطلاحات و Ruleهای ProGuard مواجه خواهید شد.

همچنین Syntax بسیاری از Configuration Ruleها همچنان با نام ProGuard شناخته می‌شود و فایل‌هایی مانند:

proguard-rules.pro

در پروژه‌های R8 نیز استفاده می‌شوند.

بنابراین بهتر است تفاوت بین:

ProGuard Tool

و:

ProGuard Configuration Rules

را درک کنید.

مقایسه R8 و ProGuard از دید یک Android Developer

اگر بخواهیم خیلی ساده نگاه کنیم:

ProGuard

Legacy / Older Tool

R8

Modern Android Shrinker

در پروژه‌های جدید:

Android App

R8

Release Build

معمولاً مسیر اصلی است.

اشتباهات رایج در استفاده از R8

۱. اضافه کردن Keep Rule برای همه کلاس‌ها

این کار می‌تواند Shrinking و Obfuscation را تا حد زیادی بی‌اثر کند.

۲. تست نکردن Release Build

ممکن است Debug Build کاملاً سالم باشد اما Release Build بعد از R8 Crash کند.

بنابراین Release Variant را حتماً تست کنید.

۳. حذف Mapping File

اگر Obfuscation فعال است، Mapping File برای تحلیل Crashهای Production اهمیت زیادی دارد.

۴. قرار دادن Secret در اپلیکیشن

R8 نباید به‌عنوان راهی برای مخفی کردن API Secret یا Password استفاده شود.

۵. نادیده گرفتن Reflection

کتابخانه‌هایی که از Reflection یا روش‌های Dynamic استفاده می‌کنند ممکن است به Configuration خاص نیاز داشته باشند.

۶. استفاده از Ruleهای قدیمی بدون بررسی

گاهی پروژه‌های قدیمی تعداد زیادی Rule دارند که دیگر ضروری نیستند.

بهتر است Configurationها را دوره‌ای بررسی کنید.

بهترین روش استفاده از R8

برای استفاده صحیح از R8 می‌توانید این رویکرد را دنبال کنید:

۱. ابتدا R8 را برای Release فعال کنید

isMinifyEnabled = true

۲. اپلیکیشن را کامل تست کنید

به‌خصوص:

  • Login
  • API
  • Database
  • Serialization
  • Push Notification
  • Deep Link
  • Payment
  • Reflection

۳. اگر Crash ایجاد شد، علت را پیدا کنید

فوراً Rule عمومی اضافه نکنید.

۴. Rule دقیق اضافه کنید

فقط کلاس‌ها یا اعضایی را که واقعاً نیاز هستند Keep کنید.

۵. Mapping File را نگه دارید

برای Debugging نسخه Production ضروری است.

R8 برای چه پروژه‌هایی مناسب است؟

تقریباً هر Android Application که قرار است به‌صورت Release منتشر شود می‌تواند از مزایای R8 استفاده کند.

به‌خصوص برای:

  • اپلیکیشن‌های تجاری
  • اپلیکیشن‌های بزرگ
  • اپلیکیشن‌های دارای Dependencyهای متعدد
  • اپلیکیشن‌های منتشرشده در Store
  • پروژه‌هایی که حجم APK/AAB اهمیت دارد

R8 در یک نگاه

می‌توان عملکرد R8 را این‌گونه خلاصه کرد:

R8

┌─────────┼─────────┐
↓ ↓ ↓
Shrink Optimize Obfuscate
│ │ │
└─────────┼─────────┘

Release Build

یعنی R8 می‌تواند:

کدهای غیرضروری را حذف کند + کد را بهینه کند + نام‌ها را Obfuscate کند.

نتیجه‌گیری

R8 و ProGuard هر دو در زمینه کوچک‌سازی و Obfuscation کد Android شناخته شده‌اند، اما در پروژه‌های مدرن Android، R8 ابزار اصلی و مدرن برای این فرآیند است.

R8 می‌تواند در Release Build برای کاهش حجم برنامه، حذف کدهای غیرضروری، بهینه‌سازی و Obfuscation مورد استفاده قرار گیرد.

در عین حال، استفاده از R8 نیازمند دقت است. اگر اپلیکیشن از Reflection، Serialization، Dependency Injection یا برخی روش‌های Dynamic استفاده کند، ممکن است لازم باشد Ruleهای مخصوصی تعریف شود.

بهترین رویکرد این است که R8 را برای Release فعال کنید، نسخه Release را به‌طور کامل تست کنید، Keep Ruleها را تا حد امکان محدود نگه دارید و Mapping File هر Release را به‌صورت امن ذخیره کنید.

در نهایت باید به خاطر داشته باشیم که R8 یک ابزار امنیتی کامل نیست؛ بلکه یکی از لایه‌های محافظتی و بهینه‌سازی اپلیکیشن است. اطلاعات حساس، Secretها و منطق‌های امنیتی مهم نباید صرفاً با Obfuscation محافظت شوند.

سوالات متداول

R8 چیست؟

R8 ابزار مدرن Android برای Code Shrinking، Optimization و Obfuscation است که در فرآیند Build اپلیکیشن استفاده می‌شود.

آیا R8 همان ProGuard است؟

خیر. R8 ابزار متفاوتی است، اما از بسیاری از Syntaxها و Ruleهای سازگار با ProGuard استفاده می‌کند. به همین دلیل فایل‌هایی مانند proguard-rules.pro در پروژه‌های R8 نیز رایج هستند.

آیا باید R8 را در Debug فعال کنیم؟

معمولاً خیر. فعال بودن Obfuscation در Debug می‌تواند فرآیند Debugging را دشوار کند. معمولاً R8 برای Release Build استفاده می‌شود.

آیا R8 امنیت اپلیکیشن را تضمین می‌کند؟

خیر. R8 می‌تواند Reverse Engineering را دشوارتر کند، اما نمی‌تواند به‌تنهایی امنیت کامل اپلیکیشن را تضمین کند.

چرا بعد از فعال کردن R8 اپلیکیشن Crash می‌کند؟

یکی از دلایل رایج، حذف یا تغییر نام کلاسی است که در Runtime از طریق Reflection، Serialization یا روش‌های Dynamic مورد استفاده قرار می‌گیرد. در چنین شرایطی ممکن است به Keep Rule مناسب نیاز داشته باشید.

فایل Mapping در R8 چه کاربردی دارد؟

Mapping File ارتباط بین نام‌های اصلی و نام‌های Obfuscated را نگه می‌دارد و برای خواندن و تحلیل Stack Traceهای Obfuscated و Crashهای Release بسیار مهم است.

آیا ProGuard هنوز در Android استفاده می‌شود؟

ProGuard همچنان به‌عنوان یک ابزار قدیمی شناخته می‌شود و Configuration Syntax آن در اکوسیستم Android اهمیت دارد، اما برای پروژه‌های مدرن معمولاً R8 انتخاب اصلی است.

آیا R8 حجم اپلیکیشن را کاهش می‌دهد؟

بله، R8 می‌تواند کدهای استفاده‌نشده را حذف کند و همراه با Resource Shrinking می‌تواند به کاهش حجم خروجی Release کمک کند؛ مقدار کاهش به ساختار و Dependencyهای هر پروژه بستگی دارد.


نظرات و بازخورد

هنوز نظری تأیید نشده است. اولین نفر باشید.

ثبت نظر جدید

نظر شما بعد از بررسی و تأیید ادمین منتشر می‌شود.

ادامه مطالعه

مقالات مشابه

همه مقالات

خدمات ناوین

از ایده تا محصول دیجیتال

کنار مطالعه مقالات، مسیر ساخت محصول را هم با تیم ناوین ببینید.

همه خدمات