किन संसाधनों को सेव रखना है, यह तय करें

ऐप्लिकेशन ऑप्टिमाइज़ेशन की सुविधा चालू करने पर, ऑप्टिमाइज़र का डिफ़ॉल्ट व्यवहार, R8 के अलग-अलग वर्शन के लिए अलग-अलग होता है.

  • अपडेट किए गए DSL की सुविधा AGP 9.3 और उसके बाद के वर्शन में उपलब्ध है. इसमें ऑप्टिमाइज़ेशन की सुविधा चालू करने पर, इस्तेमाल न किए जाने वाले रिसॉर्स को हटाने की प्रोसेस डिफ़ॉल्ट रूप से चालू रहती है. ध्यान दें कि लेगसी DSL अब भी काम करता है. हालांकि, इसके लिए कोड और रिसॉर्स ऑप्टिमाइज़ेशन की सुविधा अलग-अलग चालू करनी पड़ती है.
  • AGP 9.3 से पहले के वर्शन के लिए, isShrinkResources = true सेटिंग ऑप्टिमाइज़र को उन रिसॉर्स को हटाने का निर्देश देती है जिनका इस्तेमाल नहीं किया गया है. इससे आपके ऐप्लिकेशन का साइज़ कम करने में मदद मिलती है. इस्तेमाल न किए जाने वाले रिसॉर्स को हटाने की प्रोसेस, कोड को छोटा करने की प्रोसेस के साथ मिलकर काम करती है. इसलिए, अगर आपको रिसॉर्स ऑप्टिमाइज़ करने हैं, तो isMinifyEnabled = true भी सेट करें.

AGP 9.3 और उसके बाद के वर्शन (Kotlin)

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 (Kotlin)

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

लेगसी DSL (Groovy)

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

अगर आपको कुछ खास रिसॉर्स रखने या हटाने हैं, तो अपने प्रोजेक्ट के रिसॉर्स में XML keep फ़ाइल बनाएं. उदाहरण के लिए, res/raw/my.package.keep.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" />

यह तय करना कि किन रिसॉर्स को हटाना है, शायद गैर-ज़रूरी लगे. इसकी वजह यह है कि इन्हें सीधे तौर पर मिटाया जा सकता है. हालांकि, बिल्ड वैरिएंट का इस्तेमाल करते समय, रिसॉर्स को हटाना काम का हो सकता है.

खास बिल्ड वैरिएंट टारगेट करना

सिर्फ़ कुछ बिल्ड के वैरिएंट में मौजूद संसाधन हटाने के लिए, अपने सभी संसाधन को सामान्य प्रोजेक्ट डायरेक्ट्री में डालें. इसके बाद, वैरिएंट की संसाधन डायरेक्ट्री में हर बिल्ड के वैरिएंट के लिए, अलग-अलग my.package.build.variant.keep.xml फ़ाइल बनाएं. कीप फ़ाइल में, उन रिसॉर्स को मैन्युअल तरीके से तय करें जिन्हें हटाना है. ऐसा तब करें, जब कोई रिसॉर्स कोड में इस्तेमाल किया जा रहा हो (और इसलिए, उसे श्रिंकर ने न हटाया हो). हालांकि, आपको पता हो कि दिए गए बिल्ड के वैरिएंट के लिए उसका इस्तेमाल नहीं किया जाएगा.

इस्तेमाल न किए गए वैकल्पिक रिसॉर्स हटाना

ऑप्टिमाइज़र सिर्फ़ उन रिसॉर्स को हटाता है जिनका रेफ़रंस आपके ऐप्लिकेशन कोड में नहीं है, इसका मतलब है कि ऑप्टिमाइज़र, अलग-अलग डिवाइस कॉन्फ़िगरेशन के लिए वैकल्पिक रिसॉर्स नहीं हटाएगा.

अपने ऐप्लिकेशन के मॉड्यूल की build.gradle फ़ाइल में, Android Gradle की resConfigs प्रॉपर्टी का इस्तेमाल करके, उन वैकल्पिक रिसॉर्स फ़ाइलों को हटाएं जिनकी आपके ऐप्लिकेशन को ज़रूरत नहीं है.

उदाहरण के लिए, अगर किसी लाइब्रेरी में भाषा के संसाधन शामिल हैं (जैसे, Google Play services), तो आपके ऐप्लिकेशन में उन लाइब्रेरी में मौजूद मैसेज के लिए, अनुवाद की गई सभी भाषा स्ट्रिंग शामिल होंगी. भले ही, आपके ऐप्लिकेशन के बाकी हिस्सों का अनुवाद उन भाषाओं में किया गया हो या नहीं. सिर्फ़ उन भाषाओं को रखने के लिए जिनका आपके ऐप्लिकेशन में आधिकारिक तौर पर इस्तेमाल किया जाता है, resConfigs प्रॉपर्टी का इस्तेमाल करके उन भाषाओं को तय करें. तय नहीं की गई भाषाओं के सभी रिसॉर्स हटा दिए जाते हैं.

यहां दिए गए स्निपेट में, भाषा के संसाधनों को सिर्फ़ अंग्रेज़ी और फ़्रेंच तक सीमित करने का तरीका बताया गया है:

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

या

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

Android ऐप्लिकेशन बंडल (AAB) फ़ॉर्मैट का इस्तेमाल करके ऐप्लिकेशन पब्लिश करने पर, डिफ़ॉल्ट रूप से सिर्फ़ वे भाषाएं डाउनलोड होती हैं जो उपयोगकर्ता के डिवाइस पर कॉन्फ़िगर की गई हैं. ऐसा तब होता है, जब उपयोगकर्ता ऐप्लिकेशन इंस्टॉल करता है. इसी तरह, डाउनलोड में सिर्फ़ वे रिसॉर्स शामिल होते हैं जो डिवाइस की स्क्रीन डेंसिटी से मेल खाते हैं. साथ ही, डिवाइस के ABI से मेल खाने वाली नेटिव लाइब्रेरी भी शामिल होती हैं. ज़्यादा जानकारी के लिए, कॉन्फ़िगरेशन APK के टाइप फिर से चालू या बंद करना लेख पढ़ें.

लेगसी ऐप्लिकेशन (अगस्त 2021 से पहले बनाए गए) को APK के साथ रिलीज़ करने के लिए, स्क्रीन डेंसिटी या ABI रिसॉर्स को पसंद के मुताबिक बनाया जा सकता है. इसके लिए, अलग-अलग डिवाइस कॉन्फ़िगरेशन को टारगेट करने वाले कई APK बनाए जा सकते हैं.

रिसॉर्स मर्ज करते समय होने वाले टकराव से बचना

डिफ़ॉल्ट रूप से, Android Gradle प्लगिन (AGP), एक ही नाम वाले रिसॉर्स को मर्ज करता है. जैसे, अलग-अलग रिसॉर्स फ़ोल्डर में मौजूद एक ही नाम वाले ड्रॉएबल. shrinkResources प्रॉपर्टी से इस व्यवहार को कंट्रोल नहीं किया जा सकता. साथ ही, इसे बंद भी नहीं किया जा सकता. इसकी वजह यह है कि जब कई रिसॉर्स का नाम वही होता है जिसका रेफ़रंस आपके कोड में है, तो गड़बड़ियों से बचने के लिए यह व्यवहार ज़रूरी है.

रिसॉर्स मर्जिंग की प्रोसेस सिर्फ़ तब होती है, जब दो या उससे ज़्यादा फ़ाइलों में एक ही नाम, टाइप, और क्वालीफ़ायर वाला रिसॉर्स मौजूद हो. AGP, डुप्लीकेट में से उस फ़ाइल को चुनता है जिसे वह सबसे बेहतर विकल्प मानता है. यह फ़ाइल चुनने के लिए, नीचे बताए गए प्राथमिकता क्रम का इस्तेमाल करता है. इसके बाद, सिर्फ़ उस रिसॉर्स को AAPT को पास करता है, ताकि उसे फ़ाइनल बिल्ड आर्टफ़ैक्ट में शामिल किया जा सके.

AGP, डुप्लीकेट रिसॉर्स को इन जगहों पर ढूंढता है:

  • मुख्य रिसॉर्स, जो मुख्य सोर्स सेट से जुड़े होते हैं. ये आम तौर पर src/main/res/ में मौजूद होते हैं
  • वैरिएंट ओवरले, जो बिल्ड के तरीके और बिल्ड फ़्लेवर से मिलते हैं
  • लाइब्रेरी प्रोजेक्ट डिपेंडेंसी

AGP, डुप्लीकेट रिसॉर्स को प्राथमिकता के इस क्रम में मर्ज करता है:

डिपेंडेंसी → मुख्य → बिल्ड फ़्लेवर → बिल्ड का तरीका

उदाहरण के लिए, अगर कोई डुप्लीकेट रिसॉर्स आपके मुख्य रिसॉर्स और बिल्ड फ़्लेवर, दोनों में दिखता है, तो Gradle, बिल्ड फ़्लेवर में मौजूद रिसॉर्स को चुनता है.

अगर एक ही source set में एक जैसे रिसॉर्स दिखते हैं, तो Gradle उन्हें मर्ज नहीं कर सकता. साथ ही, रिसॉर्स मर्जिंग से जुड़ी गड़बड़ी दिखाता है. ऐसा तब हो सकता है, जब अपने मॉड्यूल की build.gradle फ़ाइल की sourceSet प्रॉपर्टी में एक से ज़्यादा सोर्स सेट तय किए जाएं. उदाहरण के लिए, अगर src/main/res/ और src/main/res2/, दोनों में एक जैसे रिसॉर्स मौजूद हों.

इस्तेमाल न किए जाने वाले रिसॉर्स को हटाने की प्रोसेस से जुड़ी समस्याएं हल करना

इस्तेमाल न किए जाने वाले रिसॉर्स को हटाने की प्रोसेस के दौरान, बिल्ड विंडो में ऐप्लिकेशन से हटाए गए रिसॉर्स की खास जानकारी दिखती है. Gradle से टेक्स्ट के रूप में पूरी जानकारी पाने के लिए, विंडो के बाईं ओर मौजूद व्यू टॉगल करें पर क्लिक करें. उदाहरण के लिए:

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

Gradle, <module-name>/build/outputs/mapping/release/ में resources.txt नाम की एक डाइग्नोस्टिक फ़ाइल भी बनाता है. यह फ़ाइल, 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 में The root reachable resources are: हेडिंग के तहत, यह रिसॉर्स दिखेगा.

इसका मतलब है कि 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 एट्रिब्यूट का इस्तेमाल करें. इससे, बिल्ड सिस्टम को उस रिसॉर्स को हटाने के बारे में जानकारी मिलेगी.