پیش از این در مطلب «آنچه بعد از دو سال برنامهنویسی اندروید آموختم-قسمت اول» به ضرورت استفاده از پروگارد در برنامههای اندروید اشاره مختصری کردیم اما آموزش استفاده از پروگارد تا این زمان به تأخیر افتاد. در این مطلب میخواهم مزایای استفاده از پروگارد را بگویم و شیوه استفاده از آن در اندروید با استفاده از اندروید استودیو را به شما آموزش دهم. امیدوارم که این مطلب برای شما مفید باشد.
پروگارد چیست؟
دیکامپایل کردن برنامههای جاوا و به تبع آن اندروید بسیار ساده است. همین الان Java Decompiler را گوگل کنید به نتایج بسیار زیادی میرسید. بعضی از این سایتها کار را ساده کردهاند و شما کافی است تا فایل apk خروجی برنامه را در سایت آپلود کنید و چند لحظه بعد نسخه دیکامپایل شده برنامه را تحویل بگیرید. البته این برنامه دیکامپایل شده را نمیتوانید مستقیماً وارد اندروید استودیو بکنید اما همان قدر که دیکامپایل کردن برنامه ساده است، وارد کردن پروژه به اندروید استودیو هم زمان زیادی را از یک کاربر و برنامهنویس حرفهای نمیگیرد.
خطر این کار فقط در لو رفتن سورس کد برنامه نیست. خطر در این است که هکر میتواند به اطلاعاتی در کد برنامه شما دست یابد که امنیت تجاری شما را به خظر بیاندازد. مثلاً برنامههایی که خرید درون برنامهای دارند، کدی را از مارکت مربوطه دریافت میکنند که هویت برنامه را نزد مارکت نشان میدهد و از آن برای رمزکردن اطلاعات رد و بدل شده استفاده میشود، حالا اگر هکر به این کد دسترسی داشته باشد، دور زدن شما و فعال کردن برنامه در حالی که آن را نخریده است فقط چند دقیقه زمان میبرد. هکر ممکن است قسمتهایی از برنامه شما که خریده شدن برنامه را چک میکند از برنامه حذف کرده و نسخهای بدلی از برنامه شما بسازد و آن را در اینترنت منتشر کند.
متاسفانه راهی برای جلوگیری از دیکامپایل شدن برنامهها وجود ندارد. سورس برنامه با قواعد خاصی کامپایل میشود و همه آنها را میتوان به صورت معکوس بر روی فایل اجرایی برنامه پیاده کرده و به سورس کد رسید. حالا سئوال اصلی این است که پس چطور جلوی این کار را بگیریم؟ پاسخ این است که نمیشود جلوی این کار را گرفت ولی میتوان آن را بسیار سخت کرد. اگر کد قبل از کامپایل شدن به گونهای تغییر کند که کل کد به هم ریخته شود، هکر بعد از دیکامپایل کردن برنامه، با حجم نسبتاً زیادی از کد روبرو میشود که بازتولید یک برنامه از روی آن بسیار سخت و زمان گیر میشود و اصطلاحاً نمیصرفد. این کاری است که پروگارد میکند. اگر کنجکاو شدید که بدانید چطور برنامههای اندروید را میتوانید دیکامپایل کنید، نگاهی به این مطلب بیاندازید. چون در حوزه کاری این سایت نیست، ترجمه نمیکنم!)
البته این تنها کار پروگارد نیست. یکی دیگر از کارهای پروگارد کوچک کردن حجم برنامه است. پروگارد در زمانی که ساختار برنامه را اسکن میکند تا در آن تغییرات بدهد، کلاسهایی که از آنها استفاده نشده است را از برنامه حذف میکند و با بعضی از تکنیکها حجم کد برنامه را بسیار کاهش میدهد. دقت کنید نگفتم حجم برنامه، چون عمده حجم برنامههای اندروید در منابع برنامه مانند عکسها و تصاویر است که پروگارد با آنها هیچ کاری ندارد. اما با این حال چند مگابایت از حجم برنامه را پروگارد کاهش میدهد که خودش عدد بزرگی است.
اگر بخواهیم کارهایی که پروگارد روی برنامه انجام میدهد را دستهبندی کنیم، این چهار تا کارهای اصلی پروگارد هستند:
- کوچک کردن برنامه یا minification
- به هم ریختن برنامه یا obfuscation
- بستهبندی مجدد برنامه یا repackaging
- بهینهسازی یا optimisation
حالا که به ضرورت استفاده از پروگارد پی بردید، کمی هم از معایب آن بگوییم!
استفاده از پروگارد دیباگ کردن برنامه را بسیار مشکل میسازد. زمانی که برنامه را دیباگ میکنیم کامپایلر اطلاعات بسیار زیادی را در کد کامپایل شده قرار میدهد که دیباگر از آنها برای نشان دادن محل دقیق خطا (اسم فایل، شماره خط و کد برنامه). پروگارد همه آنها را پاک میکند، نام کلاسها و متغیرها را عوض میکند، بسته یا پکیج کلاسها را تغییر میدهد و خلاصه کاری میکند که تقریباً میتوان گفت دیباگ برنامه از کار میافتد! ایراد دیگر استفاده از پروگارد این است که اجرای آن زمان نسبتاً زیادی (البته در مقیاس زمانهای بیلد پروژه) به خود اختصاص میدهد و اجرای آن در هر بار بیلد کردن برنامه باعث هدر رفتن وقت زیاد توسعهدهنده میشود. ایراد دیگرش این است که Instant Run یا اجرای سریع که از ویژگیهای جدید اندروید استودیو است را از کار میاندازد. با کمک «اجرای سریع» تغییرات کوچک برنامهها بدون نیاز به کامپایل و نصب مجدد برنامه، بلافاصله در شبیهساز منعکس میشود.
برای این که هم از مزایای پروگارد استفاده کنیم و هم از تا حد امکان از معایب آن به دور باشیم، معمولاً در زمان دیباگ برنامه پروگارد را غیر فعال میکنیم و فقط زمانی که میخواهیم از برنامه خروجی قابل انتشار بگیریم آن را فعال میکنیم.
نکته: مواردی پیش میآید که برنامه شما در زمان دیباگ به خوبی کار میکند اما نسخه قابل انتشار آن به علت تغییراتی که پروگارد در آن داده است، کار نمیکند یا برخی از امکانات آن با خطا روبرو میشوند. بنابراین حتماً:
۱- تنظیمات پروگارد را به دقت انجام بدهید و
۲- برنامه را حتماً قبل از انتشار نهایی کاملاً تست کنید.
نصب پروگارد
پروگارد همراه اندروید SDK عرضه میشود و بنابراین برای نصب آن نیاز نیست کار خاصی بکنید.
تنظیم پروگارد
اگر به فایل build.gradle ماژول app در برنامه todo-mvp نگاهی بیاندازید میبینید که بخشی از این تنظیمات اختصاص به بیلد تایپ (build type) دارد:
buildTypes { debug { minifyEnabled true // Uses new built-in shrinker http://tools.android.com/tech-docs/new-build-system/built-in-shrinker useProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguardTest-rules.pro' } release { minifyEnabled true useProguard true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguardTest-rules.pro' } }
در این پروژه ما دو بیلد تایپ اصلی داریم: debug و release.
از بیلد تایپ debug در زمان دیباگ برنامه استفاده میشود. همانطور که میبینید در تنظیمات این بیلد تایپ minifyEnabled با مقدار true تعریف شده است. یعنی میخواهیم در زمان دیباگ برنامه از یک کوچک کننده حجم کد استفاده کنیم اما همانطور که در خط بعد میبینید مقدار متغیر useProguard برابر با false است. این یعنی این که از پروگارد در زمان دیباگ استفاده نخواهیم کرد. یکی از امکانات جدید اندروید SDK یک کوچک کننده سادهتر است که همراه با SDK عرضه شده است که امکانات آن به پروگارد نمیرسد اما ایرادات پروگارد را هم ندارد.
اما در بیلد تایپ release هم minifyEnabled مقداری برابر true دارد و هم useProguard. این یعنی این که در زمانی که میخواهیم یک نسخه apk قابل انتشار از برنامه تهیه کنیم، اندروید SDK باید از پروگارد استفاده کند.
دو متغیر دیگری که در این بیلد تایپها تعریف شده است proguardFiles و testProguardFiles است. این دو متغیر همانطور که از نامشان پیدا است آدرس فایل تنظیمات خود پروگارد را به گریدل میدهد. از تنطیمات proguardFiles در زمان کامپایل برنامه و از testProguardFiles در زمان تست برنامه استفاده میشود.
فایل proguard-android.txt شامل تنظیمات پیش فرض پروگارد برای همه پروژههای اندروید است و در اندروید SDK قرار دارد. ما نباید این فایل را تغییر بدهیم. اگر بخواهیم که تنظیمات خاص پروژه خودمان را در پروگارد اعمال کنیم آنها را در فایل proguard-rules.pro وارد میکنیم که در خود پروزه ما قرار دارد.
ترجیحات (Option) پروگارد
اگر فایل proguard-rules.pro را با یک ویرایشگر متن باز کنید متن زیر را به عنوان تنظیمات پروگارد میبینید و هر چیزی که بخواهید را به این فایل باید اضافه کنید:
# Some methods are only called from tests, so make sure the shrinker keeps them. -keep class com.example.android.architecture.blueprints.** { *; } -keep class android.support.v4.widget.DrawerLayout { *; } -keep class android.support.test.espresso.IdlingResource { *; } -keep class com.google.common.base.Preconditions { *; } # For Guava: -dontwarn javax.annotation.** -dontwarn javax.inject.** -dontwarn sun.misc.Unsafe # Proguard rules that are applied to your test apk/code. -ignorewarnings -keepattributes *Annotation* -dontnote junit.framework.** -dontnote junit.runner.** -dontwarn android.test.** -dontwarn android.support.test.** -dontwarn org.junit.** -dontwarn org.hamcrest.** -dontwarn com.squareup.javawriter.JavaWriter # Uncomment this if you use Mockito -dontwarn org.mockito.**
هر خط در این فایل که با # شروع میشود توضیح است. سایر خطوط هر خط نشان دهنده یک ترجیح (Option) به پروگارد است. ترجیحاتی که در این تنظیمات میبینید اینها است:
-keep: به پروگارد میگوییم که این کلاسها را نگه دارد و نام آنها و بسته آنها را تغییر ندهد. اگر بخواهیم همه کلاسهای داخل یک پکیج را استثنا کنیم از * و اگر بخواهیم همه کلاسهای داخل این پکیج و همه کلاسهای داخل پکیجهای داخلی آن را استثنا کنیم از ** استفاده میکنیم.
-dontwarn: اگر ارجاعاتی به/در کلاس یا کلاسهای مشخص شده وجود دارد که پروگارد آنها را به هر دلیل پیدا نمیکند، هشدار ندهد و آنها را نادیده بگیرد.
-ignorewarnings: عملکرد آن شبیه dontwarn است با یک تفاوت: در لاگ خروجی این ارجاع نامشخص را مینویسد اما به کار خود ادامه میدهد.
-keepattributes: ویژگیهایی که اینجا اعلام کردهایم را نگه میدارد و آنها را حذف نمیکند.
-dontnote: پروگارد بعد از اجرا فایلی را در اختیار ما میگذارد که در آن تمام تغییراتی را که در پکیجها، کلاسها و ویژگیها آنها داده است، در آن میآورد. اگر بخواهیم که خطاهای بالقوه در یک یا چند کلاس خاص را در آن فایل ننویسد از این تنظیم استفاده میکنیم.
تعداد این ترجیحات در دسترس در پروگارد بیشتر از ۵۰ تا است. اگر خواستید با آنها آشنا شوید در مستندات سایت پروگارد لیست همه آنها به همراه توضیحات آمده است.
تنظیمات پروگارد برای کتابخانههای پروژه
هر پروژهای تنظیمات خاص خودش را دارد و شما به عنوان توسعه دهنده تصمیم میگیرید که چطور از پروگارد استفاده کنید. اما زمانی که از کتابخانهها یا برنامههایی که دیگران نوشتهاند میخواهید استفاده کنید، حتماً تنظیمات پروگارد مورد نیاز آن کتابخانه را در پروژه خود اعمال کنید. فرض کنید در پروژه از Retrofit استفاده کردهاید. آیا میدانید که این کتابخانه به چه تنظیماتی نیاز دارد؟ بهتر است به جای حدس زدن در این مورد به مستندات آن کتابخانه نگاهی بیاندازید. معمولاً همه کتابخانهها اگر برای عملکرد درست نیاز به تنظیمات خاصی در پروگارد داشته باشند این موضوع را صراحتاً اعلام میکنند. برای مثال اگر از Retrofit در پروژه استفاده میکنید باید تنظیمات زیر را به پروگارد اضافه کنید:
# Platform calls Class.forName on types which do not exist on Android to determine platform. -dontnote retrofit2.Platform # Platform used when running on Java 8 VMs. Will not be used at runtime. -dontwarn retrofit2.Platform$Java8 # Retain generic type information for use by reflection by converters and adapters. -keepattributes Signature # Retain declared checked exceptions for use by a Proxy instance. -keepattributes Exceptions
رتروفیت در صفحه اصلی مستندات خودش به این تنظیمات اشاره کرده است و آنها را آماده کرده است و شما باید آنها را به انتهای فایل progaurd-rules.pro اضافه کنید و این کار را برای همه کتابخانههای پروژه تکرار کنید. در غیر این صورت معلوم نیست برنامه شما پس از اجرای پروگارد چه رفتاری خواهد داشت.
سلام آقای بهزادیان
با تشکر ا زمقالات خوبتون
طبق توضیحات شما با minifyEnabled true عملیات obfuscation نباید انجام بشه ،اما در عمل بدین صورت نیست .کد پروژه من هنگام ساخت نسخه ریلیز کاملا درهم سازی انجام می شود.تنظیمات هم به صورت زیر است
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’
}
سایت های دیگر هم برای فعالسازی پروگارد فقط از این option استفاده کردند.لطف می کنید توضیحات بیشتری در مورد تفاوت minifyEnabled وuseProguard بدید.
ممنون
پیش از این minifyEnabled true به تنهایی به معنی استفاده از پروگارد بود. اما در نسخههای اخیر SDK یک کوچک کننده (Shrinker) جدید به SDK اضافه شده است. بنابراین هر وقت که minifyEnabled true باشد، باید مشخص کنیم که از پروگارد استفاده کند یا این کوچک کننده جدید. برای همین موضوع یک ویژگی جدید اضافه شده است به useProgaurd.
بنابراین:
minifyEnable true
useProgaurd true
یعنی استفاده از پروگارد
و
minifyEnable true
useProgaurd false
یعنی استفاده از کوچک کننده پیش فرض
minifyEnable false
یعنی استفاده نکردن از کوچک کننده
ممنون از پاسخ شما
با سلام و خسته نباشید خدمت آقای بهزادیان
سپاس از سایت خوبتون و آموزش های کاربردی و مفید
من یه اپلیکیشن موبایل ساختم ک تموم شده و حالا قصد استفاده از پروگارد دارم. و در این اپلیکیشن بیشتر از ۲۰ تا کتابخونه استفاده کردم که برای پروگارد به مشکل میخورم. ممنون میشم منو راهنمایی کنید ک چه طور میتونم از پروگارد برای یه اپ بزرگ استفاده کنم و روند کارم به چه صورت باشه بهتره؟