अपने ऐप्लिकेशन को जितना हो सके उतना छोटा और तेज़ बनाने के लिए, आपको isMinifyEnabled = true
की मदद से रिलीज़ बिल्ड को ऑप्टिमाइज़ और छोटा करना चाहिए.
ऐसा करने पर, छोटा करने की सुविधा चालू हो जाती है. इससे, इस्तेमाल न किए गए कोड को हटाया जाता है. साथ ही, कोड को उलझाने की सुविधा चालू हो जाती है. इससे, आपके ऐप्लिकेशन की क्लास और सदस्यों के नाम छोटे हो जाते हैं. इसके अलावा, ऑप्टिमाइज़ेशन की सुविधा चालू हो जाती है. इससे, कोड को ऑप्टिमाइज़ करने की बेहतर रणनीतियां लागू होती हैं, ताकि आपके ऐप्लिकेशन का साइज़ और परफ़ॉर्मेंस बेहतर हो सके. इस पेज पर बताया गया है कि R8 आपके प्रोजेक्ट के लिए, कंपाइल के समय ये टास्क कैसे करता है और उन्हें पसंद के मुताबिक कैसे बनाया जा सकता है.
Android Gradle प्लग इन 3.4.0 या इसके बाद के वर्शन का इस्तेमाल करके प्रोजेक्ट बनाने पर, यह प्लगिन कंपाइल टाइम कोड ऑप्टिमाइज़ेशन के लिए ProGuard का इस्तेमाल नहीं करता है. इसके बजाय, प्लगिन R8 कंपाइलर के साथ काम करके, कंपाइल-टाइम के इन टास्क को हैंडल करता है:
- कोड छोटा करना (या ट्री-शैकिंग): यह आपके ऐप्लिकेशन और उसकी लाइब्रेरी डिपेंडेंसी से, इस्तेमाल न होने वाली क्लास, फ़ील्ड, मेथड, और एट्रिब्यूट का पता लगाता है और उन्हें सुरक्षित तरीके से हटा देता है. इससे, 64 हज़ार रेफ़रंस की सीमा को पूरा करने में मदद मिलती है. उदाहरण के लिए, अगर लाइब्रेरी डिपेंडेंसी के सिर्फ़ कुछ एपीआई इस्तेमाल किए जाते हैं, तो छोटा करने की प्रोसेस से उस लाइब्रेरी कोड की पहचान की जा सकती है जिसका इस्तेमाल आपका ऐप्लिकेशन नहीं कर रहा है. साथ ही, वह आपके ऐप्लिकेशन से सिर्फ़ उस कोड को हटा सकता है. ज़्यादा जानने के लिए, कोड छोटा करने का तरीका बताने वाले सेक्शन पर जाएं.
- संसाधन का छोटा करना: आपके पैकेज किए गए ऐप्लिकेशन से, इस्तेमाल न होने वाले रिसॉर्स हटा देता है. इनमें, आपके ऐप्लिकेशन की लाइब्रेरी डिपेंडेंसी में इस्तेमाल न किए जाने वाले संसाधन भी शामिल हैं. यह सुविधा, कोड छोटा करने की सुविधा के साथ काम करती है. इसकी मदद से, इस्तेमाल न किए गए कोड को हटाने के बाद, ऐसे सभी संसाधनों को भी सुरक्षित तरीके से हटाया जा सकता है जिनका रेफ़रंस अब नहीं दिया गया है. ज़्यादा जानने के लिए, अपने संसाधनों को छोटा करने के तरीके के बारे में बताने वाले सेक्शन पर जाएं.
- ऑप्टिमाइज़ेशन: रनटाइम की परफ़ॉर्मेंस को बेहतर बनाने और ऐप्लिकेशन की DEX फ़ाइलों के साइज़ को और कम करने के लिए, आपके कोड की जांच करता है और उसे फिर से लिखता है. इससे कोड की रनटाइम परफ़ॉर्मेंस 30% तक बेहतर होती है. साथ ही, स्टार्टअप और फ़्रेम टाइमिंग में काफ़ी सुधार होता है. उदाहरण के लिए, अगर R8 को पता चलता है कि दिए गए if/else स्टेटमेंट के लिए
else {}
ब्रांच कभी नहीं ली गई, तो R8else {}
ब्रांच का कोड हटा देता है. ज़्यादा जानने के लिए, कोड ऑप्टिमाइज़ेशन के बारे में बताने वाले सेक्शन पर जाएं. - डेटा को छिपाना (या आइडेंटिफ़ायर को छोटा करना): इससे क्लास और सदस्यों के नाम छोटे हो जाते हैं. इस वजह से, DEX फ़ाइल का साइज़ कम हो जाता है. ज़्यादा जानने के लिए, अपने कोड को छिपाने के तरीके के बारे में बताने वाले सेक्शन पर जाएं.
अपने ऐप्लिकेशन का रिलीज़ वर्शन बनाते समय, R8 को कॉन्फ़िगर किया जा सकता है, ताकि वह आपके लिए ऊपर बताए गए, कंपाइल के समय होने वाले टास्क को पूरा कर सके. ProGuard की नियम फ़ाइलों की मदद से, कुछ टास्क बंद किए जा सकते हैं या R8 के काम करने के तरीके में बदलाव किया जा सकता है. असल में, R8, ProGuard की सभी मौजूदा नियम फ़ाइलों के साथ काम करता है. इसलिए, R8 का इस्तेमाल करने के लिए Android Gradle प्लग इन को अपडेट करने पर, आपको अपने मौजूदा नियमों में बदलाव करने की ज़रूरत नहीं पड़ेगी.
कोड का साइज़ कम करने, उसे अस्पष्ट बनाने, और ऑप्टिमाइज़ करने की सुविधाएं चालू करना
Android Studio 3.4 या Android Gradle प्लग इन 3.4.0 और उसके बाद के वर्शन का इस्तेमाल करने पर, R8 डिफ़ॉल्ट कंपाइलर होता है. यह आपके प्रोजेक्ट के Java बाइटकोड को DEX फ़ॉर्मैट में बदलता है, जो Android प्लैटफ़ॉर्म पर चलता है. हालांकि, जब 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 करता है.
सोर्स | जगह की जानकारी | ब्यौरा |
Android Studio | <module-dir>/proguard-rules.pro
|
Android Studio का इस्तेमाल करके नया मॉड्यूल बनाने पर, IDE उस मॉड्यूल की रूट डायरेक्ट्री में एक
proguard-rules.pro फ़ाइल बनाता है.
डिफ़ॉल्ट रूप से, यह फ़ाइल कोई नियम लागू नहीं करती. इसलिए, यहां अपने ProGuard नियम शामिल करें. जैसे, पसंद के मुताबिक बनाए गए, डेटा को सेव रखने के नियम. |
Android Gradle प्लग इन | कंपाइल करने के समय, Android Gradle प्लग इन से जनरेट किया जाता है. | Android Gradle प्लग इन,
proguard-android-optimize.txt जनरेट करता है. इसमें ऐसे नियम शामिल होते हैं जो
ज़्यादातर Android प्रोजेक्ट के लिए काम के होते हैं. साथ ही, यह
@Keep*
एनोटेशन चालू करता है.
Android Studio का इस्तेमाल करके नया मॉड्यूल बनाते समय, डिफ़ॉल्ट रूप से मॉड्यूल-लेवल वाली बिल्ड स्क्रिप्ट, रिलीज़ बिल्ड में आपके लिए यह नियम फ़ाइल शामिल करती है.
ध्यान दें: Android Gradle प्लग इन में, पहले से तय ProGuard के अतिरिक्त नियम वाली फ़ाइलें शामिल होती हैं. हालांकि, हमारा सुझाव है कि आप
|
लाइब्रेरी डिपेंडेंसी |
AAR लाइब्रेरी में:
JAR लाइब्रेरी में: इन जगहों के अलावा, 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) के साथ-साथ, श्रिंकर के खास वर्शन को टारगेट करते हैं. इससे लाइब्रेरी डेवलपर अपने नियमों को ऐसे प्रोजेक्ट में बेहतर तरीके से काम करने के लिए तैयार कर पाते हैं जो श्रिंकर वर्शन का इस्तेमाल करते हैं. साथ ही, श्रिंकर वर्शन के पुराने वर्शन वाले प्रोजेक्ट में मौजूदा नियमों का इस्तेमाल जारी रखा जा सकता है.
टारगेट किए गए, छोटा करने के नियम तय करने के लिए, लाइब्रेरी डेवलपर को उन्हें एएआर या जेएआर लाइब्रेरी में खास जगहों पर शामिल करना होगा, जैसा कि नीचे बताया गया है.
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>
इसका मतलब है कि टारगेट किए गए सिंक किए गए नियम, JAR की META-INF/com.android.tools
डायरेक्ट्री में या AAR की classes.jar
में मौजूद META-INF/com.android.tools
डायरेक्ट्री में सेव किए जाते हैं.
उस डायरेक्ट्री में, 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.2.0 तक के वर्शन में किया जाएगा. हालांकि, 8.2.0 वर्शन में इन नियमों का इस्तेमाल नहीं किया जाएगा.
इस जानकारी के आधार पर, Android Gradle प्लग-इन 3.6 या इसके बाद के वर्शन, मैच होने वाली R8 डायरेक्ट्री से नियम चुनेंगे. अगर लाइब्रेरी में, टारगेट किए गए श्रिंक नियमों की जानकारी नहीं है, तो Android Gradle प्लग इन, लेगसी जगहों से नियम चुनेगा (AAR के लिए proguard.txt
या JAR के लिए META-INF/proguard/<ProGuard-rules-file>
).
लाइब्रेरी डेवलपर अपनी लाइब्रेरी में, टारगेट किए गए छोटे किए गए नियम या ProGuard के लेगसी नियमों में से किसी एक को शामिल कर सकते हैं. अगर उन्हें 3.6 से पहले के Android Gradle प्लग इन या अन्य टूल के साथ काम करना है, तो वे दोनों तरह के नियम शामिल कर सकते हैं.
अन्य कॉन्फ़िगरेशन शामिल करें
Android Studio का इस्तेमाल करके नया प्रोजेक्ट या मॉड्यूल बनाने पर, IDE आपके लिए एक <module-dir>/proguard-rules.pro
फ़ाइल बनाता है. इसमें अपने नियम शामिल किए जा सकते हैं. अपने मॉड्यूल की बिल्ड स्क्रिप्ट की proguardFiles
प्रॉपर्टी में जोड़कर, अन्य फ़ाइलों से अन्य नियमों को भी शामिल किया जा सकता है.
उदाहरण के लिए, हर बिल्ड वैरिएंट के लिए खास नियम जोड़े जा सकते हैं. इसके लिए, उससे जुड़े productFlavor
ब्लॉक में एक और proguardFiles
प्रॉपर्टी जोड़ें. यहां दी गई Gradle फ़ाइल, flavor2-rules.pro
को flavor2
प्रॉडक्ट के फ़्लेवर में जोड़ती है.
अब flavor2
, ProGuard के तीनों नियमों का इस्तेमाल करता है, क्योंकि release
के ब्लॉक में मौजूद नियम भी लागू होते हैं.
इसके अलावा, testProguardFiles
प्रॉपर्टी जोड़ी जा सकती है. इससे, सिर्फ़ टेस्ट APK में शामिल ProGuard फ़ाइलों की सूची दिखती है:
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 सबसे पहले आपके ऐप्लिकेशन के कोड के सभी एंट्री पॉइंट तय करता है. ऐसा, कॉन्फ़िगरेशन फ़ाइलों के सेट के आधार पर होता है. इन एंट्री पॉइंट में वे सभी क्लास शामिल होती हैं जिनका इस्तेमाल Android प्लैटफ़ॉर्म, आपके ऐप्लिकेशन की गतिविधियों या सेवाओं को खोलने के लिए कर सकता है. R8, हर एंट्री पॉइंट से शुरू करके आपके ऐप्लिकेशन के कोड की जांच करता है. इससे, उन सभी तरीकों, सदस्य वैरिएबल, और अन्य क्लास का ग्राफ़ बनाया जाता है जिन्हें आपका ऐप्लिकेशन रनटाइम के दौरान ऐक्सेस कर सकता है. उस ग्राफ़ से कनेक्ट नहीं होने वाले कोड को ऐसा कोड माना जाता है जिसे ऐक्सेस नहीं किया जा सकता. साथ ही, उसे ऐप्लिकेशन से हटाया जा सकता है.
पहली इमेज में, रनटाइम लाइब्रेरी डिपेंडेंसी वाला ऐप्लिकेशन दिखाया गया है. ऐप्लिकेशन के कोड की जांच करते समय, R8 यह तय करता है कि foo()
, faz()
, और bar()
तरीकों को MainActivity.class
एंट्री पॉइंट से ऐक्सेस किया जा सकता है. हालांकि, रनटाइम के दौरान आपके ऐप्लिकेशन में क्लास OkayApi.class
या उसके तरीके baz()
का कभी इस्तेमाल नहीं किया जाता. साथ ही, R8 आपके ऐप्लिकेशन को छोटा करते समय उस कोड को हटा देता है.
पहली इमेज. कंपाइल करने के समय, R8 आपके प्रोजेक्ट के 'रखें' नियमों के आधार पर एक ग्राफ़ बनाता है. इससे, ऐक्सेस न किए जा सकने वाले कोड का पता चलता है.
R8, प्रोजेक्ट की R8 कॉन्फ़िगरेशन फ़ाइलों में मौजूद -keep
नियमों के ज़रिए एंट्री पॉइंट तय करता है. इसका मतलब है कि 'रखें' नियमों में उन क्लास के बारे में बताया जाता है जिन्हें R8 को आपके ऐप्लिकेशन को छोटा करते समय नहीं हटाना चाहिए. R8, उन क्लास को आपके ऐप्लिकेशन के संभावित एंट्री पॉइंट के तौर पर इस्तेमाल करता है. Android Gradle प्लग इन और AAPT2, 'रखें' नियम अपने-आप जनरेट करते हैं. ये नियम, आपके ज़्यादातर ऐप्लिकेशन प्रोजेक्ट के लिए ज़रूरी होते हैं. जैसे, आपके ऐप्लिकेशन की गतिविधियां, व्यू, और सेवाएं. हालांकि, अगर आपको इस डिफ़ॉल्ट व्यवहार को, डेटा को सेव रखने के अन्य नियमों के साथ पसंद के मुताबिक बनाना है, तो किस कोड को सेव रखना है, यह तय करने के तरीके के बारे में बताने वाला सेक्शन पढ़ें.
अगर आपको सिर्फ़ अपने ऐप्लिकेशन के रिसॉर्स का साइज़ कम करना है, तो अपने रिसॉर्स को छोटा करने के तरीके के बारे में बताने वाले सेक्शन पर जाएं.
ध्यान दें कि अगर किसी लाइब्रेरी प्रोजेक्ट को छोटा किया जाता है, तो उस लाइब्रेरी पर निर्भर ऐप्लिकेशन में, छोटी की गई लाइब्रेरी क्लास शामिल होती हैं. अगर लाइब्रेरी APK में क्लास मौजूद नहीं हैं, तो आपको लाइब्रेरी में कॉन्टेंट सेव रखने के नियमों में बदलाव करना पड़ सकता है. अगर किसी लाइब्रेरी को AAR फ़ॉर्मैट में बनाया और पब्लिश किया जा रहा है, तो AAR फ़ाइल में उन लोकल JAR फ़ाइलों को छोटा नहीं किया जाता जिन पर आपकी लाइब्रेरी निर्भर करती है.
यह तय करना कि कौनसा कोड रखना है
ज़्यादातर मामलों में, R8 के लिए सिर्फ़ इस्तेमाल न किए गए कोड को हटाने के लिए, ProGuard की डिफ़ॉल्ट नियम फ़ाइल (proguard-android-optimize.txt
) काफ़ी होती है. हालांकि, कुछ मामलों में R8 का सही तरीके से विश्लेषण करना मुश्किल होता है. साथ ही, ऐसा हो सकता है कि वह आपके ऐप्लिकेशन के लिए ज़रूरी कोड हटा दे. कोड को गलती से कब हटाया जा सकता है, इसके कुछ उदाहरण यहां दिए गए हैं:
- जब आपका ऐप्लिकेशन, Java नेटिव इंटरफ़ेस (जेएनआई) से किसी तरीके को कॉल करता है
- जब आपका ऐप्लिकेशन रनटाइम के दौरान कोड देखता है (जैसे कि रिफ़्लेक्शन के साथ)
अपने ऐप्लिकेशन की जांच करने से, गलत तरीके से हटाए गए कोड की वजह से हुई गड़बड़ियों का पता चल जाना चाहिए. हालांकि, हटाए गए कोड की रिपोर्ट जनरेट करके यह भी पता लगाया जा सकता है कि कौनसा कोड हटाया गया था.
गड़बड़ियों को ठीक करने और R8 को कुछ कोड को सेव करने के लिए, ProGuard के नियमों वाली फ़ाइल में एक -keep
लाइन जोड़ें. उदाहरण के लिए:
-keep public class MyClass
इसके अलावा, जिस कोड को बनाए रखना है उसमें @Keep
एनोटेशन जोड़ा जा सकता है. किसी क्लास में @Keep
जोड़ने से, पूरी क्लास पहले जैसी ही रहती है.
इसे किसी तरीके या फ़ील्ड में जोड़ने पर, तरीका/फ़ील्ड (और उसका नाम) के साथ-साथ क्लास का नाम भी बना रहेगा. ध्यान दें कि यह एनोटेशन सिर्फ़ तब उपलब्ध होता है, जब AndroidX एनोटेशन लाइब्रेरी का इस्तेमाल किया जा रहा हो. साथ ही, जब Android Gradle प्लग इन के साथ पैकेज की गई ProGuard नियम फ़ाइल को शामिल किया गया हो. इस बारे में ज़्यादा जानने के लिए, ऐप्लिकेशन को छोटा करने की सुविधा चालू करने का तरीका बताने वाले सेक्शन पर जाएं.
-keep
विकल्प का इस्तेमाल करते समय, आपको कई बातों का ध्यान रखना चाहिए. अपनी नियम फ़ाइल को पसंद के मुताबिक बनाने के बारे में ज़्यादा जानने के लिए, ProGuard मैन्युअल पढ़ें.
समस्या हल करना सेक्शन में, कोड हटने पर होने वाली अन्य सामान्य समस्याओं के बारे में बताया गया है.
नेटिव लाइब्रेरी हटाना
डिफ़ॉल्ट रूप से, आपके ऐप्लिकेशन के रिलीज़ बिल्ड में नेटिव कोड लाइब्रेरी हटा दी जाती हैं. इसमें, आपके ऐप्लिकेशन में इस्तेमाल की गई किसी भी नेटिव लाइब्रेरी में मौजूद सिंबल टेबल और डीबग करने से जुड़ी जानकारी हटा दी जाती है. नेटिव कोड लाइब्रेरी हटाने से, ऐप्लिकेशन के साइज़ में काफ़ी कमी आती है. हालांकि, जानकारी (जैसे, क्लास और फ़ंक्शन के नाम) मौजूद न होने की वजह से, Google Play Console पर क्रैश का पता लगाना मुमकिन नहीं होता.
नेटिव क्रैश के लिए सहायता
Google Play Console, Android की ज़रूरी जानकारी में नेटिव क्रैश की रिपोर्ट दिखाता है. कुछ ही चरणों में, अपने ऐप्लिकेशन के लिए नेटिव डीबग सिंबल फ़ाइल जनरेट और अपलोड की जा सकती है. यह फ़ाइल, Android Vitals में सिम्बॉलाइज़ किए गए नेटिव क्रैश स्टैक ट्रेस (इसमें क्लास और फ़ंक्शन के नाम शामिल होते हैं) को चालू करती है. इससे, आपको प्रोडक्शन में अपने ऐप्लिकेशन को डीबग करने में मदद मिलती है. आपके प्रोजेक्ट में इस्तेमाल किए गए Android Gradle प्लग इन के वर्शन और प्रोजेक्ट के बिल्ड आउटपुट के आधार पर, ये चरण अलग-अलग हो सकते हैं.
Android Gradle प्लग इन का 4.1 या इसके बाद का वर्शन
अगर आपके प्रोजेक्ट में Android ऐप्लिकेशन बंडल बनाया जाता है, तो इसमें नेटिव डीबग सिंबल वाली फ़ाइल को अपने-आप शामिल किया जा सकता है. इस फ़ाइल को रिलीज़ के बिल्ड में शामिल करने के लिए, अपने ऐप्लिकेशन की build.gradle.kts
फ़ाइल में यह जोड़ें:
android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }
इनमें से डीबग सिंबल का लेवल चुनें:
- Play Console में सिम्बॉलिकेट किए गए स्टैक ट्रेस में फ़ंक्शन के नाम पाने के लिए,
SYMBOL_TABLE
का इस्तेमाल करें. इस लेवल पर टूंबस्टोन इस्तेमाल किए जा सकते हैं. - Play Console के सिंबल वाले स्टैक ट्रेस में फ़ंक्शन के नाम, फ़ाइलें, और लाइन नंबर पाने के लिए,
FULL
का इस्तेमाल करें.
अगर आपके प्रोजेक्ट में APK बनाया जाता है, तो नेटिव डीबग सिंबल वाली फ़ाइल को अलग से जनरेट करने के लिए, पहले दिखाई गई build.gradle.kts
बिल्ड सेटिंग का इस्तेमाल करें. Google Play Console में, मैन्युअल तरीके से नेटिव डीबग सिंबल वाली फ़ाइल अपलोड करें. बिल्ड प्रोसेस का हिस्सा होने के तौर पर, '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
इस डायरेक्ट्री के कॉन्टेंट की ज़िप फ़ाइल बनाएं:
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
Google Play Console में, मैन्युअल तरीके से
symbols.zip
फ़ाइल अपलोड करें.
अपने संसाधनों को छोटा करना
संसाधन छोटा करने की सुविधा, सिर्फ़ कोड छोटा करने की सुविधा के साथ काम करती है. कोड छोटा करने वाला टूल, इस्तेमाल न किए गए सभी कोड को हटाने के बाद, संसाधन छोटा करने वाला टूल यह पता लगा सकता है कि ऐप्लिकेशन अब भी किन संसाधनों का इस्तेमाल करता है. यह खास तौर पर तब ज़रूरी होता है, जब आपने कोड लाइब्रेरी जोड़ी हो और उनमें रिसॉर्स शामिल हों. आपको लाइब्रेरी का इस्तेमाल न किया गया कोड हटाना होगा, ताकि लाइब्रेरी के रिसॉर्स का रेफ़रंस न रहे. इससे रिसॉर्स को छोटा करने वाला टूल, रिसॉर्स को हटा सकता है.
संसाधन को छोटा करने की सुविधा चालू करने के लिए, अपनी बिल्ड स्क्रिप्ट में 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
फ़ाइल में बदलाव करना पड़ सकता है, ताकि डाइनैमिक तौर पर बनाई गई या इस्तेमाल की गई क्लास या तरीकों को रखा जा सके.
यह तय करना कि कौनसे रिसॉर्स सेव रखने हैं
अगर आपको कुछ खास संसाधनों को सेव रखना या खारिज करना है, तो अपने प्रोजेक्ट में <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
फ़ाइल के लिए कोई यूनीक नाम इस्तेमाल किया हो. जब अलग-अलग लाइब्रेरी को एक साथ जोड़ा जाता है, तब 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/
के अलग-अलग रिसॉर्स को भी देखता है. साथ ही, file:///android_res/drawable//ic_plus_anim_016.png
जैसे फ़ॉर्मैट में रिसॉर्स यूआरएल खोजता है. अगर इस तरह की या ऐसी अन्य स्ट्रिंग मिलती हैं जिनका इस्तेमाल इस तरह के यूआरएल बनाने के लिए किया जा सकता है, तो उन्हें नहीं हटाया जाता.
ये सुरक्षित तरीके से छोटा करने वाले मोड के उदाहरण हैं. यह मोड डिफ़ॉल्ट रूप से चालू होता है.
हालांकि, "पहले से सुरक्षित रहें" वाले इस तरीके को बंद किया जा सकता है. साथ ही, यह भी तय किया जा सकता है कि रिसोर्स को छोटा करने वाला टूल सिर्फ़ उन रिसोर्स को सेव रखे जिनका इस्तेमाल किया जा रहा है. ऐसा करने के लिए, keep.xml
फ़ाइल में shrinkMode
को strict
पर सेट करें. इसके लिए, यह तरीका अपनाएं:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />
अगर आपने स्ट्रिक्ट स्ट्रिंग मोड चालू किया है और आपका कोड, डाइनैमिक तौर पर जनरेट हुई स्ट्रिंग वाले संसाधनों का भी रेफ़रंस देता है, जैसा कि ऊपर दिखाया गया है, तो आपको tools:keep
एट्रिब्यूट का इस्तेमाल करके, उन संसाधनों को मैन्युअल तौर पर रखना होगा.
इस्तेमाल नहीं किए गए वैकल्पिक रिसॉर्स हटाना
Gradle रिसॉर्स श्रिन्कर सिर्फ़ उन संसाधनों को हटाता है जिनका आपके ऐप्लिकेशन कोड में रेफ़रंस नहीं दिया गया है. इसका मतलब है कि यह अलग-अलग डिवाइस कॉन्फ़िगरेशन के लिए
वैकल्पिक संसाधनों को नहीं हटाएगा. ज़रूरत पड़ने पर, Android Gradle प्लग इन की resConfigs
प्रॉपर्टी का इस्तेमाल करके, वैकल्पिक संसाधन फ़ाइलों को हटाया जा सकता है. ये फ़ाइलें आपके ऐप्लिकेशन के लिए ज़रूरी नहीं हैं.
उदाहरण के लिए, अगर किसी ऐसी लाइब्रेरी का इस्तेमाल किया जा रहा है जिसमें भाषा के संसाधन शामिल हैं, जैसे कि AppCompat या Google Play Services, तो आपके ऐप्लिकेशन में उन लाइब्रेरी के मैसेज के लिए, अनुवाद की गई सभी भाषा की स्ट्रिंग शामिल होती हैं. भले ही, आपके ऐप्लिकेशन के बाकी हिस्से का अनुवाद उन भाषाओं में किया गया हो या नहीं. अगर आपको सिर्फ़ वे भाषाएं इस्तेमाल करनी हैं जो आपके ऐप्लिकेशन में आधिकारिक तौर पर काम करती हैं, तो resConfig
प्रॉपर्टी का इस्तेमाल करके उन भाषाओं की जानकारी दें. जिन भाषाओं के लिए संसाधन नहीं दिए गए हैं उन्हें हटा दिया जाता है.
नीचे दिए गए स्निपेट में, भाषा के संसाधनों को सिर्फ़ अंग्रेज़ी और फ़्रेंच तक सीमित करने का तरीका बताया गया है:
android { defaultConfig { ... resourceConfigurations.addAll(listOf("en", "fr")) } }
android { defaultConfig { ... resConfigs "en", "fr" } }
Android ऐप्लिकेशन बंडल फ़ॉर्मैट का इस्तेमाल करके ऐप्लिकेशन रिलीज़ करते समय, डिफ़ॉल्ट रूप से ऐप्लिकेशन इंस्टॉल करते समय सिर्फ़ उपयोगकर्ता के डिवाइस पर कॉन्फ़िगर की गई भाषाएं डाउनलोड की जाती हैं. इसी तरह, डिवाइस की स्क्रीन डेंसिटी से मैच करने वाले सिर्फ़ संसाधन और डिवाइस के एबीआई से मैच करने वाली नेटिव लाइब्रेरी ही डाउनलोड की जाती हैं. ज़्यादा जानकारी के लिए, Android ऐप्लिकेशन बंडल कॉन्फ़िगरेशन देखें.
APK (अगस्त 2021 से पहले बनाए गए) के साथ रिलीज़ होने वाले लेगसी ऐप्लिकेशन के लिए, कई APK बनाकर यह तय किया जा सकता है कि किन स्क्रीन सघनता या एबीआई संसाधनों को आपके APK में शामिल करना है और हर APK एक अलग डिवाइस कॉन्फ़िगरेशन को टारगेट करता है.
डुप्लीकेट संसाधनों को मर्ज करना
डिफ़ॉल्ट रूप से, Gradle, एक जैसे नाम वाले संसाधनों को भी मर्ज करता है. जैसे,
एक ही नाम वाली ड्रॉ करने लायक फ़ाइलें, जो अलग-अलग रिसॉर्स फ़ोल्डर में मौजूद हो सकती हैं. इस व्यवहार को shrinkResources
प्रॉपर्टी से कंट्रोल नहीं किया जाता और इसे बंद नहीं किया जा सकता. ऐसा इसलिए ज़रूरी है, ताकि जब आपके कोड में खोजे जा रहे नाम से कई संसाधन मैच करते हों, तो गड़बड़ियों से बचा जा सके.
रिसॉर्स मर्ज करने की प्रोसेस सिर्फ़ तब होती है, जब दो या उससे ज़्यादा फ़ाइलों में एक ही रिसॉर्स का नाम, टाइप, और क्वालीफ़ायर हो. Gradle वह फ़ाइल चुनता है जो उसे डुप्लीकेट (नीचे बताए गए प्राथमिकता क्रम के आधार पर) में सबसे अच्छा मानता है. साथ ही, वह फ़ाइनल आर्टफ़ैक्ट में डिस्ट्रिब्यूशन के लिए सिर्फ़ उस एक संसाधन को AAPT में पास करता है.
Gradle, इन जगहों पर डुप्लीकेट संसाधनों की खोज करता है:
- मुख्य सोर्स सेट से जुड़े मुख्य संसाधन, आम तौर पर
src/main/res/
में मौजूद होते हैं. - बिल्ड टाइप और बिल्ड फ़्लेवर से मिले वैरिएंट ओवरले.
- लाइब्रेरी प्रोजेक्ट की डिपेंडेंसी.
Gradle, डुप्लीकेट संसाधनों को नीचे दिए गए कैस्केडिंग प्राथमिकता क्रम में मर्ज करता है:
डिपेंडेंसी → मुख्य → बिल्ड फ़्लेवर → बिल्ड टाइप
उदाहरण के लिए, अगर आपके मुख्य संसाधनों और किसी बिल्ड फ़्लेवर, दोनों में डुप्लीकेट संसाधन दिखता है, तो Gradle, बिल्ड फ़्लेवर में मौजूद संसाधन को चुनता है.
अगर एक ही सोर्स सेट में एक जैसे रिसॉर्स दिखते हैं, तो Gradle उन्हें मर्ज नहीं कर सकता और रिसॉर्स मर्ज करने से जुड़ी गड़बड़ी का मैसेज दिखाता है. ऐसा तब हो सकता है, जब आपने अपनी build.gradle.kts
फ़ाइल की sourceSet
प्रॉपर्टी में एक से ज़्यादा सोर्स सेट तय किए हों. उदाहरण के लिए, अगर 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 फ़ाइलों वाले ऐप्लिकेशन के साइज़ में काफ़ी कमी देखी जा सकती है. ये फ़ाइलें कई क्लास, मेथड, और फ़ील्ड को इंडेक्स करती हैं. हालांकि, कोड को धुंधला करने की प्रोसेस में, आपके कोड के अलग-अलग हिस्सों का नाम बदल दिया जाता है. इसलिए, कुछ टास्क के लिए, आपको अतिरिक्त टूल की ज़रूरत पड़ सकती है. जैसे, स्टैक ट्रेस की जांच करना. कोड को बदलने के बाद, स्टैक ट्रेस को समझने के लिए, बदले गए स्टैक ट्रेस को डिकोड करने का तरीका बताने वाला सेक्शन पढ़ें.
इसके अलावा, अगर आपका कोड आपके ऐप्लिकेशन के तरीकों और कक्षाओं के लिए, अनुमानित नाम रखने पर निर्भर करता है, तो आपको उन हस्ताक्षरों को एंट्री पॉइंट के तौर पर इस्तेमाल करना चाहिए. साथ ही, उनके लिए नियम तय करने चाहिए. इस बारे में कोड को पसंद के मुताबिक बनाने के लिए सेक्शन में बताया गया है. 'रखें' नियम, R8 को यह बताते हैं कि वह कोड को आपके ऐप्लिकेशन के फ़ाइनल DEX में न सिर्फ़ रखें, बल्कि उसका मूल नाम भी बनाए रखें.
उलझाने वाले स्टैक ट्रेस को डिकोड करना
R8 आपके कोड को अस्पष्ट करने के बाद, स्टैक ट्रेस को समझना मुश्किल हो जाता है. ऐसा इसलिए होता है, क्योंकि हो सकता है कि क्लास और तरीकों के नाम बदल दिए गए हों. ओरिजनल स्टैक ट्रेस पाने के लिए, आपको स्टैक ट्रेस को फिर से ट्रैक करना होगा.
कोड ऑप्टिमाइज़ेशन
आपके ऐप्लिकेशन को और भी बेहतर तरीके से ऑप्टिमाइज़ करने के लिए, R8 आपके कोड की बारीकी से जांच करता है. इससे, इस्तेमाल न किए गए ज़्यादा कोड को हटाया जा सकता है. इसके अलावा, जहां भी हो सके वहां आपके कोड को फिर से लिखकर, उसे कम शब्दों में बनाया जा सकता है. इस तरह के ऑप्टिमाइज़ेशन के कुछ उदाहरण यहां दिए गए हैं:
- अगर आपका कोड किसी दिए गए if/else स्टेटमेंट के लिए कभी भी
else {}
शाखा को नहीं लेता है, तो हो सकता है कि R8,else {}
शाखा के लिए कोड हटा दे. - अगर आपका कोड किसी मेथड को सिर्फ़ कुछ जगहों पर कॉल करता है, तो हो सकता है कि R8 उस मेथड को हटा दे और उसे कॉल करने वाली कुछ जगहों पर इनलाइन कर दे.
- अगर R8 को पता चलता है कि किसी क्लास में सिर्फ़ एक यूनीक सब-क्लास है और क्लास खुद इंस्टैंशिएट नहीं की गई है (उदाहरण के लिए, ऐब्सट्रैक्ट बेस क्लास, जिसका इस्तेमाल सिर्फ़ एक कंक्रीट लागू करने वाली क्लास में किया जाता है), तो R8 दोनों क्लास को जोड़कर ऐप्लिकेशन से क्लास हटा सकता है.
- ज़्यादा जानने के लिए, जैक व्हार्टन की लिखी R8 ऑप्टिमाइज़ेशन ब्लॉग पोस्ट पढ़ें.
R8 में, अलग-अलग ऑप्टिमाइज़ेशन को बंद या चालू करने या किसी ऑप्टिमाइज़ेशन के व्यवहार में बदलाव करने की अनुमति नहीं है. असल में, R8 उन सभी ProGuard नियमों को अनदेखा करता है जो डिफ़ॉल्ट ऑप्टिमाइज़ेशन में बदलाव करने की कोशिश करते हैं. जैसे, -optimizations
और
-optimizationpasses
. यह पाबंदी ज़रूरी है, क्योंकि R8 में लगातार सुधार हो रहा है. ऑप्टिमाइज़ेशन के लिए स्टैंडर्ड व्यवहार को बनाए रखने से, Android Studio की टीम को आने वाली किसी भी समस्या को आसानी से हल करने में मदद मिलती है.
ध्यान दें कि ऑप्टिमाइज़ेशन चालू करने से, आपके ऐप्लिकेशन के स्टैक ट्रेस बदल जाएंगे. उदाहरण के लिए, इनलाइन करने से स्टैक फ़्रेम हटा दिए जाएंगे. ओरिजनल स्टैक ट्रेस पाने का तरीका जानने के लिए, फिर से ट्रैक करने वाला सेक्शन देखें.
रनटाइम परफ़ॉर्मेंस पर असर
अगर छोटा करने, छिपाने, और ऑप्टिमाइज़ करने की सुविधाएं चालू हैं, तो 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 से क्लास को हटा देता है. इसका मतलब है कि अगर आपको क्लास और उसके स्टैटिक शुरू करने वाले को बनाए रखना है, तो आपको ऐसा करने के लिए अपनी नियम फ़ाइल में 'रखें' नियम शामिल करना होगा.
अगर R8 के "फ़ुल मोड" का इस्तेमाल करते समय कोई समस्या आती है, तो समस्या का हल पाने के लिए R8 के बारे में अक्सर पूछे जाने वाले सवालों का पेज देखें. अगर आपको समस्या हल करने में समस्या आ रही है, तो कृपया गड़बड़ी की शिकायत करें.
स्टैक ट्रेस को फिर से ट्रैक करना
R8 की मदद से प्रोसेस किए गए कोड में कई तरह के बदलाव किए जाते हैं. इनकी वजह से, स्टैक ट्रेस को समझना मुश्किल हो सकता है. ऐसा इसलिए, क्योंकि स्टैक ट्रेस, सोर्स कोड से पूरी तरह मेल नहीं खाते. ऐसा हो सकता है कि डीबग करने की जानकारी न रखते समय, लाइन नंबर में किए गए बदलाव हों. ऐसा इनलाइनिंग और आउटलाइनिंग जैसे ऑप्टिमाइज़ेशन की वजह से हो सकता है. सबसे ज़्यादा योगदान, कोड को धुंधला करने की प्रोसेस से मिलता है. इसमें क्लास और मेथड के नाम भी बदल जाते हैं.
ओरिजनल स्टैक ट्रेस को वापस पाने के लिए, R8 में retrace कमांड-लाइन टूल उपलब्ध है. यह टूल, कमांड-लाइन टूल पैकेज के साथ बंडल किया गया है.
अपने ऐप्लिकेशन के स्टैक ट्रेस को फिर से ट्रैक करने के लिए, आपको यह पक्का करना होगा कि बिल्ड में ज़रूरत के मुताबिक जानकारी हो, ताकि उसे फिर से ट्रैक किया जा सके. इसके लिए, अपने मॉड्यूल की proguard-rules.pro
फ़ाइल में ये नियम जोड़ें:
-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile
LineNumberTable
एट्रिब्यूट, तरीकों में पोज़िशन की जानकारी को बनाए रखता है, ताकि उन पोज़िशन को स्टैक ट्रेस में प्रिंट किया जा सके. SourceFile
एट्रिब्यूट से यह पक्का होता है कि सभी संभावित रनटाइम, पोज़िशन की जानकारी को प्रिंट करते हैं. -renamesourcefileattribute
डायरेक्टिव, स्टैक ट्रैस में सोर्स फ़ाइल का नाम सिर्फ़ 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
...
इस्तेमाल नहीं किए जाने वाले रिसॉर्स को हटाने की प्रोसेस से जुड़ी समस्या हल करना
संसाधनों को छोटा करने पर, बिल्ड
विंडो, ऐप्लिकेशन से हटाए गए रिसॉर्स की खास जानकारी दिखाती है. (Gredle से, पूरी जानकारी वाला टेक्स्ट आउटपुट दिखाने के लिए, आपको पहले विंडो की बाईं ओर मौजूद टॉगल व्यू
पर क्लिक करना होगा.) उदाहरण के लिए:
: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
तक कैसे पहुंचा जा सकता है.
साथ ही, ऊपर की ओर खोजने पर आपको दिखेगा कि संसाधन, "रूट ऐक्सेस किए जा सकने वाले मुख्य संसाधन हैं:" में दिया गया है. इसका मतलब है कि 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
एट्रिब्यूट का इस्तेमाल करके, बिल्ड सिस्टम को उसे हटाने के लिए कहें. इसके बारे में किस संसाधन को बनाए रखना है, यह तय करने का तरीका सेक्शन में बताया गया है.