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

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

  • با DSL به‌روزرسانی‌شده‌ای که از AGP 9.3 و بالاتر در دسترس است، هنگام فعال بودن بهینه‌سازی، کاهش منابع به‌طور پیش‌فرض فعال می‌شود. توجه داشته باشید که DSL قدیمی، که نیاز به فعال بودن مجزای بهینه‌سازی کد و منابع دارد، همچنان پشتیبانی می‌شود.
  • برای نسخه‌های قبل از AGP 9.3 ، تنظیم isShrinkResources = true به بهینه‌ساز دستور می‌دهد منابعی را که استفاده نمی‌شوند حذف کند، که به کاهش اندازه برنامه شما کمک می‌کند. کاهش منابع فقط در کنار کاهش کد کار می‌کند، بنابراین اگر در حال بهینه‌سازی منابع هستید، isMinifyEnabled = true نیز تنظیم کنید.

AGP 9.3+ (کاتلین)

buildTypes {
    release {
        optimization {
            enable = true // Enables code and resource optimizations.
        }
    }
}

AGP 9.3+ (Groovy)

buildTypes {
    release {
        optimization {
            enable = true // Enables code and resource optimizations.
        }
    }
}

DSL قدیمی (کاتلین)

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

DSL قدیمی (Groovy)

buildTypes {
    release {
        minifyEnabled = true
        shrinkResources = true
        ...
    }
}

اگر می‌خواهید منابع خاصی را نگه دارید یا کنار بگذارید، یک فایل keep با فرمت XML در قسمت resource های پروژه خود ایجاد کنید، برای مثال res/raw/my.package.keep.xml . این فایل keep دارای اجزای زیر است:

  • تگ <resources> — شامل تمام عناصر منبع فرزند و ویژگی‌های keep/discard است.
  • ویژگی 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" />

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

انواع ساخت خاص را هدف قرار دهید

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

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

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

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

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

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

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

یا

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

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

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

هنگام ادغام منابع، از تداخل جلوگیری کنید

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

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

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

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

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

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

برای مثال، اگر یک منبع تکراری هم در منابع اصلی شما و هم در یک build flavor ظاهر شود، Gradle منبع موجود در build flavor را انتخاب می‌کند.

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

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

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

: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 ‎ قابل دسترسی است؛ و اگر به سمت بالا جستجو کنید، منبعی را که در زیر عنوان «منابع ریشه قابل دسترسی عبارتند از: در resources.txt » فهرست شده است، خواهید یافت.

این یعنی یک ارجاع کد به add_schedule_fab_icon_anim وجود دارد، یعنی شناسه R.drawable آن در کد قابل دسترسی پیدا شده است.

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

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

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