लाइब्रेरी के लेखक के तौर पर, आपको यह पक्का करना चाहिए कि ऐप्लिकेशन डेवलपर, आपकी लाइब्रेरी को आसानी से अपने ऐप्लिकेशन में शामिल कर सकें. साथ ही, यह भी पक्का करना होगा कि इससे उपयोगकर्ताओं को अच्छी क्वालिटी का अनुभव मिले. आपको यह पक्का करना चाहिए कि आपकी लाइब्रेरी, Android के ऑप्टिमाइज़ेशन के साथ काम करती हो. इसके लिए, आपको कोई अतिरिक्त सेटअप करने की ज़रूरत नहीं है. इसके अलावा, आपको यह दस्तावेज़ भी तैयार करना चाहिए कि लाइब्रेरी, Android पर इस्तेमाल करने के लिए सही नहीं है.
यह दस्तावेज़, पब्लिश की गई लाइब्रेरी के डेवलपर के लिए है. हालांकि, यह बड़े और मॉड्यूलर ऐप्लिकेशन में इंटरनल लाइब्रेरी मॉड्यूल के डेवलपर के लिए भी काम का हो सकता है.
अगर आप ऐप्लिकेशन डेवलपर हैं और आपको अपने Android ऐप्लिकेशन को ऑप्टिमाइज़ करने के बारे में जानना है, तो ऐप्लिकेशन ऑप्टिमाइज़ करने की सुविधा चालू करना लेख पढ़ें. कौनसी लाइब्रेरी का इस्तेमाल करना सही है, इस बारे में जानने के लिए लाइब्रेरी का सही तरीके से इस्तेमाल करना लेख पढ़ें.
रिफ़्लेक्शन के बजाय कोड जनरेशन का इस्तेमाल करें
जब हो सके, तो रिफ़्लेक्शन के बजाय कोड जनरेट करने (codegen) का इस्तेमाल करें. प्रोग्रामिंग के दौरान, बॉयलरप्लेट कोड से बचने के लिए कोड जनरेशन और रिफ़्लेक्शन, दोनों सामान्य तरीके हैं. हालांकि, कोड जनरेशन, R8 जैसे ऐप्लिकेशन ऑप्टिमाइज़र के साथ ज़्यादा काम करता है:
- कोड जनरेट करने की सुविधा की मदद से, कोड का विश्लेषण किया जाता है और उसे बिल्ड प्रोसेस के दौरान बदला जाता है. कंपाइल होने के बाद, कोड में कोई बड़ा बदलाव नहीं किया जाता. इसलिए, ऑप्टिमाइज़र को पता होता है कि आखिर में किस कोड की ज़रूरत है और किस कोड को हटाया जा सकता है.
- रिफ़्लेक्शन की मदद से, कोड का विश्लेषण किया जाता है और उसे रनटाइम में बदला जाता है. जब तक कोड लागू नहीं हो जाता, तब तक उसे फ़ाइनल नहीं माना जाता. इसलिए, ऑप्टिमाइज़र को यह पता नहीं होता कि कौनसे कोड को सुरक्षित तरीके से हटाया जा सकता है. इससे, रनटाइम के दौरान रिफ़्लेक्शन के ज़रिए डाइनैमिक तरीके से इस्तेमाल किया जाने वाला कोड हट जाएगा. इसकी वजह से, उपयोगकर्ताओं के लिए ऐप्लिकेशन क्रैश हो जाते हैं.
आजकल की कई लाइब्रेरी, रिफ़्लेक्शन के बजाय कोडजन का इस्तेमाल करती हैं. Room, Dagger2, और कई अन्य लाइब्रेरी के लिए इस्तेमाल किए जाने वाले सामान्य एंट्रीपॉइंट के लिए, KSP देखें.
जब रिफ़्लेक्शन ठीक हो
अगर आपको रिफ़्लेक्शन का इस्तेमाल करना है, तो आपको सिर्फ़ इनमें से किसी एक में रिफ़्लेक्ट करना चाहिए:
- टारगेट किए गए खास टाइप (खास इंटरफ़ेस लागू करने वाले या सबक्लास)
- किसी खास रनटाइम एनोटेशन का इस्तेमाल करने वाला कोड
इस तरह से रिफ़्लेक्शन का इस्तेमाल करने से, रनटाइम की लागत कम हो जाती है. साथ ही, उपभोक्ताओं को टारगेट करने वाले डेटा को सुरक्षित रखने के नियम लिखे जा सकते हैं.
इस तरह की खास और टारगेट की गई रिफ़्लेक्शन, एक ऐसा पैटर्न है जो आपको Android फ़्रेमवर्क (उदाहरण के लिए, ऐक्टिविटी, व्यू, और ड्रॉएबल को बड़ा करते समय) और AndroidX लाइब्रेरी (उदाहरण के लिए, WorkManager
ListenableWorkers या RoomDatabases बनाते समय) दोनों में दिख सकता है. इसके उलट, Android ऐप्लिकेशन में Gson का इस्तेमाल करना सही नहीं है.
लाइब्रेरी में डेटा सुरक्षित रखने से जुड़े नियमों के टाइप
लाइब्रेरी में दो तरह के कीप नियम लागू किए जा सकते हैं:
- उपयोगकर्ता के निजी डेटा के रखरखाव के नियमों में, ऐसे नियम शामिल होने चाहिए जिनसे लाइब्रेरी में मौजूद डेटा को सुरक्षित रखा जा सके. अगर कोई लाइब्रेरी, अपने कोड या क्लाइंट ऐप्लिकेशन से तय किए गए कोड को कॉल करने के लिए रिफ़्लेक्शन या जेएनआई का इस्तेमाल करती है, तो इन नियमों में यह बताना ज़रूरी है कि किस कोड को बनाए रखना है. लाइब्रेरी को, उपभोक्ता के डेटा को सुरक्षित रखने से जुड़े नियमों को पैकेज करना चाहिए. ये नियम, ऐप्लिकेशन के डेटा को सुरक्षित रखने से जुड़े नियमों के फ़ॉर्मैट में ही होने चाहिए. ये नियम, लाइब्रेरी आर्टफ़ैक्ट (AAR या JAR) में बंडल किए जाते हैं. साथ ही, लाइब्रेरी का इस्तेमाल करने पर, Android ऐप्लिकेशन को ऑप्टिमाइज़ करने के दौरान इनका इस्तेमाल अपने-आप होता है. इन नियमों को,
build.gradle.kts(याbuild.gradle) फ़ाइल मेंconsumerProguardFilesप्रॉपर्टी के साथ दी गई फ़ाइल में बनाए रखा जाता है. ज़्यादा जानने के लिए, उपयोगकर्ता के डेटा को सुरक्षित रखने के लिए नियम बनाना लेख पढ़ें. - लाइब्रेरी बनाने के दौरान, लाइब्रेरी बिल्ड कीप के नियमों को लागू किया जाता है. इनकी ज़रूरत सिर्फ़ तब होती है, जब आपको लाइब्रेरी को बिल्ड टाइम पर आंशिक रूप से ऑप्टिमाइज़ करना हो.
उन्हें लाइब्रेरी के सार्वजनिक एपीआई को हटाने से रोकना होगा. ऐसा न करने पर, सार्वजनिक एपीआई लाइब्रेरी के डिस्ट्रिब्यूशन में मौजूद नहीं होगा. इसका मतलब है कि ऐप्लिकेशन डेवलपर, लाइब्रेरी का इस्तेमाल नहीं कर पाएंगे. इन नियमों को उस फ़ाइल में बनाए रखा जाता है जिसे आपकी
build.gradle.kts(याbuild.gradle) फ़ाइल मेंproguardFilesप्रॉपर्टी के साथ स्पेसिफ़ाई किया गया है. ज़्यादा जानने के लिए, AAR लाइब्रेरी के बिल्ड को ऑप्टिमाइज़ करना लेख पढ़ें.
उपयोगकर्ता के डेटा को बनाए रखने से जुड़े नियम लिखना
डेटा को सुरक्षित रखने के नियम से जुड़े सबसे सही तरीकों के अलावा, यहां लाइब्रेरी के लेखकों के लिए कुछ सुझाव दिए गए हैं.
- गलत ग्लोबल नियमों का इस्तेमाल न करें. जैसे, अपनी लाइब्रेरी की उपभोक्ता के लिए बने नियमों वाली फ़ाइल में
-dontobfuscateया-allowaccessmodificationजैसी ग्लोबल सेटिंग न डालें. ऐसा इसलिए, क्योंकि इनका असर आपकी लाइब्रेरी का इस्तेमाल करने वाले सभी ऐप्लिकेशन पर पड़ता है. - पैकेज के लिए बनाए गए डेटा को सुरक्षित रखने के नियमों को शामिल न करें. जैसे,
-keep class com.mylibrary.** { *; }. इस तरह के नियमों से, पूरी लाइब्रेरी में ऑप्टिमाइज़ेशन सीमित हो जाता है. इससे लाइब्रेरी का इस्तेमाल करने वाले सभी ऐप्लिकेशन के साइज़ पर असर पड़ता है. - अपनी लाइब्रेरी के उपभोक्ता के डेटा को सुरक्षित रखने से जुड़े नियमों वाली फ़ाइल में
-repackageclassesका इस्तेमाल न करें. हालांकि, अपनी लाइब्रेरी के बिल्ड को ऑप्टिमाइज़ करने के लिए,-repackageclassesका इस्तेमाल किया जा सकता है. इसके लिए, लाइब्रेरी के बिल्ड कीप रूल्स फ़ाइल में<your.library.package>.internalजैसे इंटरनल पैकेज का नाम डालें. इससे आपकी लाइब्रेरी ज़्यादा असरदार बन सकती है. भले ही, इसका इस्तेमाल करने वाले ऐप्लिकेशन ऑप्टिमाइज़ न किए गए हों. हालांकि, आम तौर पर इसकी ज़रूरत नहीं होती, क्योंकि ऐप्लिकेशन को भी ऑप्टिमाइज़ करना चाहिए. लाइब्रेरी को ऑप्टिमाइज़ करने के बारे में ज़्यादा जानने के लिए, लाइब्रेरी के लेखकों के लिए ऑप्टिमाइज़ेशन लेख पढ़ें. - अपनी लाइब्रेरी के लिए ज़रूरी एट्रिब्यूट का एलान, लाइब्रेरी के कीप नियमों वाली फ़ाइलों में करें. भले ही,
proguard-android-optimize.txtमें तय किए गए एट्रिब्यूट के साथ ओवरलैप हो रहा हो. - अगर आपको अपनी लाइब्रेरी के डिस्ट्रिब्यूशन में ये एट्रिब्यूट चाहिए, तो इन्हें अपनी लाइब्रेरी की बिल्ड कीप रूल्स फ़ाइल में बनाए रखें. साथ ही, इन्हें अपनी लाइब्रेरी की कंज्यूमर कीप रूल्स फ़ाइल में न रखें:
AnnotationDefaultEnclosingMethodExceptionsInnerClassesRuntimeInvisibleAnnotationsRuntimeInvisibleParameterAnnotationsRuntimeInvisibleTypeAnnotationsRuntimeVisibleAnnotationsRuntimeVisibleParameterAnnotationsRuntimeVisibleTypeAnnotationsSignature
- अगर रनटाइम में एनोटेशन का इस्तेमाल किया जाता है, तो लाइब्रेरी के लेखकों को अपने उपभोक्ता के नियमों में
RuntimeVisibleAnnotationsएट्रिब्यूट को बनाए रखना चाहिए. - लाइब्रेरी के लेखकों को, उपभोक्ता के लिए बनाए गए नियमों में इन ग्लोबल विकल्पों का इस्तेमाल नहीं करना चाहिए:
-include-basedirectory-injars-outjars-libraryjars-repackageclasses-flattenpackagehierarchy-allowaccessmodification-overloadaggressively-renamesourcefileattribute-ignorewarnings-addconfigurationdebugging-printconfiguration-printmapping-printusage-printseeds-applymapping-obfuscationdictionary-classobfuscationdictionary-packageobfuscationdictionary
एएआर लाइब्रेरी
किसी AAR लाइब्रेरी के लिए उपभोक्ता नियम जोड़ने के लिए, Android लाइब्रेरी मॉड्यूल की बिल्ड स्क्रिप्ट में consumerProguardFiles विकल्प का इस्तेमाल करें. ज़्यादा जानकारी के लिए, लाइब्रेरी मॉड्यूल बनाने के बारे में दिशा-निर्देश देखें.
Kotlin
android { defaultConfig { consumerProguardFiles("consumer-proguard-rules.pro") } ... }
Groovy
android { defaultConfig { consumerProguardFiles 'consumer-proguard-rules.pro' } ... }
ज़ार लाइब्रेरी
अगर आपको अपनी Kotlin/Java लाइब्रेरी के साथ नियमों को बंडल करना है, तो अपनी नियमों वाली फ़ाइल को फ़ाइनल JAR की META-INF/proguard/ डायरेक्ट्री में रखें. इसके लिए, किसी भी फ़ाइल नाम का इस्तेमाल किया जा सकता है.
उदाहरण के लिए, अगर आपने <libraryroot>/src/main/kotlin में कोड डाला है, तो उपभोक्ता नियमों वाली फ़ाइल को <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro पर रखें. इसके बाद, नियमों को आपके आउटपुट JAR में सही जगह पर बंडल कर दिया जाएगा.
पुष्टि करें कि फ़ाइनल JAR बंडल में नियम सही तरीके से लागू किए गए हैं. इसके लिए, यह देखें कि नियम META-INF/proguard डायरेक्ट्री में मौजूद हैं या नहीं.
AAR लाइब्रेरी के बिल्ड को ऑप्टिमाइज़ करना (ऐडवांस)
आम तौर पर, आपको लाइब्रेरी बिल्ड को सीधे तौर पर ऑप्टिमाइज़ करने की ज़रूरत नहीं होती, क्योंकि लाइब्रेरी बिल्ड के समय ऑप्टिमाइज़ेशन के विकल्प बहुत कम होते हैं. ऐप्लिकेशन बनाने के दौरान ही, R8 को यह पता चल सकता है कि लाइब्रेरी के सभी तरीकों का इस्तेमाल कैसे किया जाता है और कौनसे पैरामीटर पास किए जाते हैं. ऐसा तब होता है, जब लाइब्रेरी को ऐप्लिकेशन के हिस्से के तौर पर शामिल किया जाता है. लाइब्रेरी डेवलपर के तौर पर, आपको ऑप्टिमाइज़ेशन के कई चरणों के बारे में सोचना होगा. साथ ही, लाइब्रेरी और ऐप्लिकेशन बनाने के समय के व्यवहार को ध्यान में रखना होगा. इसके बाद ही, आपको लाइब्रेरी को ऑप्टिमाइज़ करना होगा.
अगर आपको अब भी बिल्ड के समय अपनी लाइब्रेरी को ऑप्टिमाइज़ करना है, तो Android Gradle Plugin की मदद से ऐसा किया जा सकता है.
Kotlin
android { buildTypes { release { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } configureEach { consumerProguardFiles("consumer-rules.pro") } } }
Groovy
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } configureEach { consumerProguardFiles "consumer-rules.pro" } } }
ध्यान दें कि proguardFiles का व्यवहार, consumerProguardFiles से काफ़ी अलग होता है:
proguardFilesका इस्तेमाल, लाइब्रेरी बनाने के समय किया जाता है. अक्सर इनका इस्तेमालgetDefaultProguardFile("proguard-android-optimize.txt")के साथ किया जाता है. इससे यह तय किया जाता है कि लाइब्रेरी बनाने के दौरान, लाइब्रेरी के किस हिस्से को रखा जाना चाहिए. कम से कम, यह आपका सार्वजनिक एपीआई है.- इसके उलट,
consumerProguardFilesको लाइब्रेरी में पैकेज किया जाता है, ताकि बाद में होने वाले ऑप्टिमाइज़ेशन पर असर पड़े. ऐसा तब होता है, जब आपकी लाइब्रेरी का इस्तेमाल करने वाला ऐप्लिकेशन बनाया जा रहा हो.
उदाहरण के लिए, अगर आपकी लाइब्रेरी इंटरनल क्लास बनाने के लिए रिफ़्लेक्शन का इस्तेमाल करती है, तो आपको proguardFiles और consumerProguardFiles, दोनों में कीप नियम तय करने पड़ सकते हैं.
अगर आपने अपनी लाइब्रेरी के बिल्ड में -repackageclasses का इस्तेमाल किया है, तो क्लास को अपनी लाइब्रेरी के पैकेज में मौजूद सब-पैकेज में फिर से पैकेज करें. उदाहरण के लिए, -repackageclasses 'internal' के बजाय -repackageclasses
'com.example.mylibrary.internal' का इस्तेमाल करें.
R8 के अलग-अलग वर्शन के साथ काम करता है (ऐडवांस)
R8 के किसी खास वर्शन को टारगेट करने के लिए, नियमों को अपनी ज़रूरत के मुताबिक बनाया जा सकता है. इससे आपकी लाइब्रेरी, R8 के नए वर्शन का इस्तेमाल करने वाले प्रोजेक्ट में बेहतर तरीके से काम कर पाती है. साथ ही, R8 के पुराने वर्शन का इस्तेमाल करने वाले प्रोजेक्ट में मौजूदा नियमों का इस्तेमाल जारी रखा जा सकता है.
टारगेट किए गए R8 नियमों को तय करने के लिए, आपको उन्हें AAR के classes.jar में मौजूद META-INF/com.android.tools डायरेक्ट्री में या JAR की META-INF/com.android.tools डायरेक्ट्री में शामिल करना होगा.
In an AAR library:
proguard.txt (legacy location, the file name must be "proguard.txt")
classes.jar
└── META-INF
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
In a JAR library:
META-INF
├── proguard/<ProGuard-rule-files> (legacy location)
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
META-INF/com.android.tools डायरेक्ट्री में, कई सबडायरेक्ट्री हो सकती हैं. इनके नाम r8-from-<X>-upto-<Y> के फ़ॉर्मैट में होते हैं. इससे यह पता चलता है कि नियम, R8 के किन वर्शन के लिए लिखे गए हैं. हर सबडायरेक्ट्री में, R8 के नियमों वाली एक या उससे ज़्यादा फ़ाइलें हो सकती हैं. इनके नाम और एक्सटेंशन कुछ भी हो सकते हैं.
ध्यान दें कि -from-<X> और -upto-<Y> हिस्से वैकल्पिक हैं. <Y> वर्शन एक्सक्लूसिव है. साथ ही, वर्शन की रेंज आम तौर पर लगातार होती है, लेकिन यह ओवरलैप भी हो सकती है.
उदाहरण के लिए, r8, r8-upto-8.0.0, r8-from-8.0.0-upto-8.2.0, और r8-from-8.2.0, डायरेक्ट्री के नाम हैं. ये टारगेट की गई R8 की नियमों के सेट को दिखाते हैं. r8 डायरेक्ट्री में मौजूद नियमों का इस्तेमाल, R8 के किसी भी वर्शन में किया जा सकता है. r8-from-8.0.0-upto-8.2.0 डायरेक्ट्री में दिए गए नियमों का इस्तेमाल, R8 के वर्शन 8.0.0 से लेकर 8.2.0 तक किया जा सकता है. हालांकि, 8.2.0 शामिल नहीं है.
Android Gradle प्लगिन, इस जानकारी का इस्तेमाल करके उन सभी नियमों को चुनता है जिनका इस्तेमाल R8 के मौजूदा वर्शन में किया जा सकता है. अगर कोई लाइब्रेरी, टारगेट किए गए R8 नियमों के बारे में नहीं बताती है, तो Android Gradle प्लगिन, लेगसी लोकेशन (एएआर के लिए proguard.txt या जार के लिए META-INF/proguard/<ProGuard-rule-files>) से नियमों को चुनेगा.