برنامه خود را کوچک، مبهم و بهینه کنید

برای اینکه برنامه خود را تا حد امکان کوچک و سریع کنید، باید نسخه انتشار خود را با isMinifyEnabled = true بهینه سازی و کوچک کنید.

انجام این کار کوچک کردن را فعال می کند که کد و منابع استفاده نشده را حذف می کند. مبهم سازی ، که نام کلاس ها و اعضای برنامه شما را کوتاه می کند. و بهینه سازی ، که استراتژی های تهاجمی تری را برای کاهش بیشتر اندازه و بهبود عملکرد برنامه شما اعمال می کند. این صفحه توضیح می دهد که R8 چگونه این وظایف زمان کامپایل را برای پروژه شما انجام می دهد و چگونه می توانید آنها را سفارشی کنید.

وقتی پروژه خود را با استفاده از افزونه Android Gradle نسخه 3.4.0 یا بالاتر می‌سازید، افزونه دیگر از ProGuard برای بهینه‌سازی کد در زمان کامپایل استفاده نمی‌کند. در عوض، این افزونه با کامپایلر R8 کار می کند تا وظایف زمان کامپایل زیر را انجام دهد:

  • کوچک کردن کد (یا تکان دادن درخت): کلاس‌ها، فیلدها، روش‌ها و ویژگی‌های استفاده نشده را از برنامه شما و وابستگی‌های کتابخانه‌اش شناسایی و با خیال راحت حذف می‌کند (که آن را به ابزاری ارزشمند برای کار در حدود 64 هزار مرجع تبدیل می‌کند). برای مثال، اگر فقط از چند API وابسته به کتابخانه استفاده می‌کنید، کوچک کردن می‌تواند کد کتابخانه‌ای را که برنامه شما از آن استفاده نمی‌کند شناسایی کند و فقط آن کد را از برنامه شما حذف کند. برای کسب اطلاعات بیشتر، به بخش نحوه کوچک کردن کد خود بروید.
  • کاهش منابع: منابع استفاده نشده را از برنامه بسته بندی شده شما حذف می کند، از جمله منابع استفاده نشده در وابستگی های کتابخانه برنامه شما. این در ارتباط با کوچک کردن کد کار می کند به طوری که پس از حذف کدهای استفاده نشده، هر منبعی که دیگر به آن ارجاع داده نمی شود، می تواند با خیال راحت حذف شود. برای کسب اطلاعات بیشتر، به بخش نحوه کاهش منابع خود بروید.
  • بهینه سازی: کد شما را بازرسی و بازنویسی می کند تا عملکرد زمان اجرا را بهبود بخشد و حجم فایل های DEX برنامه شما را کاهش دهد. این عملکرد زمان اجرا کد را تا 30 درصد بهبود می بخشد و به شدت راه اندازی و زمان بندی فریم را بهبود می بخشد. برای مثال، اگر R8 تشخیص دهد که شاخه else {} برای یک عبارت if/else داده شده هرگز گرفته نشده است، R8 کد شاخه else {} را حذف می کند. برای کسب اطلاعات بیشتر، به بخش بهینه سازی کد بروید.
  • مبهم سازی (یا کوچک سازی شناسه): نام کلاس ها و اعضا را کوتاه می کند که منجر به کاهش اندازه فایل DEX می شود. برای کسب اطلاعات بیشتر، به بخش نحوه مبهم کردن کد خود بروید.

هنگام ساخت نسخه انتشار برنامه خود، R8 می تواند پیکربندی شود تا وظایف زمان کامپایل که در بالا توضیح داده شد را برای شما انجام دهد. همچنین می‌توانید وظایف خاصی را غیرفعال کنید یا رفتار R8 را از طریق فایل‌های قوانین ProGuard سفارشی کنید. در واقع، R8 با تمام فایل‌های قوانین ProGuard موجود شما کار می‌کند ، بنابراین به‌روزرسانی پلاگین Android Gradle برای استفاده از R8 نباید شما را ملزم به تغییر قوانین موجود خود کند.

کوچک کردن، مبهم سازی و بهینه سازی را فعال کنید

هنگامی که از Android Studio 3.4 یا Android Gradle 3.4.0 و بالاتر استفاده می کنید، R8 کامپایلر پیش فرضی است که بایت کد جاوا پروژه شما را به فرمت DEX که روی پلتفرم اندروید اجرا می شود تبدیل می کند. با این حال، هنگامی که یک پروژه جدید با استفاده از Android Studio ایجاد می کنید، بهینه سازی کد، کوچک شدن، مبهم سازی و کد به طور پیش فرض فعال نیست. دلیلش این است که این بهینه‌سازی‌های زمان کامپایل زمان ساخت پروژه شما را افزایش می‌دهند و در صورتی که کد مورد نظر را به اندازه کافی سفارشی نکنید، ممکن است اشکالاتی را ایجاد کنند.

بنابراین، بهتر است هنگام ساختن نسخه نهایی برنامه خود که قبل از انتشار آزمایش می کنید، این وظایف زمان کامپایل را فعال کنید. برای فعال کردن کوچک کردن، مبهم سازی و بهینه سازی، موارد زیر را در اسکریپت ساخت سطح پروژه خود بگنجانید.

کاتلین

android {
    buildTypes {
        getByName("release") {
            // Enables code shrinking, obfuscation, and optimization for only
            // your project's release build type. Make sure to use a build
            // variant with `isDebuggable=false`.
            isMinifyEnabled = true

            // Enables resource shrinking, which is performed by the
            // Android Gradle plugin.
            isShrinkResources = true

            proguardFiles(
                // Includes the default ProGuard rules files that are packaged with
                // the Android Gradle plugin. To learn more, go to the section about
                // R8 configuration files.
                getDefaultProguardFile("proguard-android-optimize.txt"),

                // Includes a local, custom Proguard rules file
                "proguard-rules.pro"
            )
        }
    }
    ...
}

شیار

android {
    buildTypes {
        release {
            // Enables code shrinking, obfuscation, and optimization for only
            // your project's release build type. Make sure to use a build
            // variant with `debuggable false`.
            minifyEnabled true

            // Enables resource shrinking, which is performed by the
            // Android Gradle plugin.
            shrinkResources true

            // Includes the default ProGuard rules files that are packaged with
            // the Android Gradle plugin. To learn more, go to the section about
            // R8 configuration files.
            proguardFiles getDefaultProguardFile(
                    'proguard-android-optimize.txt'),
                    'proguard-rules.pro'
        }
    }
    ...
}

فایل های پیکربندی R8

R8 از فایل‌های قوانین ProGuard استفاده می‌کند تا رفتار پیش‌فرض خود را اصلاح کند و ساختار برنامه‌تان را بهتر بشناسد، مانند کلاس‌هایی که به عنوان نقاط ورودی به کد برنامه شما عمل می‌کنند. اگرچه می‌توانید برخی از این فایل‌های قوانین را تغییر دهید، برخی از قوانین ممکن است به‌طور خودکار توسط ابزارهای زمان کامپایل مانند AAPT2 ایجاد شوند یا از وابستگی‌های کتابخانه برنامه شما به ارث برده شوند. جدول زیر منابع فایل های قوانین ProGuard را که R8 استفاده می کند، توضیح می دهد.

منبع مکان توضیحات
اندروید استودیو <module-dir>/proguard-rules.pro هنگامی که یک ماژول جدید با استفاده از Android Studio ایجاد می کنید، IDE یک فایل proguard-rules.pro را در فهرست اصلی آن ماژول ایجاد می کند.

به طور پیش فرض، این فایل هیچ قانونی را اعمال نمی کند. بنابراین، قوانین ProGuard خود را در اینجا وارد کنید، مانند قوانین حفظ سفارشی خود.

پلاگین اندروید Gradle در زمان کامپایل توسط افزونه Android Gradle ایجاد شده است. افزونه Android Gradle proguard-android-optimize.txt را ایجاد می کند که شامل قوانینی است که برای اکثر پروژه های Android مفید است و حاشیه نویسی @Keep* را فعال می کند.

به طور پیش فرض، هنگام ایجاد یک ماژول جدید با استفاده از اندروید استودیو، اسکریپت ساخت سطح ماژول شامل این فایل قوانین در بیلد انتشار شما برای شما می شود.

توجه: افزونه Android Gradle شامل فایل‌های قوانین ProGuard از پیش تعریف‌شده اضافی است، اما توصیه می‌شود از proguard-android-optimize.txt استفاده کنید.

وابستگی های کتابخانه

در یک کتابخانه AAR:
proguard.txt

در یک کتابخانه JAR:
META-INF/proguard/<ProGuard-rules-file>

علاوه بر این مکان‌ها، افزونه Android Gradle نسخه 3.6 یا بالاتر نیز از قوانین کوچک کردن هدفمند پشتیبانی می‌کند.

اگر یک کتابخانه AAR یا JAR با فایل قوانین خاص خود منتشر شود و شما آن کتابخانه را به عنوان یک وابستگی زمان کامپایل قرار دهید، R8 به طور خودکار آن قوانین را هنگام کامپایل پروژه شما اعمال می کند.

علاوه بر قوانین معمولی ProGuard، افزونه Android Gradle نسخه 3.6 یا بالاتر نیز از قوانین کوچک کردن هدفمند پشتیبانی می کند. اینها قوانینی هستند که کوچک کننده های خاص (R8 یا ProGuard) و همچنین نسخه های کوچک کننده خاص را هدف قرار می دهند.

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

با این حال، باید توجه داشته باشید که از آنجایی که قوانین افزودنی هستند، برخی از قوانینی که وابستگی کتابخانه شامل آن می شود را نمی توان حذف کرد و ممکن است بر گردآوری قسمت های دیگر برنامه شما تأثیر بگذارد. به عنوان مثال، اگر یک کتابخانه شامل یک قانون برای غیرفعال کردن بهینه سازی کد باشد، آن قانون بهینه سازی را برای کل پروژه شما غیرفعال می کند.

Android Asset Package Tool 2 (AAPT2) پس از ساختن پروژه خود با minifyEnabled true : <module-dir>/build/intermediates/aapt_proguard_file/.../aapt_rules.txt AAPT2 بر اساس ارجاع به کلاس‌ها در مانیفست، طرح‌بندی‌ها و سایر منابع برنامه، قوانین حفظ را ایجاد می‌کند. به عنوان مثال، AAPT2 برای هر فعالیتی که در مانیفست برنامه خود به عنوان نقطه ورودی ثبت می کنید، یک قانون نگه داشتن دارد.
فایل های پیکربندی سفارشی به‌طور پیش‌فرض، وقتی یک ماژول جدید با استفاده از Android Studio ایجاد می‌کنید، IDE <module-dir>/proguard-rules.pro را برای شما ایجاد می‌کند تا قوانین خود را اضافه کنید. می توانید پیکربندی های اضافی اضافه کنید و R8 آنها را در زمان کامپایل اعمال می کند.

هنگامی که ویژگی minifyEnabled را روی true تنظیم می کنید، R8 قوانین را از تمام منابع موجود لیست شده در بالا ترکیب می کند. این مهم است که هنگام عیب‌یابی با R8 به خاطر داشته باشید، زیرا وابستگی‌های زمان کامپایل دیگر، مانند وابستگی‌های کتابخانه، ممکن است تغییراتی را در رفتار R8 ایجاد کنند که شما از آن اطلاعی ندارید.

برای خروجی یک گزارش کامل از تمام قوانینی که R8 هنگام ساخت پروژه خود اعمال می کند، موارد زیر را در فایل proguard-rules.pro ماژول خود قرار دهید:

// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt

قوانین کوچک کردن هدفمند

افزونه Android Gradle نسخه 3.6 یا بالاتر از قوانین کتابخانه‌هایی پشتیبانی می‌کند که کوچک‌کننده‌های خاص (R8 یا ProGuard) و همچنین نسخه‌های کوچک‌کننده خاص را هدف قرار می‌دهند. این به توسعه‌دهندگان کتابخانه اجازه می‌دهد تا قوانین خود را برای کار بهینه در پروژه‌هایی که از نسخه‌های کوچک‌کننده جدید استفاده می‌کنند، تنظیم کنند، در حالی که اجازه می‌دهد قوانین موجود همچنان در پروژه‌هایی با نسخه‌های کوچک‌کننده قدیمی‌تر استفاده شوند.

برای تعیین قوانین کوچک کردن هدفمند، توسعه دهندگان کتابخانه باید آنها را در مکان های خاصی در داخل یک کتابخانه AAR یا JAR قرار دهند، همانطور که در زیر توضیح داده شده است.

In an AAR library:
    proguard.txt (legacy location)
    classes.jar
    └── META-INF
        └── com.android.tools (targeted shrink rules location)
            ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
            └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

In a JAR library:
    META-INF
    ├── proguard/<ProGuard-rules-file> (legacy location)
    └── com.android.tools (targeted shrink rules location)
        ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
        └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

این بدان معناست که قوانین کوچک کردن هدفمند در فهرست META-INF/com.android.tools یک JAR یا در فهرست META-INF/com.android.tools داخل classes.jar یک AAR ذخیره می‌شوند.

در زیر آن دایرکتوری، می‌توان چندین دایرکتوری با نام‌هایی به شکل r8-from-<X>-upto-<Y> یا proguard-from-<X>-upto-<Y> وجود داشته باشد تا مشخص شود کدام نسخه‌های کوچک‌کننده قوانین داخل دایرکتوری ها برای آنها نوشته شده است. توجه داشته باشید که قسمت های -from-<X> و -upto-<Y> اختیاری هستند، نسخه <Y> انحصاری است و محدوده های نسخه باید پیوسته باشند.

برای مثال، r8-upto-8.0.0 ، r8-from-8.0.0-upto-8.2.0 و r8-from-8.2.0 مجموعه معتبری از قوانین کوچک کردن هدفمند را تشکیل می دهند. قوانین تحت پوشه r8-from-8.0.0-upto-8.2.0 توسط R8 از نسخه 8.0.0 تا نسخه 8.0.0 استفاده می شود، اما شامل نسخه 8.2.0 نمی شود .

با توجه به این اطلاعات، افزونه Android Gradle نسخه 3.6 یا بالاتر، قوانین را از فهرست های R8 منطبق انتخاب می کند. اگر یک کتابخانه قوانین کوچک کردن هدفمند را مشخص نکند، افزونه Android Gradle قوانین را از مکان‌های قدیمی انتخاب می‌کند ( proguard.txt برای AAR یا META-INF/proguard/<ProGuard-rules-file> برای JAR).

توسعه‌دهندگان کتابخانه می‌توانند برای حفظ سازگاری با افزونه Android Gradle قدیمی‌تر از 3.6 یا ابزارهای دیگر، قوانین هدفمند کوچک کردن یا قوانین ProGuard قدیمی را در کتابخانه‌های خود یا هر دو نوع را در کتابخانه‌های خود بگنجانند.

شامل تنظیمات اضافی

هنگامی که یک پروژه یا ماژول جدید با استفاده از Android Studio ایجاد می کنید، IDE یک فایل <module-dir>/proguard-rules.pro را برای شما ایجاد می کند تا قوانین خود را در آن لحاظ کنید. همچنین می‌توانید با افزودن آنها به ویژگی proguardFiles در اسکریپت ساخت ماژول، قوانین اضافی را از فایل‌های دیگر اضافه کنید.

به عنوان مثال، می‌توانید با افزودن یک ویژگی proguardFiles دیگر در بلوک productFlavor مربوطه، قوانینی را اضافه کنید که مختص هر نوع ساخت هستند. فایل Gradle زیر flavor2-rules.pro را به طعم محصول flavor2 اضافه می کند. اکنون، flavor2 از هر سه قانون ProGuard استفاده می‌کند، زیرا قوانین مربوط به بلوک release نیز اعمال می‌شوند.

علاوه بر این، می‌توانید ویژگی testProguardFiles را اضافه کنید که فهرستی از فایل‌های ProGuard را که فقط در APK آزمایشی گنجانده شده‌اند را مشخص می‌کند:

کاتلین

android {
    ...
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                // List additional ProGuard rules for the given build type here. By default,
                // Android Studio creates and includes an empty rules file for you (located
                // at the root directory of each module).
                "proguard-rules.pro"
            )
            testProguardFiles(
                // The proguard files listed here are included in the
                // test APK only.
                "test-proguard-rules.pro"
            )
        }
    }
    flavorDimensions.add("version")
    productFlavors {
        create("flavor1") {
            ...
        }
        create("flavor2") {
            proguardFile("flavor2-rules.pro")
        }
    }
}

شیار

android {
    ...
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles
                getDefaultProguardFile('proguard-android-optimize.txt'),
                // List additional ProGuard rules for the given build type here. By default,
                // Android Studio creates and includes an empty rules file for you (located
                // at the root directory of each module).
                'proguard-rules.pro'
            testProguardFiles
                // The proguard files listed here are included in the
                // test APK only.
                'test-proguard-rules.pro'
        }
    }
    flavorDimensions "version"
    productFlavors {
        flavor1 {
            ...
        }
        flavor2 {
            proguardFile 'flavor2-rules.pro'
        }
    }
}

کد خود را کوچک کنید

هنگامی که ویژگی minifyEnabled روی true تنظیم می کنید، کوچک شدن کد با R8 به طور پیش فرض فعال می شود.

کوچک کردن کد (همچنین به عنوان تکان دادن درخت شناخته می شود)، فرآیند حذف کدی است که R8 تشخیص می دهد در زمان اجرا لازم نیست. اگر برای مثال، برنامه شما دارای وابستگی های کتابخانه ای زیادی باشد اما تنها از بخش کوچکی از عملکرد آنها استفاده کند، این فرآیند می تواند اندازه برنامه شما را تا حد زیادی کاهش دهد.

برای کوچک کردن کد برنامه، R8 ابتدا تمام نقاط ورود به کد برنامه شما را بر اساس مجموعه فایل‌های پیکربندی ترکیبی تعیین می‌کند. این نقاط ورودی شامل تمام کلاس‌هایی است که پلتفرم Android ممکن است برای باز کردن فعالیت‌ها یا خدمات برنامه شما از آنها استفاده کند. با شروع از هر نقطه ورودی، R8 کد برنامه شما را بررسی می کند تا نموداری از همه روش ها، متغیرهای عضو و سایر کلاس هایی که برنامه شما ممکن است در زمان اجرا به آنها دسترسی داشته باشد بسازد. کدی که به آن نمودار متصل نیست غیرقابل دسترس تلقی می شود و ممکن است از برنامه حذف شود.

شکل 1 یک برنامه با وابستگی به کتابخانه زمان اجرا را نشان می دهد. در حین بررسی کد برنامه، R8 تشخیص می دهد که متدهای foo() , faz() و bar() از نقطه ورودی MainActivity.class قابل دسترسی هستند. با این حال، کلاس OkayApi.class یا متد baz() هرگز توسط برنامه شما در زمان اجرا استفاده نمی شود و R8 آن کد را هنگام کوچک کردن برنامه شما حذف می کند.

شکل 1. در زمان کامپایل، R8 یک نمودار بر اساس قوانین نگهداری ترکیبی پروژه شما برای تعیین کد غیرقابل دسترس می سازد.

R8 نقاط ورودی را از طریق قوانین -keep در فایل های پیکربندی R8 پروژه تعیین می کند. به این معنی که قوانین حفظ، کلاس‌هایی را مشخص می‌کنند که R8 نباید هنگام کوچک کردن برنامه‌تان آن‌ها را کنار بگذارد و R8 آن کلاس‌ها را به عنوان نقاط ورود احتمالی به برنامه شما در نظر می‌گیرد. افزونه Android Gradle و AAPT2 به‌طور خودکار قوانین نگه‌داری را ایجاد می‌کنند که اکثر پروژه‌های برنامه برای شما مورد نیاز هستند، مانند فعالیت‌ها، بازدیدها و خدمات برنامه‌تان. با این حال، اگر می‌خواهید این رفتار پیش‌فرض را با قوانین نگه‌داری اضافی سفارشی کنید، بخش نحوه سفارشی‌سازی کد نگه‌داری را بخوانید.

اگر در عوض فقط به کاهش حجم منابع برنامه خود علاقه دارید، به بخش نحوه کوچک کردن منابع خود بروید.

توجه داشته باشید که اگر یک پروژه کتابخانه کوچک شود، برنامه‌ای که به آن کتابخانه وابسته است شامل کلاس‌های کتابخانه کوچک شده است. اگر کلاس‌هایی در APK کتابخانه وجود ندارد، ممکن است لازم باشد قوانین نگهداری کتابخانه را تنظیم کنید. اگر در حال ساخت و انتشار یک کتابخانه با فرمت AAR هستید، فایل‌های JAR محلی که کتابخانه شما به آن وابسته است، در فایل AAR کوچک نمی‌شوند .

کدی را که باید حفظ شود سفارشی کنید

برای اکثر مواقع، فایل قوانین پیش‌فرض ProGuard ( proguard-android-optimize.txt ) برای R8 کافی است تا فقط کدهای استفاده نشده را حذف کند. با این حال، تجزیه و تحلیل درست برخی از موقعیت‌ها برای R8 دشوار است و ممکن است کدهایی را که برنامه شما واقعاً به آن نیاز دارد حذف کند. چند نمونه از مواردی که ممکن است کد را به اشتباه حذف کند عبارتند از:

  • وقتی برنامه شما روشی را از رابط بومی جاوا (JNI) فراخوانی می‌کند.
  • وقتی برنامه شما کد را در زمان اجرا جستجو می کند (مانند بازتاب)

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

برای رفع خطاها و مجبور کردن R8 به نگه داشتن کد خاص، یک خط -keep را در فایل قوانین ProGuard اضافه کنید. به عنوان مثال:

-keep public class MyClass

از طرف دیگر، می‌توانید حاشیه‌نویسی @Keep به کدی که می‌خواهید نگه دارید اضافه کنید. افزودن @Keep به یک کلاس کل کلاس را همانطور که هست نگه می دارد. افزودن آن به یک متد یا فیلد، متد/فیلد (و نام آن) و همچنین نام کلاس را دست نخورده نگه می‌دارد. توجه داشته باشید که این حاشیه‌نویسی فقط در صورت استفاده از کتابخانه Annotations AndroidX و زمانی که فایل قوانین ProGuard را که با افزونه Android Gradle بسته‌بندی شده است، در دسترس قرار می‌دهید، همانطور که در بخش نحوه فعال کردن کوچک کردن توضیح داده شده است.

هنگام استفاده از گزینه -keep باید ملاحظات زیادی را رعایت کنید. برای اطلاعات بیشتر در مورد سفارشی کردن فایل قوانین خود، راهنمای ProGuard را بخوانید. بخش عیب‌یابی سایر مشکلات رایجی را که ممکن است هنگام حذف کدتان با آن مواجه شوید، تشریح می‌کند.

کتابخانه های بومی را حذف کنید

به‌طور پیش‌فرض، کتابخانه‌های کد بومی در نسخه‌های انتشار برنامه شما حذف می‌شوند. این حذف شامل حذف جدول نمادها و اشکال زدایی اطلاعات موجود در کتابخانه های بومی مورد استفاده برنامه شما است. حذف کتابخانه های کد بومی منجر به صرفه جویی قابل توجهی در اندازه می شود. با این حال، تشخیص خرابی در کنسول Google Play به دلیل اطلاعات از دست رفته (مانند نام کلاس و عملکرد) غیرممکن است.

پشتیبانی از خرابی بومی

کنسول Google Play خرابی های بومی تحت حیاتی اندروید را گزارش می کند. با چند مرحله، می توانید یک فایل نمادهای اشکال زدایی بومی را برای برنامه خود ایجاد و آپلود کنید. این فایل ردیابی پشته تصادف بومی نمادین (شامل نام کلاس و توابع) را در حیاتی اندروید فعال می‌کند تا به شما کمک کند برنامه خود را در مرحله تولید اشکال‌زدایی کنید. این مراحل بسته به نسخه پلاگین Android Gradle مورد استفاده در پروژه شما و خروجی ساخت پروژه شما متفاوت است.

پلاگین Android Gradle نسخه 4.1 یا بالاتر

اگر پروژه شما یک Android App Bundle می سازد، می توانید به طور خودکار فایل نمادهای اشکال زدایی بومی را در آن قرار دهید. برای گنجاندن این فایل در نسخه‌های انتشار، موارد زیر را به فایل build.gradle.kts برنامه خود اضافه کنید:

android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }

سطح نماد اشکال زدایی را از موارد زیر انتخاب کنید:

  • از SYMBOL_TABLE برای دریافت نام توابع در ردپای نمادین پشته کنسول Play استفاده کنید. این سطح از سنگ قبرها پشتیبانی می کند.
  • FULL برای دریافت نام توابع، فایل‌ها و شماره خطوط در ردیابی پشته نمادین کنسول Play استفاده کنید.

اگر پروژه شما یک APK می‌سازد، از تنظیمات ساخت build.gradle.kts که قبلاً نشان داده شده بود استفاده کنید تا فایل نمادهای اشکال زدایی بومی را جداگانه ایجاد کنید. فایل نمادهای اشکال زدایی بومی را به صورت دستی در کنسول Google Play آپلود کنید . به عنوان بخشی از فرآیند ساخت، افزونه Android Gradle این فایل را در محل پروژه زیر خروجی می‌دهد:

app/build/outputs/native-debug-symbols/ variant-name /native-debug-symbols.zip

پلاگین Android Gradle نسخه 4.0 یا بالاتر (و سایر سیستم های ساخت)

به عنوان بخشی از فرآیند ساخت، پلاگین Android Gradle یک کپی از کتابخانه‌های جدا نشده را در فهرست پروژه نگه می‌دارد. این ساختار دایرکتوری شبیه به زیر است:

app/build/intermediates/cmake/universal/release/obj/
├── armeabi-v7a/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
├── arm64-v8a/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
├── x86/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
└── x86_64/
    ├── libgameengine.so
    ├── libothercode.so
    └── libvideocodec.so
  1. محتویات این دایرکتوری را فشرده کنید:

    cd app/build/intermediates/cmake/universal/release/obj
    zip -r symbols.zip .
    
  2. فایل symbols.zip را به صورت دستی در کنسول Google Play آپلود کنید .

منابع خود را کوچک کنید

کوچک کردن منابع فقط در رابطه با کوچک کردن کد کار می کند. پس از حذف کدهای کوچک‌کننده، همه کدهای استفاده نشده را حذف می‌کند، کوچک‌کننده منابع می‌تواند شناسایی کند که برنامه هنوز از چه منابعی استفاده می‌کند. این امر مخصوصاً زمانی صادق است که شما کتابخانه‌های کدی را که شامل منابع هستند اضافه می‌کنید—شما باید کد کتابخانه استفاده‌نشده را حذف کنید تا منابع کتابخانه بی‌ارجاع شوند و در نتیجه توسط کوچک‌کننده منبع قابل حذف باشند.

برای فعال کردن کوچک شدن منابع، ویژگی shrinkResources را در اسکریپت ساخت خود روی true تنظیم کنید (در کنار minifyEnabled برای کوچک کردن کد). به عنوان مثال:

کاتلین

android {
    ...
    buildTypes {
        getByName("release") {
            isShrinkResources = true
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

شیار

android {
    ...
    buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles
                getDefaultProguardFile('proguard-android.txt'),
                'proguard-rules.pro'
        }
    }
}

اگر قبلاً برنامه خود را با استفاده از minifyEnabled برای کوچک کردن کد نساخته‌اید، قبل از فعال کردن shrinkResources آن را امتحان کنید، زیرا ممکن است لازم باشد فایل proguard-rules.pro خود را ویرایش کنید تا کلاس‌ها یا روش‌هایی را که ایجاد یا فراخوانی می‌شوند به صورت پویا قبل از شروع حذف نگه دارید. منابع

شخصی سازی کنید که کدام منابع را نگه دارید

اگر منابع خاصی وجود دارد که می‌خواهید آن را نگه دارید یا کنار بگذارید، یک فایل XML در پروژه خود با تگ <resources> ایجاد کنید و هر منبع را در ویژگی tools:keep و هر منبع را در ویژگی tools:discard مشخص کنید. هر دو ویژگی فهرستی از نام منابع را می‌پذیرند که با کاما جدا شده‌اند. می توانید از کاراکتر ستاره به عنوان کارت وحشی استفاده کنید.

به عنوان مثال:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
    tools:discard="@layout/unused2" />

این فایل را در منابع پروژه خود ذخیره کنید، به عنوان مثال، در res/raw/my.package.keep.xml . بیلد این فایل را در برنامه شما بسته بندی نمی کند.

توجه: حتما از یک نام منحصر به فرد برای فایل keep استفاده کنید. وقتی کتابخانه‌های مختلف با هم مرتبط می‌شوند، قوانین نگهداری آنها در غیر این صورت با هم تضاد می‌کنند، و باعث ایجاد مشکلات بالقوه با قوانین نادیده گرفته شده یا منابع نگهداری غیر ضروری می‌شود.

مشخص کردن منابعی که باید حذف شوند ممکن است احمقانه به نظر برسد، اما این می تواند هنگام استفاده از انواع ساخت مفید باشد. به عنوان مثال، ممکن است تمام منابع خود را در دایرکتوری مشترک پروژه قرار دهید، سپس یک فایل my.package.build.variant.keep.xml متفاوت برای هر نوع ساخت ایجاد کنید، زمانی که می دانید به نظر می رسد یک منبع داده شده در کد استفاده می شود (و بنابراین توسط شرینکر حذف نمی شود) اما می دانید که در واقع برای نوع ساخت داده شده استفاده نخواهد شد. همچنین این امکان وجود دارد که ابزارهای ساخت به اشتباه منبع مورد نیاز را شناسایی کرده باشند، که این امکان وجود دارد زیرا کامپایلر شناسه های منبع را به صورت درون خطی اضافه می کند و سپس تحلیلگر منبع ممکن است تفاوت بین یک منبع ارجاع شده واقعی و یک مقدار صحیح در کد را که اتفاق می افتد نداند. ارزش یکسانی دارند

بررسی های مرجع دقیق را فعال کنید

به طور معمول، کوچک کننده منبع می تواند به دقت تعیین کند که آیا از یک منبع استفاده شده است یا خیر. با این حال، اگر کد شما با Resources.getIdentifier() تماس بگیرد (یا اگر هر یک از کتابخانه های شما این کار را انجام دهد—کتابخانه AppCompat این کار را می کند)، به این معنی است که کد شما نام منابع را بر اساس رشته های تولید شده به صورت پویا جستجو می کند. وقتی این کار را انجام می‌دهید، کوچک‌کننده منبع به‌طور پیش‌فرض رفتار تدافعی دارد و همه منابع را با قالب نام منطبق به‌عنوان بالقوه استفاده شده و غیرقابل حذف علامت‌گذاری می‌کند.

به عنوان مثال، کد زیر باعث می شود که تمام منابع با پیشوند img_ به عنوان استفاده شده علامت گذاری شوند.

کاتلین

val name = String.format("img_%1d", angle + 1)
val res = resources.getIdentifier(name, "drawable", packageName)

جاوا

String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());

کوچک‌کننده منبع همچنین تمام ثابت‌های رشته‌ای در کد شما و همچنین منابع مختلف res/raw/ را بررسی می‌کند و به دنبال URLهای منبع در قالبی مشابه file:///android_res/drawable//ic_plus_anim_016.png می‌گردد. اگر رشته‌هایی مانند این یا رشته‌های دیگری را پیدا کند که به نظر می‌رسد می‌توان از آنها برای ساخت نشانی‌های اینترنتی مانند این استفاده کرد، آنها را حذف نمی‌کند.

اینها نمونه هایی از حالت انقباض ایمن هستند که به طور پیش فرض فعال است. با این حال، می‌توانید این مدیریت «ایمن‌تر از متأسفانه» را خاموش کنید و مشخص کنید که کوچک‌کننده منابع فقط منابعی را نگه می‌دارد که مطمئن است استفاده می‌شوند. برای انجام این کار، shrinkMode در فایل keep.xml به صورت strict گیر کنید:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:shrinkMode="strict" />

اگر حالت انقباض دقیق را فعال کنید و کد شما همچنین به منابعی با رشته های تولید شده به صورت پویا ارجاع می دهد، همانطور که در بالا نشان داده شده است، باید به صورت دستی آن منابع را با استفاده از ویژگی tools:keep نگه دارید.

منابع جایگزین استفاده نشده را حذف کنید

کوچک‌کننده منابع Gradle فقط منابعی را حذف می‌کند که کد برنامه شما به آنها ارجاع نمی‌دهد، به این معنی که منابع جایگزین را برای پیکربندی‌های مختلف دستگاه حذف نمی‌کند. در صورت لزوم، می‌توانید از ویژگی resConfigs افزونه Android Gradle برای حذف فایل‌های منبع جایگزینی که برنامه شما به آن نیازی ندارد، استفاده کنید.

برای مثال، اگر از کتابخانه‌ای استفاده می‌کنید که شامل منابع زبانی است (مانند AppCompat یا Google Play Services)، برنامه شما شامل تمام رشته‌های زبان ترجمه‌شده برای پیام‌های موجود در آن کتابخانه‌ها می‌شود، چه بقیه برنامه شما به همان زبان‌ها ترجمه شده باشد یا نه اگر می‌خواهید فقط زبان‌هایی را نگه دارید که برنامه شما به طور رسمی از آنها پشتیبانی می‌کند، می‌توانید آن زبان‌ها را با استفاده از ویژگی resConfig مشخص کنید. هر منبعی برای زبان های مشخص نشده حذف می شود.

قطعه زیر نشان می دهد که چگونه منابع زبان خود را فقط به انگلیسی و فرانسوی محدود کنید:

کاتلین

android {
    defaultConfig {
        ...
        resourceConfigurations.addAll(listOf("en", "fr"))
    }
}

شیار

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

هنگام انتشار یک برنامه با استفاده از قالب Android App Bundle، به طور پیش‌فرض فقط زبان‌های پیکربندی شده در دستگاه کاربر هنگام نصب برنامه دانلود می‌شوند. به طور مشابه، تنها منابعی که با تراکم صفحه دستگاه مطابقت دارند و کتابخانه های بومی مطابق با ABI دستگاه در دانلود گنجانده شده است. برای اطلاعات بیشتر به پیکربندی Android App Bundle مراجعه کنید.

برای برنامه‌های قدیمی که با APK منتشر می‌شوند (که قبل از آگوست 2021 ایجاد شده‌اند)، می‌توانید با ساختن چندین APK که هر کدام پیکربندی دستگاه متفاوتی را هدف قرار می‌دهند، تراکم صفحه یا منابع ABI را در APK خود تنظیم کنید.

ادغام منابع تکراری

به‌طور پیش‌فرض، Gradle منابعی با نام یکسان را ادغام می‌کند. این رفتار توسط ویژگی shrinkResources کنترل نمی‌شود و نمی‌توان آن را غیرفعال کرد، زیرا لازم است وقتی چندین منبع با نامی که کد شما جستجو می‌شود مطابقت دارند از خطا جلوگیری شود.

ادغام منابع تنها زمانی اتفاق می افتد که دو یا چند فایل نام، نوع و واجد شرایط منبع یکسانی را به اشتراک بگذارند. Gradle انتخاب می کند که کدام فایل را بهترین انتخاب در بین موارد تکراری می داند (بر اساس ترتیب اولویت که در زیر توضیح داده شده است) و فقط آن یک منبع را برای توزیع در آرتیفکت نهایی به AAPT ارسال می کند.

Gradle به دنبال منابع تکراری در مکان‌های زیر می‌گردد:

  • منابع اصلی، مرتبط با مجموعه منبع اصلی، معمولاً در src/main/res/ قرار دارند.
  • پوشش های مختلف، از نوع ساخت و طعم های ساخت.
  • وابستگی های پروژه کتابخانه

Gradle منابع تکراری را به ترتیب اولویت آبشاری زیر ادغام می کند:

وابستگی ها → اصلی → طعم ساخت → نوع ساخت

به عنوان مثال، اگر یک منبع تکراری هم در منابع اصلی و هم در طعم ساخت ظاهر می شود، Gradle منبعی را در طعم ساخت انتخاب می کند.

اگر منابع یکسان در مجموعه منبع یکسان ظاهر شوند، Gradle نمی تواند آنها را ادغام کند و یک خطای ادغام منابع منتشر می کند. اگر چندین مجموعه منبع را در ویژگی sourceSet فایل build.gradle.kts خود تعریف کنید، ممکن است اتفاق بیفتد - برای مثال اگر هر دو src/main/res/ و src/main/res2/ دارای منابع یکسان باشند.

کد خود را مبهم کنید

هدف از مبهم سازی کاهش اندازه برنامه شما با کوتاه کردن نام کلاس ها، روش ها و فیلدهای برنامه شما است. مثال زیر نمونه ای از مبهم سازی با استفاده از R8 است:

androidx.appcompat.app.ActionBarDrawerToggle$DelegateProvider -> a.a.a.b:
androidx.appcompat.app.AlertController -> androidx.appcompat.app.AlertController:
    android.content.Context mContext -> a
    int mListItemLayout -> O
    int mViewSpacingRight -> l
    android.widget.Button mButtonNeutral -> w
    int mMultiChoiceItemLayout -> M
    boolean mShowTitle -> P
    int mViewSpacingLeft -> j
    int mButtonPanelSideLayout -> K

در حالی که مبهم سازی کد را از برنامه شما حذف نمی کند، صرفه جویی در اندازه قابل توجهی را می توان در برنامه هایی با فایل های DEX مشاهده کرد که بسیاری از کلاس ها، روش ها و فیلدها را فهرست می کنند. با این حال، از آنجایی که مبهم سازی قسمت‌های مختلف کد شما را تغییر نام می‌دهد، وظایف خاصی مانند بررسی ردپای پشته، به ابزارهای اضافی نیاز دارد. برای درک stacktrace خود پس از مبهم کردن، بخش نحوه رمزگشایی یک stack trace مبهم را بخوانید.

به‌علاوه، اگر کد شما متکی به نام‌گذاری قابل پیش‌بینی برای روش‌ها و کلاس‌های برنامه‌تان است—مثلاً هنگام استفاده از بازتاب، باید آن امضاها را به‌عنوان نقاط ورودی در نظر بگیرید و قوانین حفظ را برای آن‌ها مشخص کنید، همانطور که در بخش نحوه سفارشی کردن کد توضیح داده شد. نگه داشتن . این قوانین حفظ به R8 می گویند که نه تنها آن کد را در DEX نهایی برنامه شما نگه دارد، بلکه نام اصلی خود را نیز حفظ کند.

رمزگشایی یک رد پشته مبهم

بعد از اینکه R8 کد شما را مبهم کرد، درک ردیابی پشته دشوار است (اگر غیرممکن نباشد) زیرا ممکن است نام کلاس ها و متدها تغییر کرده باشند. برای به دست آوردن ردیابی پشته اصلی باید ردیابی پشته را دوباره دنبال کنید.

بهینه سازی کد

به منظور بهینه سازی برنامه شما حتی بیشتر، R8 کد شما را در سطح عمیق تری بازرسی می کند تا کدهای استفاده نشده بیشتری را حذف کند یا، در صورت امکان، کد شما را بازنویسی کند تا کمتر پرمخاطب باشد. در زیر چند نمونه از این بهینه سازی ها آورده شده است:

  • اگر کد شما هرگز شاخه else {} را برای یک عبارت if/else نمی گیرد، R8 ممکن است کد شعبه else {} را حذف کند.
  • اگر کد شما یک روش را فقط در چند مکان فراخوانی می‌کند، R8 ممکن است روش را حذف کرده و آن را در چند سایت تماس وارد کند.
  • اگر R8 تشخیص دهد که یک کلاس فقط یک زیر کلاس منحصر به فرد دارد، و خود کلاس نمونه سازی نشده است (به عنوان مثال، یک کلاس پایه انتزاعی فقط توسط یک کلاس پیاده سازی مشخص استفاده می شود)، آنگاه R8 می تواند دو کلاس را ترکیب کرده و یک کلاس را از برنامه حذف کند. .
  • برای کسب اطلاعات بیشتر، پست های وبلاگ بهینه سازی R8 توسط جیک وارتون را بخوانید.

R8 به شما اجازه نمی دهد که بهینه سازی های گسسته را غیرفعال یا فعال کنید، یا رفتار یک بهینه سازی را تغییر دهید. در واقع، R8 قوانین ProGuard را که سعی در اصلاح بهینه‌سازی‌های پیش‌فرض دارند، مانند -optimizations و -optimizationpasses را نادیده می‌گیرد. این محدودیت مهم است زیرا با ادامه بهبود R8، حفظ یک رفتار استاندارد برای بهینه‌سازی به تیم اندروید استودیو کمک می‌کند تا به راحتی هر مشکلی را که ممکن است با آن مواجه شوید عیب‌یابی و حل کند.

توجه داشته باشید که فعال کردن بهینه سازی، ردیابی پشته را برای برنامه شما تغییر می دهد. برای مثال، درون‌سازی، فریم‌های پشته را حذف می‌کند. برای یادگیری نحوه به دست آوردن ردیابی پشته اصلی به بخش ردیابی مجدد مراجعه کنید.

تاثیر بر عملکرد زمان اجرا

اگر کوچک کردن، مبهم سازی و بهینه‌سازی همگی فعال باشند، R8 عملکرد زمان اجرا کد (از جمله زمان راه‌اندازی و فریم در رشته رابط کاربر) را تا 30 درصد بهبود می‌بخشد. غیرفعال کردن هر یک از این موارد، مجموعه بهینه‌سازی‌هایی را که R8 استفاده می‌کند، به شدت محدود می‌کند.

اگر R8 فعال است، برای عملکرد راه‌اندازی بهتر نیز باید نمایه‌های راه‌اندازی ایجاد کنید .

بهینه سازی های تهاجمی تر را فعال کنید

R8 شامل مجموعه ای از بهینه سازی های اضافی است (که به آن "حالت کامل" گفته می شود) که باعث می شود رفتار متفاوتی با ProGuard داشته باشد. این بهینه‌سازی‌ها به‌طور پیش‌فرض از پلاگین Android Gradle نسخه 8.0.0 فعال هستند.

می توانید این بهینه سازی های اضافی را با قرار دادن موارد زیر در فایل gradle.properties پروژه خود غیرفعال کنید:

android.enableR8.fullMode=false

از آنجایی که بهینه‌سازی‌های اضافی باعث می‌شود R8 متفاوت از ProGuard رفتار کند، ممکن است از شما بخواهد که قوانین ProGuard اضافی را برای جلوگیری از مشکلات زمان اجرا در صورتی که از قوانین طراحی‌شده برای ProGuard استفاده می‌کنید، اضافه کنید. به عنوان مثال، بگویید که کد شما از طریق Java Reflection API به یک کلاس ارجاع می دهد. وقتی از "حالت کامل" استفاده نمی‌کنید ، R8 فرض می‌کند که شما قصد دارید اشیاء آن کلاس را در زمان اجرا بررسی و دستکاری کنید - حتی اگر کد شما واقعاً این کار را نمی‌کند - و به طور خودکار کلاس و مقدار اولیه استاتیک آن را نگه می‌دارد.

با این حال، هنگام استفاده از "حالت کامل"، R8 این فرض را نمی‌کند و اگر R8 ادعا کند که در غیر این صورت کد شما هرگز از کلاس در زمان اجرا استفاده نمی‌کند، کلاس را از DEX نهایی برنامه شما حذف می‌کند. یعنی اگر می‌خواهید کلاس و استاتیک اولیه آن را حفظ کنید، باید یک قانون keep را در فایل قوانین خود قرار دهید تا این کار را انجام دهید.

اگر هنگام استفاده از "حالت کامل" R8 با مشکلی مواجه شدید، برای راه حل احتمالی به صفحه پرسش و پاسخ R8 مراجعه کنید. اگر نمی توانید مشکل را حل کنید، لطفاً یک اشکال را گزارش کنید .

ردیابی مجدد stacktraces

کد پردازش شده توسط R8 به روش‌های مختلفی تغییر می‌کند که می‌تواند درک ردپای پشته را سخت‌تر کند، زیرا ردیابی پشته دقیقاً با کد منبع مطابقت ندارد. این می تواند در مورد تغییرات در شماره خطوط زمانی که اطلاعات اشکال زدایی نگهداری نمی شود. این می تواند به دلیل بهینه سازی هایی مانند inlining و outlining باشد. بزرگترین عامل مبهم سازی است که در آن حتی کلاس ها و متدها نیز نام ها را تغییر می دهند.

برای بازیابی پشته اصلی، R8 ابزار خط فرمان retrace را ارائه می‌کند که با بسته ابزار خط فرمان همراه است.

برای پشتیبانی از ردیابی مجدد ردیابی پشته برنامه خود، باید با افزودن قوانین زیر به فایل proguard-rules.pro ماژول خود، اطمینان حاصل کنید که ساخت اطلاعات کافی برای ردیابی مجدد را حفظ می کند:

-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile

ویژگی LineNumberTable اطلاعات موقعیتی را در روش هایی حفظ می کند که این موقعیت ها در ردیابی پشته چاپ می شوند. ویژگی SourceFile تضمین می‌کند که تمام زمان‌های اجرا بالقوه واقعاً اطلاعات موقعیتی را چاپ می‌کنند. دستور -renamesourcefileattribute نام فایل منبع در stack traces را فقط به SourceFile تنظیم می کند. نام فایل منبع اصلی واقعی هنگام ردیابی مجدد لازم نیست زیرا فایل نگاشت حاوی فایل منبع اصلی است.

R8 هر بار که اجرا می‌شود یک فایل mapping.txt ایجاد می‌کند که حاوی اطلاعات مورد نیاز برای ترسیم ردپای پشته‌ها به دنباله‌های پشته اصلی است. Android Studio فایل را در فهرست <module-name> /build/outputs/mapping/ <build-type> / ذخیره می کند.

هنگام انتشار برنامه خود در Google Play، می توانید فایل mapping.txt را برای هر نسخه از برنامه خود آپلود کنید. هنگام انتشار با استفاده از بسته نرم افزاری Android، این فایل به طور خودکار به عنوان بخشی از محتوای بسته برنامه گنجانده می شود. سپس Google Play ردیابی پشته های ورودی از مشکلات گزارش شده توسط کاربر را مجدداً ردیابی می کند تا بتوانید آنها را در Play Console مرور کنید. برای اطلاعات بیشتر، به مقاله مرکز راهنمایی درباره نحوه رفع ابهام از ردیابی پشته خرابی مراجعه کنید.

عیب یابی با R8

این بخش برخی از استراتژی‌ها را برای عیب‌یابی مشکلات هنگام فعال کردن کوچک کردن، مبهم‌سازی و بهینه‌سازی با استفاده از R8 توضیح می‌دهد. اگر در زیر راه‌حلی برای مشکل خود پیدا نکردید، صفحه پرسش‌های متداول R8 و راهنمای عیب‌یابی ProGuard را نیز بخوانید.

گزارشی از کد حذف شده (یا نگهداری شده) ایجاد کنید

برای کمک به عیب یابی برخی از مشکلات R8، دیدن گزارشی از تمام کدهایی که R8 از برنامه شما حذف کرده است، ممکن است مفید باشد. برای هر ماژولی که می‌خواهید این گزارش را برای آن ایجاد کنید، -printusage <output-dir>/usage.txt را به فایل قوانین سفارشی خود اضافه کنید. وقتی R8 را فعال می‌کنید و برنامه خود را می‌سازید، R8 گزارشی با مسیر و نام فایلی که شما مشخص کرده‌اید را خروجی می‌دهد. گزارش کد حذف شده شبیه به زیر است:

androidx.drawerlayout.R$attr
androidx.vectordrawable.R
androidx.appcompat.app.AppCompatDelegateImpl
    public void setSupportActionBar(androidx.appcompat.widget.Toolbar)
    public boolean hasWindowFeature(int)
    public void setHandleNativeActionModesEnabled(boolean)
    android.view.ViewGroup getSubDecor()
    public void setLocalNightMode(int)
    final androidx.appcompat.app.AppCompatDelegateImpl$AutoNightModeManager getAutoNightModeManager()
    public final androidx.appcompat.app.ActionBarDrawerToggle$Delegate getDrawerToggleDelegate()
    private static final boolean DEBUG
    private static final java.lang.String KEY_LOCAL_NIGHT_MODE
    static final java.lang.String EXCEPTION_HANDLER_MESSAGE_SUFFIX
...

اگر در عوض می‌خواهید گزارشی از نقاط ورودی که R8 از قوانین حفظ پروژه خود تعیین می‌کند، مشاهده کنید، -printseeds <output-dir>/seeds.txt را در فایل قوانین سفارشی خود قرار دهید. وقتی R8 را فعال می‌کنید و برنامه خود را می‌سازید، R8 گزارشی با مسیر و نام فایلی که شما مشخص کرده‌اید را خروجی می‌دهد. گزارش نقاط ورودی نگهداری شده مشابه موارد زیر است:

com.example.myapplication.MainActivity
androidx.appcompat.R$layout: int abc_action_menu_item_layout
androidx.appcompat.R$attr: int activityChooserViewStyle
androidx.appcompat.R$styleable: int MenuItem_android_id
androidx.appcompat.R$styleable: int[] CoordinatorLayout_Layout
androidx.lifecycle.FullLifecycleObserverAdapter
...

عیب یابی کاهش منابع

وقتی منابع را کوچک می کنید، Build پنجره خلاصه ای از منابع حذف شده از برنامه را نشان می دهد. (باید ابتدا روی Toggle view کلیک کنید در سمت چپ پنجره برای نمایش خروجی متن دقیق از Gradle.) به عنوان مثال:

:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning

Gradle همچنین یک فایل تشخیصی به نام resources.txt در <module-name>/build/outputs/mapping/release/ (همان پوشه فایل های خروجی ProGuard) ایجاد می کند. این فایل شامل جزئیاتی مانند اینکه کدام منابع به منابع دیگر ارجاع می دهند و کدام منابع استفاده شده یا حذف شده است.

برای مثال، برای اینکه بفهمید چرا @drawable/ic_plus_anim_016 هنوز در برنامه شما است، فایل resources.txt را باز کنید و نام آن فایل را جستجو کنید. ممکن است متوجه شوید که از منبع دیگری ارجاع داده شده است، به شرح زیر:

16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out]     @drawable/ic_plus_anim_016

اکنون باید بدانید که چرا @drawable/add_schedule_fab_icon_anim قابل دسترسی است—و اگر به سمت بالا جستجو کنید می‌بینید که منبع در زیر «منابع قابل دسترسی ریشه هستند:» فهرست شده است. این بدان معناست که یک مرجع کد به add_schedule_fab_icon_anim وجود دارد (یعنی شناسه R.drawable آن در کد قابل دسترسی پیدا شده است).

اگر از بررسی دقیق استفاده نمی‌کنید، شناسه‌های منبع را می‌توان به‌عنوان قابل دسترسی علامت‌گذاری کرد اگر ثابت‌های رشته‌ای وجود داشته باشند که به نظر می‌رسد ممکن است برای ساخت نام منابع برای منابع بارگذاری شده پویا استفاده شوند. در این صورت، اگر خروجی ساخت را برای نام منبع جستجو کنید، ممکن است پیامی مانند این پیدا کنید:

10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
    used because it format-string matches string pool constant ic_plus_anim_%1$d.

اگر یکی از این رشته ها را می بینید و مطمئن هستید که از رشته برای بارگذاری دینامیک منبع داده شده استفاده نمی شود، می توانید از ویژگی tools:discard برای اطلاع رسانی به سیستم ساخت برای حذف آن استفاده کنید، همانطور که در بخش نحوه انجام آن توضیح داده شد. شخصی سازی کنید که کدام منابع را نگه دارید .