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

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

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


-<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

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

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

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

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

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

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

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

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

क्लास स्पेसिफ़िकेशन में, यह भी बताया जाता है कि क्लास में किन सदस्यों को रखना है. इस नियम से, MaterialButton क्लास और उसके सभी सदस्यों को इन कार्रवाइयों से सुरक्षित रखा जाता है:

-keep class com.google.android.material.button.MaterialButton { *; }

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

किसी सबक्लास या इंटरफ़ेस को लागू करने वाली क्लास को टारगेट करने के लिए, क्रमशः 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
R8, -keep class * extends 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 f: Int
      internal fun m() {}
    }
    

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

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

    उदाहरण के लिए, अगर आपने 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(...);
    }
    

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

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

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

-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 *;
}

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

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

[<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>;

उदाहरण के लिए, यहां दिया गया keep नियम, 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 फ़ंक्शन का रेफ़रंस देना है, तो पक्का करें कि आपने 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);
}

प्रकार

इस सेक्शन में बताया गया है कि कीप रूल के सदस्य के स्पेसिफ़िकेशन में, रिटर्न टाइप, पैरामीटर टाइप, और फ़ील्ड टाइप कैसे तय किए जाते हैं. अगर टाइप, 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();
}

वाइल्डकार्ड

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

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