'रखें' नियम जोड़ना

किसी क्लास (या सबक्लास या लागू करने का तरीका) और फिर उस क्लास में मौजूद सदस्यों—तरीकों, कंस्ट्रक्टर या फ़ील्ड—को सुरक्षित रखने के लिए, कीप नियम तय किया जाता है.

डेटा बनाए रखने के नियम का सामान्य सिंटैक्स इस तरह होता है:


-<keep_option>[,<keep_option_modifier_1>,<keep_option_modifier_2>,...] <class_specification>

यहां, डेटा को सुरक्षित रखने के नियम का एक उदाहरण दिया गया है. इसमें keepclassmembers को सुरक्षित रखने के विकल्प के तौर पर, allowoptimization को मॉडिफ़ायर के तौर पर इस्तेमाल किया गया है. साथ ही, com.example.MyClass से someSpecificMethod() को सुरक्षित रखा गया है:

-keepclassmembers,allowoptimization class com.example.MyClass {
  void someSpecificMethod();
}

विकल्प को बनाए रखें

'रखें' विकल्प, डेटा बनाए रखने के नियम का पहला हिस्सा होता है. इससे यह तय किया जाता है कि क्लास के किन पहलुओं को बनाए रखना है. डेटा को सुरक्षित रखने के छह अलग-अलग विकल्प हैं. जैसे, keep, keepclassmembers, keepclasseswithmembers, keepnames, keepclassmembernames, keepclasseswithmembernames.

यहां दी गई टेबल में, इन विकल्पों के बारे में बताया गया है:

Keep विकल्प ब्यौरा
keepclassmembers यह कुकी, सिर्फ़ उन सदस्यों की जानकारी सेव करती है जिनकी क्लास ऑप्टिमाइज़ेशन के बाद भी मौजूद रहती है.
keep यह कुकी, तय की गई क्लास और सदस्यों (फ़ील्ड और तरीके) को सेव करती है. इससे उन्हें ऑप्टिमाइज़ होने से रोका जाता है.

ध्यान दें: आम तौर पर, keep का इस्तेमाल सिर्फ़ कीप विकल्प मॉडिफ़ायर के साथ किया जाना चाहिए. इसकी वजह यह है कि keep का इस्तेमाल करने पर, मैच की गई क्लास के लिए किसी भी तरह का ऑप्टिमाइज़ेशन नहीं किया जा सकता.
keepclasseswithmembers यह कुकी, किसी क्लास और उसके चुने गए सदस्यों को तब तक सेव रखती है, जब तक क्लास में क्लास स्पेसिफ़िकेशन के सभी सदस्य शामिल न हों.
keepclassmembernames इससे क्लास में शामिल सदस्यों के नाम बदलने पर रोक लग जाती है. हालांकि, इससे क्लास या उसमें शामिल सदस्यों को हटाने पर कोई असर नहीं पड़ता.

ध्यान दें: इस विकल्प का मतलब अक्सर गलत समझा जाता है. इसलिए, इसके बजाय -keepclassmembers,allowshrinking का इस्तेमाल करें.
keepnames इससे क्लास और उसके सदस्यों का नाम बदलने से रोका जाता है. हालांकि, अगर क्लास का इस्तेमाल नहीं किया जा रहा है, तो उसे पूरी तरह से हटाने से नहीं रोका जाता.

ध्यान दें: इस विकल्प का मतलब अक्सर गलत समझा जाता है. इसलिए, इसके बजाय -keep,allowshrinking का इस्तेमाल करें.
keepclasseswithmembernames इससे क्लास और उसके सदस्यों का नाम बदलने से रोका जा सकता है. हालांकि, ऐसा सिर्फ़ तब किया जा सकता है, जब सदस्य फ़ाइनल कोड में मौजूद हों. इससे कोड को हटाने से नहीं रोका जा सकता.

ध्यान दें: इस विकल्प का मतलब अक्सर गलत समझा जाता है. इसके बजाय, -keepclasseswithmembers,allowshrinking का इस्तेमाल करें.

डेटा को सेव रखने का सही विकल्प चुनना

अपने ऐप्लिकेशन के लिए सही ऑप्टिमाइज़ेशन तय करने में, कोड को सुरक्षित रखने का सही विकल्प चुनना ज़रूरी है. कोड को सुरक्षित रखने के कुछ विकल्पों से कोड छोटा हो जाता है. इस प्रोसेस में, बिना रेफ़रंस वाले कोड को हटा दिया जाता है. वहीं, अन्य विकल्पों से कोड को अस्पष्ट कर दिया जाता है या उसका नाम बदल दिया जाता है. यहां दी गई टेबल में, अलग-अलग कीप विकल्पों के बारे में बताया गया है:

Keep विकल्प क्लास को छोटा करता है क्लास के नाम छिपाता है सदस्यों की संख्या कम करता है सदस्यों की जानकारी को छिपाता है
keep
keepclassmembers
keepclasseswithmembers
keepnames
keepclassmembernames
keepclasseswithmembernames

विकल्प के मॉडिफ़ायर को बनाए रखें

निजी डेटा के रखरखाव के नियम के दायरे और व्यवहार को कंट्रोल करने के लिए, निजी डेटा के रखरखाव के विकल्प में बदलाव करने वाले मॉडिफ़ायर का इस्तेमाल किया जाता है. अपने कीप नियम में, कीप विकल्प के लिए 0 या उससे ज़्यादा मॉडिफ़ायर जोड़े जा सकते हैं.

कीप विकल्प मॉडिफ़ायर के लिए संभावित वैल्यू के बारे में यहां दी गई टेबल में बताया गया है:

वैल्यू ब्यौरा
allowoptimization इससे तय किए गए एलिमेंट को ऑप्टिमाइज़ किया जा सकता है. हालांकि, बताए गए एलिमेंट का नाम नहीं बदला जाता या उन्हें हटाया नहीं जाता.
allowobfucastion इससे चुने गए एलिमेंट का नाम बदला जा सकता है. हालांकि, एलिमेंट को हटाया नहीं जाएगा या उन्हें ऑप्टिमाइज़ नहीं किया जाएगा.
allowshrinking अगर R8 को तय किए गए एलिमेंट के कोई रेफ़रंस नहीं मिलते हैं, तो उन्हें हटाने की अनुमति देता है. हालांकि, एलिमेंट का नाम नहीं बदला जाता है और न ही उन्हें ऑप्टिमाइज़ किया जाता है.
includedescriptorclasses यह R8 को उन सभी क्लास को बनाए रखने का निर्देश देता है जो बनाए रखी जा रही क्लास के तरीकों (पैरामीटर टाइप और रिटर्न टाइप) और फ़ील्ड (फ़ील्ड टाइप) के डिस्क्रिप्टर में दिखती हैं.
allowaccessmodification इस विकल्प की मदद से, R8 को ऑप्टिमाइज़ेशन प्रोसेस के दौरान क्लास, तरीकों, और फ़ील्ड के ऐक्सेस मॉडिफ़ायर (public, private, protected) को बदलने (आम तौर पर, ज़्यादा ऐक्सेस देने) की अनुमति मिलती है.
allowrepackage इस विकल्प की मदद से, R8 क्लास को अलग-अलग पैकेज में ले जा सकता है. इनमें डिफ़ॉल्ट (रूट) पैकेज भी शामिल है.

क्लास की जानकारी

आपको हर कीप नियम में एक क्लास (इसमें इंटरफ़ेस, enum, और एनोटेशन क्लास शामिल हैं) तय करनी होगी. एनोटेशन के आधार पर, नियम को सीमित किया जा सकता है. इसके लिए, सुपरक्लास या लागू किया गया इंटरफ़ेस तय करें या क्लास के लिए ऐक्सेस मॉडिफ़ायर तय करें. सभी क्लास, जिनमें java.lang नेमस्पेस की क्लास जैसे कि java.lang.String शामिल हैं, को उनके पूरी तरह क्वालिफ़ाइड Java नाम का इस्तेमाल करके तय किया जाना चाहिए. इस्तेमाल किए जाने वाले नामों को समझने के लिए, जनरेट किए गए Java नामों की जांच करना में बताए गए टूल का इस्तेमाल करके, बाइटकोड की जांच करें.

यहां दिए गए उदाहरण में बताया गया है कि आपको MaterialButton क्लास को कैसे तय करना चाहिए:

  • सही: com.google.android.material.button.MaterialButton
  • गलत: MaterialButton

क्लास स्पेसिफ़िकेशन से यह भी तय किया जाता है कि क्लास में कौनसे सदस्य शामिल होने चाहिए. उदाहरण के लिए, यहां दिया गया नियम MyClass क्लास और someSpecificMethod() तरीके को बनाए रखता है:

-keep class com.example.MyClass {
  void someSpecificMethod();
}

एनोटेशन के आधार पर क्लास तय करना

एनोटेशन के आधार पर क्लास तय करने के लिए, एनोटेशन के पूरी तरह से क्वालिफ़ाइड किए गए Java नाम के आगे @ सिंबल लगाएं. उदाहरण के लिए:

-keep class @com.example.MyAnnotation com.example.MyClass

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

-keep class @com.example.Annotation1 @com.example.Annotation2 *

सबक्लास और लागू करने के तरीके के बारे में बताएं

किसी सबक्लास या इंटरफ़ेस लागू करने वाली क्लास को टारगेट करने के लिए, क्रमशः extend और implements का इस्तेमाल करें.

उदाहरण के लिए, अगर आपके पास क्लास Bar है और उसकी सबक्लास Foo इस तरह है:

class Foo : Bar()

यहां दिया गया Keep का नियम, Bar की सभी सबक्लास को सुरक्षित रखता है. ध्यान दें कि कीप नियम में, सुपरक्लास Bar को शामिल नहीं किया जाता.

-keep class * extends Bar

अगर आपके पास Foo क्लास है, जो Bar इंटरफ़ेस को लागू करती है, तो:

class Foo : Bar

नीचे दिए गए कीप नियम से, Bar को लागू करने वाली सभी क्लास को सुरक्षित रखा जाता है. ध्यान दें कि डेटा बनाए रखने के नियम में, इंटरफ़ेस Bar शामिल नहीं है.

-keep class * implements Bar

ऐक्सेस मॉडिफ़ायर के आधार पर क्लास तय करना

अपने कीप नियमों को ज़्यादा सटीक बनाने के लिए, ऐक्सेस मॉडिफ़ायर तय किए जा सकते हैं. जैसे, public, private, static, और final.

उदाहरण के लिए, यहां दिया गया नियम, api पैकेज और उसके सब-पैकेज में मौजूद सभी public क्लास और इन क्लास में मौजूद सभी सार्वजनिक और सुरक्षित सदस्यों को बनाए रखता है.

-keep public class com.example.api.** { public protected *; }

किसी क्लास में शामिल सदस्यों के लिए भी मॉडिफ़ायर इस्तेमाल किए जा सकते हैं. उदाहरण के लिए, यहां दिया गया नियम, Utils क्लास के सिर्फ़ public static तरीकों को बनाए रखता है:

-keep class com.example.Utils {
  public static void *(...);
}

Kotlin के लिए खास तौर पर बनाए गए मॉडिफ़ायर

R8, Kotlin के खास मॉडिफ़ायर के साथ काम नहीं करता. जैसे, internal और suspend. ऐसे फ़ील्ड को बनाए रखने के लिए, इन दिशा-निर्देशों का पालन करें.

  • किसी internal क्लास, तरीके या फ़ील्ड को बनाए रखने के लिए, उसे सार्वजनिक के तौर पर मार्क करें. उदाहरण के लिए, यहां दिया गया Kotlin सोर्स देखें:

    package com.example
    internal class ImportantInternalClass {
      internal val f: Int
      internal fun m() {}
    }
    

    Kotlin कंपाइलर से जनरेट हुई .class फ़ाइलों में, internal क्लास, तरीके, और फ़ील्ड public होते हैं. इसलिए, आपको public कीवर्ड का इस्तेमाल करना होगा. जैसा कि इस उदाहरण में दिखाया गया है:

    -keepclassmembers public class com.example.ImportantInternalClass {
      public int f;
      public void m();
    }
    
  • जब किसी suspend सदस्य को कंपाइल किया जाता है, तो कंपाइल किए गए उसके हस्ताक्षर का मिलान, कीप नियम में मौजूद हस्ताक्षर से करें.

    उदाहरण के लिए, अगर आपने fetchUser फ़ंक्शन को इस स्निपेट में दिखाए गए तरीके से तय किया है:

    suspend fun fetchUser(id: String): User
    

    कंपाइल करने पर, बाइटकोड में इसका सिग्नेचर ऐसा दिखता है:

    public final Object fetchUser(String id, Continuation<? super User> continuation);
    

    इस फ़ंक्शन के लिए निजी डेटा के रखरखाव का नियम लिखने के लिए, आपको इस कंपाइल किए गए सिग्नेचर से मिलान करना होगा या ... का इस्तेमाल करना होगा.

    कंपाइल किए गए सिग्नेचर का इस्तेमाल करने का उदाहरण यहां दिया गया है:

    -keepclassmembers class com.example.repository.UserRepository {
      public java.lang.Object fetchUser(java.lang.String,  kotlin.coroutines.Continuation);
    }
    

    ... का इस्तेमाल करने का एक उदाहरण यहां दिया गया है:

    -keepclassmembers class com.example.repository.UserRepository {
      public java.lang.Object fetchUser(...);
    }
    

सदस्य की जानकारी

क्लास स्पेसिफ़िकेशन में, उन क्लास सदस्यों को शामिल किया जा सकता है जिन्हें बनाए रखना है. अगर किसी क्लास के लिए एक या उससे ज़्यादा सदस्यों को चुना जाता है, तो यह नियम अन्य सदस्यों पर लागू नहीं होता.

एनोटेशन के आधार पर सदस्यों के बारे में जानकारी देना

एनोटेशन के आधार पर सदस्यों को तय किया जा सकता है. क्लास की तरह ही, एनोटेशन के पूरी तरह क्वालिफ़ाइड Java नाम के आगे @ प्रीफ़िक्स लगाएं. इसकी मदद से, किसी क्लास में सिर्फ़ उन सदस्यों को रखा जा सकता है जिन्हें खास एनोटेशन के साथ मार्क किया गया है. उदाहरण के लिए, @com.example.MyAnnotation के साथ एनोटेट किए गए तरीकों और फ़ील्ड को बनाए रखने के लिए:

-keep class com.example.MyClass {
  @com.example.MyAnnotation <methods>;
  @com.example.MyAnnotation <fields>;
}

बेहतर तरीके से टारगेट करने वाली, असरदार नियमों के लिए, इसे क्लास-लेवल के एनोटेशन मैचिंग के साथ जोड़ा जा सकता है:

-keep class @com.example.ClassAnnotation * {
  @com.example.MethodAnnotation <methods>;
  @com.example.FieldAnnotation <fields>;
}

इससे क्लास को @ClassAnnotation से एनोटेट किया जाता है. साथ ही, उन क्लास में, @MethodAnnotation से एनोटेट किए गए तरीकों और @FieldAnnotation से एनोटेट किए गए फ़ील्ड को बनाए रखा जाता है.

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

माटिंग में इस्तेमाल हुए तरीके

किसी कीप नियम के लिए, सदस्य की खास जानकारी में किसी तरीके को तय करने का सिंटैक्स इस तरह होता है:

[<access_modifier>] [<return_type>] <method_name>(<parameter_types>);

उदाहरण के लिए, यहां दिया गया कीप नियम, setLabel() नाम के एक सार्वजनिक तरीके को सुरक्षित रखता है. यह तरीका void वैल्यू दिखाता है और String लेता है.

-keep class com.example.MyView {
    public void setLabel(java.lang.String);
}

किसी क्लास में मौजूद सभी तरीकों को मैच करने के लिए, <methods> को शॉर्टकट के तौर पर इस्तेमाल किया जा सकता है. इसके लिए, यह तरीका अपनाएं:

-keep class com.example.MyView {
    <methods>;
}

रिटर्न टाइप और पैरामीटर टाइप के लिए टाइप तय करने के बारे में ज़्यादा जानने के लिए, टाइप देखें.

कंस्ट्रक्टर

कंस्ट्रक्टर के बारे में बताने के लिए, <init> का इस्तेमाल करें. निजी डेटा के रखरखाव के नियम के लिए, सदस्य की खास जानकारी में कंस्ट्रक्टर तय करने का सिंटैक्स इस तरह होता है:

[<access_modifier>] <init>(parameter_types);

उदाहरण के लिए, यहां दिया गया कीप नियम, कस्टम View कंस्ट्रक्टर को बनाए रखता है. यह Context और AttributeSet लेता है.

-keep class com.example.ui.MyCustomView {
    public <init>(android.content.Context, android.util.AttributeSet);
}

सभी सार्वजनिक कंस्ट्रक्टर को बनाए रखने के लिए, इस उदाहरण का इस्तेमाल करें:

-keep class com.example.ui.MyCustomView {
    public <init>(...);
}

फ़ील्ड्स की फ़िल्में

किसी कीप नियम के लिए सदस्य की खास जानकारी में फ़ील्ड तय करने का सिंटैक्स यहां दिया गया है:

[<access_modifier>...] [<type>] <field_name>;

उदाहरण के लिए, यहां दिया गया कीप नियम, userId नाम के एक प्राइवेट स्ट्रिंग फ़ील्ड और STATUS_ACTIVE नाम के एक सार्वजनिक स्टैटिक पूर्णांक फ़ील्ड को सुरक्षित रखता है:

-keep class com.example.models.User {
    private java.lang.String userId;
    public static int STATUS_ACTIVE;
}

क्लास के सभी फ़ील्ड को इस तरह मैच करने के लिए, <fields> को शॉर्टकट के तौर पर इस्तेमाल किया जा सकता है:

-keep class com.example.models.User {
    <fields>;
}

प्रकार

इस सेक्शन में, कीप रूल के सदस्य के स्पेसिफ़िकेशन में, रिटर्न टाइप, पैरामीटर टाइप, और फ़ील्ड टाइप तय करने का तरीका बताया गया है. अगर टाइप, Kotlin सोर्स कोड से अलग हैं, तो टाइप तय करने के लिए जनरेट किए गए Java नामों का इस्तेमाल करना न भूलें.

प्रिमिटिव टाइप

प्रिमिटिव टाइप तय करने के लिए, उसके Java कीवर्ड का इस्तेमाल करें. R8 इन प्रिमिटिव टाइप को पहचानता है: boolean, byte, short, char, int, long, float, double.

प्रिमिटिव टाइप वाले नियम का उदाहरण यहां दिया गया है:

# Keeps a method that takes an int and a float as parameters.
-keepclassmembers class com.example.Calculator {
    public void setValues(int, float);
}

जेनरिक टाइप

कंपाइलेशन के दौरान, Kotlin/Java कंपाइलर सामान्य टाइप की जानकारी मिटा देता है. इसलिए, सामान्य टाइप वाले कीप नियम लिखते समय, आपको अपने कोड के कंपाइल किए गए वर्शन को टारगेट करना होगा, न कि ओरिजनल सोर्स कोड को. सामान्य टाइप में बदलाव करने के तरीके के बारे में ज़्यादा जानने के लिए, टाइप इरेज़र देखें.

उदाहरण के लिए, अगर आपके पास Box.kt में तय किए गए अनबाउंडेड जेनरिक टाइप वाला यह कोड है:

package com.myapp.data

class Box<T>(val item: T) {
    fun getItem(): T {
        return item
    }
}

टाइप इरेज़र के बाद, T को Object से बदल दिया जाता है. क्लास कंस्ट्रक्टर और तरीके को बनाए रखने के लिए, आपके नियम में सामान्य T के बजाय java.lang.Object का इस्तेमाल किया जाना चाहिए.

डेटा को सुरक्षित रखने के नियम का एक उदाहरण यहां दिया गया है:

# Keep the constructor and methods of the Box class.
-keep class com.myapp.data.Box {
    public init(java.lang.Object);
    public java.lang.Object getItem();
}

अगर आपके पास NumberBox.kt में बाउंडेड जेनरिक टाइप वाला यह कोड है:

package com.myapp.data

// T is constrained to be a subtype of Number
class NumberBox<T : Number>(val number: T)

इस मामले में, टाइप इरेज़र T को उसके बाउंड java.lang.Number से बदल देता है.

डेटा को सुरक्षित रखने के नियम का एक उदाहरण यहां दिया गया है:

-keep class com.myapp.data.NumberBox {
    public init(java.lang.Number);
}

ऐप्लिकेशन के हिसाब से सामान्य टाइप को बेस क्लास के तौर पर इस्तेमाल करते समय, बेस क्लास के लिए भी कीप नियमों को शामिल करना ज़रूरी है.

उदाहरण के लिए, इस कोड के लिए:

package com.myapp.data

data class UnpackOptions(val useHighPriority: Boolean)

// The generic Box class with UnpackOptions as the bounded type
class Box<T: UnpackOptions>(val item: T) {
}

includedescriptorclasses के साथ कीप नियम का इस्तेमाल करके, UnpackOptions क्लास और Box क्लास के तरीके, दोनों को एक ही नियम के साथ सुरक्षित रखा जा सकता है. इसके लिए, यहां दिया गया तरीका अपनाएं:

-keep,includedescriptorclasses class com.myapp.data.Box {
    public <init>(com.myapp.data.UnpackOptions);
}

अगर आपको ऑब्जेक्ट की सूची को प्रोसेस करने वाले किसी फ़ंक्शन को बनाए रखना है, तो आपको एक ऐसा नियम लिखना होगा जो फ़ंक्शन के सिग्नेचर से पूरी तरह मेल खाता हो. ध्यान दें कि सामान्य टाइप मिटा दिए जाते हैं. इसलिए, List<Product> जैसे पैरामीटर को java.util.List के तौर पर देखा जाता है.

उदाहरण के लिए, अगर आपके पास एक यूटिलिटी क्लास है, जिसमें एक ऐसा फ़ंक्शन है जो Product ऑब्जेक्ट की सूची को इस तरह प्रोसेस करता है:

package com.myapp.utils

import com.myapp.data.Product
import android.util.Log

class DataProcessor {
    // This is the function we want to keep
    fun processProducts(products: List<Product>) {
        Log.d("DataProcessor", "Processing ${products.size} products.")
        // Business logic ...
    }
}

// The data class used in the list (from the previous example)
package com.myapp.data
data class Product(val id: String, val name: String)

सिर्फ़ processProducts फ़ंक्शन को सुरक्षित रखने के लिए, इस नियम का इस्तेमाल किया जा सकता है:

-keep class com.myapp.utils.DataProcessor {
    public void processProducts(java.util.List);
}

ऐरे के टाइप

ऐरे के हर डाइमेंशन के लिए, कॉम्पोनेंट टाइप में [] जोड़कर ऐरे टाइप तय करें. यह क्लास टाइप और प्रिमिटिव टाइप, दोनों पर लागू होता है.

  • एक डाइमेंशन वाली क्लास ऐरे: java.lang.String[]
  • दो डाइमेंशन वाला प्रिमिटिव ऐरे: int[][]

उदाहरण के लिए, अगर आपके पास यह कोड है:

package com.example.data

class ImageProcessor {
  fun process(): ByteArray {
    // process image to return a byte array
  }
}

इस तरह के डेटा को सुरक्षित रखने के लिए, यह नियम इस्तेमाल किया जा सकता है:

# Keeps a method that returns a byte array.
-keepclassmembers class com.example.data.ImageProcessor {
    public byte[] process();
}

उदाहरण

उदाहरण के लिए, किसी क्लास और उसके सभी सदस्यों को सुरक्षित रखने के लिए, इसका इस्तेमाल करें:

-keep class com.myapp.MyClass { *; }

सिर्फ़ क्लास और उसके डिफ़ॉल्ट कंस्ट्रक्टर को बनाए रखने के लिए, लेकिन अन्य सदस्यों को नहीं, तो इसका इस्तेमाल करें:

-keep class com.myapp.MyClass

हमारा सुझाव है कि आप हमेशा कुछ सदस्यों के नाम दें. उदाहरण के लिए, यहां दिए गए उदाहरण में क्लास MyClass में, पब्लिक फ़ील्ड text और पब्लिक मेथड updateText() को बनाए रखा गया है.

-keep class com.myapp.MyClass {
    public java.lang.String text;
    public void updateText(java.lang.String);
}

सभी सार्वजनिक फ़ील्ड और सार्वजनिक तरीके बनाए रखने के लिए, यह उदाहरण देखें:

-keep public class com.example.api.ApiClient {
    public *;
}

सदस्यता की जानकारी शामिल न करना

मेंबर स्पेसिफ़िकेशन को शामिल न करने पर, R8 क्लास के लिए डिफ़ॉल्ट कंस्ट्रक्टर को बनाए रखता है.

उदाहरण के लिए, अगर आपने -keep class com.example.MyClass या -keep class com.example.MyClass {} लिखा है, तो R8 इन्हें इस तरह से ट्रीट करेगा:

-keep class com.example.MyClass{
  void <init>();
}

पैकेज-लेवल के फ़ंक्शन

अगर आपको किसी क्लास के बाहर तय किए गए Kotlin फ़ंक्शन (आम तौर पर, इन्हें टॉप लेवल फ़ंक्शन कहा जाता है) को रेफ़रंस करना है, तो पक्का करें कि आपने Kotlin कंपाइलर की ओर से अपने-आप जोड़ी गई क्लास के लिए, जनरेट किए गए Java नाम का इस्तेमाल किया हो. क्लास का नाम, Kotlin फ़ाइल का नाम होता है. इसमें Kt जोड़ा जाता है. उदाहरण के लिए, अगर आपके पास MyClass.kt नाम की कोई Kotlin फ़ाइल है, जिसे इस तरह से तय किया गया है:

package com.example.myapp.utils

// A top-level function not inside a class
fun isEmailValid(email: String): Boolean {
    return email.contains("@")
}

isEmailValid फ़ंक्शन के लिए, डेटा के रखरखाव का नियम लिखने के लिए, क्लास स्पेसिफ़िकेशन को जनरेट की गई क्लास MyClassKt को टारगेट करना होगा:

-keep class com.example.myapp.utils.MyClassKt {
    public static boolean isEmailValid(java.lang.String);
}

वाइल्डकार्ड

यहां दी गई टेबल में बताया गया है कि वाइल्डकार्ड का इस्तेमाल करके, एक जैसे पैटर्न वाली कई क्लास या सदस्यों पर, डेटा सुरक्षित रखने के नियमों को कैसे लागू किया जाता है.

वाइल्डकार्ड क्लास या सदस्यों पर लागू होता है ब्यौरा
** दोनों इसका इस्तेमाल सबसे ज़्यादा किया जाता है. यह किसी भी टाइप के नाम से मेल खाता है. इसमें पैकेज सेपरेटर की कोई भी संख्या शामिल है. यह किसी पैकेज और उसके सब-पैकेज में मौजूद सभी क्लास का मिलान करने के लिए काम आता है.
* दोनों क्लास स्पेसिफ़िकेशन के लिए, यह टाइप के नाम के किसी भी ऐसे हिस्से से मेल खाता है जिसमें पैकेज सेपरेटर (.) शामिल नहीं होते हैं
मेंबर स्पेसिफ़िकेशन के लिए, यह किसी भी तरीके या फ़ील्ड के नाम से मेल खाता है. इसका इस्तेमाल अकेले करने पर, यह ** का उपनाम भी होता है.
? दोनों क्लास या सदस्य के नाम में मौजूद किसी भी वर्ण से मेल खाता है.
*** सदस्य यह किसी भी टाइप से मेल खाता है. जैसे, प्रिमिटिव टाइप (जैसे, int), क्लास टाइप (जैसे, java.lang.String), और किसी भी डाइमेंशन के ऐरे टाइप (जैसे, byte[][]).
... सदस्य किसी तरीके के लिए पैरामीटर की किसी भी सूची से मेल खाता है.
% सदस्य किसी भी प्रिमिटिव टाइप (जैसे कि `int`, `float`, `boolean` या अन्य) से मेल खाता है.

खास वाइल्डकार्ड इस्तेमाल करने के कुछ उदाहरण यहां दिए गए हैं:

  • अगर आपके पास एक ही नाम वाले कई ऐसे तरीके हैं जो इनपुट के तौर पर अलग-अलग प्रिमिटिव टाइप लेते हैं, तो % का इस्तेमाल करके, एक ऐसा नियम लिखा जा सकता है जो उन सभी को बनाए रखता है. उदाहरण के लिए, इस DataStore क्लास में कई setValue तरीके हैं:

    class DataStore {
        fun setValue(key: String, value: Int) { ... }
        fun setValue(key: String, value: Boolean) { ... }
        fun setValue(key: String, value: Float) { ... }
    }
    

    'सुरक्षित रखें' नियम के तहत, सभी तरीकों को सुरक्षित रखा जाता है:

    -keep class com.example.DataStore {
        public void setValue(java.lang.String, %);
    }
    
  • अगर आपके पास ऐसी कई क्लास हैं जिनके नाम में सिर्फ़ एक वर्ण का अंतर है, तो उन सभी को बनाए रखने के लिए, ? का इस्तेमाल करके एक नियम लिखें. उदाहरण के लिए, अगर आपके पास ये क्लास हैं:

    com.example.models.UserV1 {...}
    com.example.models.UserV2 {...}
    com.example.models.UserV3 {...}
    

    यहां दिया गया कीप नियम, सभी क्लास को बनाए रखता है:

    -keep class com.example.models.UserV?
    
  • अगर आपको Example और AnotherExample क्लास (अगर वे रूट-लेवल की क्लास थीं) को मैच करना है, लेकिन com.foo.Example को नहीं, तो इस कीप नियम का इस्तेमाल करें:

    -keep class *Example
    
  • सिर्फ़ * का इस्तेमाल करने पर, यह ** के लिए एलियास के तौर पर काम करता है. उदाहरण के लिए, यहां दिए गए कीप नियम एक जैसे हैं:

    -keepclasseswithmembers class * { public static void main(java.lang.String[];) }
    
    -keepclasseswithmembers class ** { public static void main(java.lang.String[];) }
    

जनरेट किए गए Java नामों की जांच करना

नियम लिखते समय, आपको क्लास और अन्य रेफ़रंस टाइप के नाम बताने होंगे. ऐसा तब करना होगा, जब उन्हें Java बाइटकोड में कंपाइल कर लिया गया हो. उदाहरण के लिए, क्लास स्पेसिफ़िकेशन और टाइप देखें. अपने कोड के लिए जनरेट किए गए Java नामों का पता लगाने के लिए, Android Studio में इनमें से किसी एक टूल का इस्तेमाल करें:

  • APK ऐनालाइज़र
  • Kotlin सोर्स फ़ाइल खुली होने पर, बाइटकोड की जांच करें. इसके लिए, Tools > Kotlin > Show Kotlin Bytecode > Decompile पर जाएं.