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

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

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

अगर आपको कुछ खास संसाधनों को सेव या हटाना है, तो अपने प्रोजेक्ट के संसाधनों में एक्सएमएल keep फ़ाइल बनाएं. उदाहरण के लिए, res/raw/my.package.keep.xml. keep फ़ाइल में ये कॉम्पोनेंट होते हैं:

  • <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 ऐप्लिकेशन बंडल (एएबी) फ़ॉर्मैट का इस्तेमाल करके ऐप्लिकेशन पब्लिश करने पर, डिफ़ॉल्ट रूप से उपयोगकर्ता के डिवाइस पर कॉन्फ़िगर की गई भाषाएं ही डाउनलोड होती हैं. इसी तरह, डिवाइस के स्क्रीन डेंसिटी और डिवाइस के एबीआई से मैच करने वाले नेटिव लाइब्रेरी ही डाउनलोड में शामिल होती हैं. ज़्यादा जानकारी के लिए, अलग-अलग तरह के कॉन्फ़िगरेशन APK को फिर से चालू या बंद करना लेख पढ़ें.

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

संसाधनों को मर्ज करते समय, टकराव से बचना

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

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

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

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

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

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

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

अगर एक ही सोर्स सेट में एक जैसे संसाधन दिखते हैं, तो 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 में ऐसे संसाधन जो रूट से ऐक्सेस किए जा सकते हैं: हेडिंग में संसाधन दिखेगा.

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