আপনার অ্যাপকে সঙ্কুচিত করুন, অস্পষ্ট করুন এবং অপ্টিমাইজ করুন

আপনার অ্যাপটিকে যতটা সম্ভব ছোট এবং দ্রুত করতে, আপনার রিলিজ বিল্ডটিকে isMinifyEnabled = true দিয়ে অপ্টিমাইজ করা এবং ছোট করা উচিত।

এটি করার ফলে সঙ্কুচিত হয়, যা অব্যবহৃত কোড এবং সংস্থানগুলিকে সরিয়ে দেয়; অস্পষ্টতা , যা আপনার অ্যাপের ক্লাস এবং সদস্যদের নাম ছোট করে; এবং অপ্টিমাইজেশান , যা আরও আক্রমনাত্মক কৌশল প্রয়োগ করে আকার আরও কমাতে এবং আপনার অ্যাপের কর্মক্ষমতা উন্নত করতে। এই পৃষ্ঠাটি বর্ণনা করে যে কীভাবে R8 আপনার প্রকল্পের জন্য এই কম্পাইল-টাইম কাজগুলি সম্পাদন করে এবং কীভাবে আপনি সেগুলি কাস্টমাইজ করতে পারেন।

আপনি যখন অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.4.0 বা উচ্চতর ব্যবহার করে আপনার প্রকল্প তৈরি করেন, তখন প্লাগইনটি আর কম্পাইল-টাইম কোড অপ্টিমাইজেশান সঞ্চালনের জন্য প্রোগার্ড ব্যবহার করে না। পরিবর্তে, প্লাগইন R8 কম্পাইলারের সাথে নিম্নলিখিত কম্পাইল-টাইম কাজগুলি পরিচালনা করতে কাজ করে:

  • কোড সঙ্কুচিত করা (বা ট্রি-কাঁপানো): আপনার অ্যাপ এবং এর লাইব্রেরি নির্ভরতা থেকে অব্যবহৃত ক্লাস, ক্ষেত্র, পদ্ধতি এবং বৈশিষ্ট্যগুলি সনাক্ত করে এবং নিরাপদে সরিয়ে দেয় (এটি 64k রেফারেন্স সীমার কাছাকাছি কাজ করার জন্য একটি মূল্যবান হাতিয়ার তৈরি করে)। উদাহরণস্বরূপ, যদি আপনি একটি লাইব্রেরি নির্ভরতার শুধুমাত্র কয়েকটি API ব্যবহার করেন, তাহলে সঙ্কুচিত লাইব্রেরি কোড সনাক্ত করতে পারে যা আপনার অ্যাপ ব্যবহার করছে না এবং আপনার অ্যাপ থেকে শুধুমাত্র সেই কোডটি সরিয়ে ফেলতে পারে। আরও জানতে, কীভাবে আপনার কোড সঙ্কুচিত করবেন সে সম্পর্কে বিভাগে যান।
  • রিসোর্স সঙ্কুচিত করা: আপনার প্যাকেজ করা অ্যাপ থেকে অব্যবহৃত সংস্থানগুলি সরিয়ে দেয়, আপনার অ্যাপের লাইব্রেরি নির্ভরতাগুলির অব্যবহৃত সংস্থানগুলি সহ। এটি কোড সঙ্কুচিত করার সাথে একত্রে কাজ করে যে একবার অব্যবহৃত কোড মুছে ফেলা হলে, যেকোন সংস্থান আর উল্লেখ করা হয় না নিরাপদে মুছে ফেলা যেতে পারে। আরও জানতে, কীভাবে আপনার সংস্থানগুলি সঙ্কুচিত করবেন সে সম্পর্কে বিভাগে যান৷
  • অপ্টিমাইজেশান: রানটাইম পারফরম্যান্স উন্নত করতে এবং আপনার অ্যাপের DEX ফাইলের আকার আরও কমাতে আপনার কোড পরিদর্শন করে এবং পুনর্লিখন করে। এটি কোডের রানটাইম কর্মক্ষমতা 30% পর্যন্ত উন্নত করে, স্টার্টআপ এবং ফ্রেমের সময়কে ব্যাপকভাবে উন্নত করে। উদাহরণস্বরূপ, যদি R8 সনাক্ত করে যে প্রদত্ত if/else স্টেটমেন্টের জন্য else {} শাখাটি কখনই নেওয়া হয় না, R8 else {} শাখার কোডটি সরিয়ে দেয়। আরও জানতে, কোড অপ্টিমাইজেশন সম্পর্কে বিভাগে যান।
  • অস্পষ্টতা (বা আইডেন্টিফায়ার মিনিফিকেশন): ক্লাস এবং সদস্যদের নাম ছোট করে, যার ফলে DEX ফাইলের আকার কমে যায়। আরও জানতে, কীভাবে আপনার কোড অস্পষ্ট করতে হয় সে বিষয়ে বিভাগে যান।

আপনার অ্যাপের রিলিজ সংস্করণ তৈরি করার সময়, R8 আপনার জন্য উপরে বর্ণিত কম্পাইল-টাইম কাজগুলি সম্পাদন করার জন্য কনফিগার করা যেতে পারে। এছাড়াও আপনি কিছু কাজ অক্ষম করতে পারেন বা ProGuard নিয়ম ফাইলের মাধ্যমে R8 এর আচরণ কাস্টমাইজ করতে পারেন। প্রকৃতপক্ষে, R8 আপনার সমস্ত বিদ্যমান ProGuard নিয়ম ফাইলগুলির সাথে কাজ করে , তাই R8 ব্যবহার করার জন্য Android Gradle প্লাগইন আপডেট করার জন্য আপনার বিদ্যমান নিয়মগুলি পরিবর্তন করার প্রয়োজন হবে না৷

সঙ্কুচিত, অস্পষ্টতা এবং অপ্টিমাইজেশান সক্ষম করুন৷

আপনি যখন অ্যান্ড্রয়েড স্টুডিও 3.4 বা অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.4.0 এবং উচ্চতর ব্যবহার করেন, তখন R8 হল ডিফল্ট কম্পাইলার যা আপনার প্রোজেক্টের জাভা বাইটকোডকে DEX ফর্ম্যাটে রূপান্তর করে যা অ্যান্ড্রয়েড প্ল্যাটফর্মে চলে৷ যাইহোক, যখন আপনি অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে একটি নতুন প্রজেক্ট তৈরি করেন, তখন ডিফল্টরূপে সঙ্কুচিত, অস্পষ্টতা এবং কোড অপ্টিমাইজেশান সক্ষম হয় না। কারণ এই কম্পাইল-টাইম অপ্টিমাইজেশানগুলি আপনার প্রোজেক্টের বিল্ড টাইম বাড়িয়ে দেয় এবং আপনি যদি কোন কোডটি রাখতে হবে তা পর্যাপ্তভাবে কাস্টমাইজ না করলে বাগ প্রবর্তন করতে পারে।

সুতরাং, আপনার অ্যাপের চূড়ান্ত সংস্করণ তৈরি করার সময় এই কম্পাইল-টাইম কাজগুলিকে সক্ষম করা ভাল যা আপনি প্রকাশের আগে পরীক্ষা করেন৷ সংকোচন, অস্পষ্টতা এবং অপ্টিমাইজেশন সক্ষম করতে, আপনার প্রকল্প-স্তরের বিল্ড স্ক্রিপ্টে নিম্নলিখিতগুলি অন্তর্ভুক্ত করুন।

কোটলিন

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, বা আপনার অ্যাপের লাইব্রেরি নির্ভরতা থেকে উত্তরাধিকারসূত্রে প্রাপ্ত। নীচের টেবিলটি R8 ব্যবহার করে ProGuard নিয়ম ফাইলগুলির উত্স বর্ণনা করে।

উৎস অবস্থান বর্ণনা
অ্যান্ড্রয়েড স্টুডিও <module-dir>/proguard-rules.pro আপনি যখন Android Studio ব্যবহার করে একটি নতুন মডিউল তৈরি করেন, তখন IDE সেই মডিউলের রুট ডিরেক্টরিতে একটি proguard-rules.pro ফাইল তৈরি করে।

ডিফল্টরূপে, এই ফাইলটি কোনো নিয়ম প্রয়োগ করে না। সুতরাং, এখানে আপনার নিজস্ব ProGuard নিয়ম অন্তর্ভুক্ত করুন, যেমন আপনার কাস্টম রাখা নিয়ম

অ্যান্ড্রয়েড গ্রেডল প্লাগইন কম্পাইলের সময়ে অ্যান্ড্রয়েড গ্রেডল প্লাগইন দ্বারা উত্পন্ন। অ্যান্ড্রয়েড গ্রেডল প্লাগইন proguard-android-optimize.txt তৈরি করে, যার মধ্যে এমন নিয়ম রয়েছে যা বেশিরভাগ অ্যান্ড্রয়েড প্রোজেক্টের জন্য উপযোগী এবং @Keep* টীকা সক্ষম করে।

ডিফল্টরূপে, অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে একটি নতুন মডিউল তৈরি করার সময়, মডিউল-স্তরের বিল্ড স্ক্রিপ্ট আপনার জন্য আপনার রিলিজ বিল্ডে এই নিয়ম ফাইলটি অন্তর্ভুক্ত করে।

দ্রষ্টব্য: অ্যান্ড্রয়েড গ্রেডল প্লাগইনে অতিরিক্ত পূর্বনির্ধারিত ProGuard নিয়মের ফাইল অন্তর্ভুক্ত রয়েছে, তবে আপনাকে proguard-android-optimize.txt ব্যবহার করার পরামর্শ দেওয়া হচ্ছে।

লাইব্রেরি নির্ভরতা

একটি AAR লাইব্রেরিতে:
proguard.txt

একটি JAR লাইব্রেরিতে:
META-INF/proguard/<ProGuard-rules-file>

এই অবস্থানগুলি ছাড়াও, Android Gradle প্লাগইন 3.6 বা উচ্চতর এছাড়াও লক্ষ্যযুক্ত সঙ্কুচিত নিয়মগুলিকে সমর্থন করে৷

যদি একটি AAR বা JAR লাইব্রেরি তার নিজস্ব নিয়ম ফাইলের সাথে প্রকাশিত হয়, এবং আপনি সেই লাইব্রেরিটিকে একটি কম্পাইল-টাইম নির্ভরতা হিসাবে অন্তর্ভুক্ত করেন, R8 স্বয়ংক্রিয়ভাবে আপনার প্রকল্প কম্পাইল করার সময় সেই নিয়মগুলি প্রয়োগ করে।

প্রচলিত ProGuard নিয়মগুলি ছাড়াও, Android Gradle প্লাগইন 3.6 বা উচ্চতর এছাড়াও লক্ষ্যযুক্ত সঙ্কুচিত নিয়মগুলিকে সমর্থন করে৷ এগুলি এমন নিয়ম যা নির্দিষ্ট সঙ্কুচিতকারী (R8 বা ProGuard) এবং সেইসাথে নির্দিষ্ট সংকোচনকারী সংস্করণগুলিকে লক্ষ্য করে।

লাইব্রেরিগুলির সাথে প্যাকেজ করা নিয়ম ফাইলগুলি ব্যবহার করা দরকারী যদি লাইব্রেরির সঠিকভাবে কাজ করার জন্য কিছু নিয়মের প্রয়োজন হয়—অর্থাৎ, লাইব্রেরি বিকাশকারী আপনার জন্য সমস্যা সমাধানের পদক্ষেপগুলি সম্পাদন করেছে৷

যাইহোক, আপনার সচেতন হওয়া উচিত যে, নিয়মগুলি সংযোজিত হওয়ার কারণে, লাইব্রেরি নির্ভরতা অন্তর্ভুক্ত করে এমন কিছু নিয়ম সরানো যায় না এবং আপনার অ্যাপের অন্যান্য অংশগুলির সংকলনকে প্রভাবিত করতে পারে৷ উদাহরণস্বরূপ, যদি একটি লাইব্রেরিতে কোড অপ্টিমাইজেশন অক্ষম করার জন্য একটি নিয়ম অন্তর্ভুক্ত থাকে, তবে সেই নিয়মটি আপনার সম্পূর্ণ প্রকল্পের জন্য অপ্টিমাইজেশন অক্ষম করে।

অ্যান্ড্রয়েড অ্যাসেট প্যাকেজ টুল 2 (AAPT2) minifyEnabled true : <module-dir>/build/intermediates/aapt_proguard_file/.../aapt_rules.txt দিয়ে আপনার প্রকল্প তৈরি করার পর AAPT2 আপনার অ্যাপের ম্যানিফেস্ট, লেআউট এবং অন্যান্য অ্যাপ রিসোর্সে ক্লাসের রেফারেন্সের উপর ভিত্তি করে নিয়মগুলি তৈরি করে। উদাহরণস্বরূপ, AAPT2 প্রতিটি কার্যকলাপের জন্য একটি রাখার নিয়ম অন্তর্ভুক্ত করে যা আপনি একটি এন্ট্রি পয়েন্ট হিসাবে আপনার অ্যাপের ম্যানিফেস্টে নিবন্ধন করেন।
কাস্টম কনফিগারেশন ফাইল ডিফল্টরূপে, আপনি যখন অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে একটি নতুন মডিউল তৈরি করেন, তখন 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

টার্গেটেড সঙ্কুচিত নিয়ম

অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.6 বা উচ্চতর লাইব্রেরির নিয়মগুলিকে সমর্থন করে যা নির্দিষ্ট সংকোচনকারী (R8 বা ProGuard) এবং সেইসাথে নির্দিষ্ট সংকোচনকারী সংস্করণগুলিকে লক্ষ্য করে। এটি লাইব্রেরি ডেভেলপারদের নতুন সঙ্কুচিত সংস্করণগুলি ব্যবহার করে এমন প্রকল্পগুলিতে সর্বোত্তমভাবে কাজ করার জন্য তাদের নিয়মগুলি তৈরি করতে দেয়, যেখানে বিদ্যমান নিয়মগুলি পুরানো সঙ্কুচিত সংস্করণগুলির সাথে প্রকল্পগুলিতে ব্যবহার করা চালিয়ে যাওয়ার অনুমতি দেয়৷

লক্ষ্যযুক্ত সঙ্কুচিত নিয়মগুলি নির্দিষ্ট করার জন্য, লাইব্রেরি বিকাশকারীদের একটি AAR বা JAR লাইব্রেরির মধ্যে নির্দিষ্ট স্থানে সেগুলি অন্তর্ভুক্ত করতে হবে, যেমন নীচে বর্ণিত হয়েছে৷

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 অন্তর্ভুক্ত নয়

সেই তথ্যের প্রেক্ষিতে, Android Gradle প্লাগইন 3.6 বা উচ্চতর মান R8 ডিরেক্টরি থেকে নিয়মগুলি নির্বাচন করবে। যদি একটি লাইব্রেরি টার্গেটেড সঙ্কুচিত নিয়মগুলি নির্দিষ্ট না করে, তাহলে Android Gradle প্লাগইন লিগ্যাসি অবস্থানগুলি থেকে নিয়মগুলি নির্বাচন করবে (একটি AAR এর জন্য proguard.txt বা META-INF/proguard/<ProGuard-rules-file> একটি JAR এর জন্য)।

লাইব্রেরি ডেভেলপাররা তাদের লাইব্রেরিতে হয় টার্গেটেড সঙ্কুচিত নিয়ম বা লিগ্যাসি ProGuard নিয়ম অন্তর্ভুক্ত করতে বেছে নিতে পারেন, অথবা যদি তারা 3.6-এর থেকে পুরানো অ্যান্ড্রয়েড গ্রেডল প্লাগইনের সাথে সামঞ্জস্য বজায় রাখতে চান তবে উভয় প্রকার।

অতিরিক্ত কনফিগারেশন অন্তর্ভুক্ত করুন

আপনি যখন অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে একটি নতুন প্রজেক্ট বা মডিউল তৈরি করেন, তখন IDE একটি <module-dir>/proguard-rules.pro ফাইল তৈরি করে যাতে আপনার নিজের নিয়মগুলি অন্তর্ভুক্ত করা যায়। আপনি আপনার মডিউলের বিল্ড স্ক্রিপ্টে proguardFiles সম্পত্তিতে যোগ করে অন্যান্য ফাইল থেকে অতিরিক্ত নিয়মগুলিও অন্তর্ভুক্ত করতে পারেন।

উদাহরণ স্বরূপ, আপনি সংশ্লিষ্ট productFlavor ব্লকে অন্য proguardFiles প্রপার্টি যোগ করে প্রতিটি বিল্ড ভেরিয়েন্টের জন্য নির্দিষ্ট নিয়ম যোগ করতে পারেন। নিম্নলিখিত Gradle ফাইলটি flavor2 পণ্যের স্বাদে flavor2-rules.pro যোগ করে। এখন, flavor2 তিনটি প্রোগার্ড নিয়ম ব্যবহার করে কারণ release ব্লক থেকেও প্রয়োগ করা হয়।

উপরন্তু, আপনি testProguardFiles প্রপার্টি যোগ করতে পারেন, যা ProGuard ফাইলগুলির একটি তালিকা নির্দিষ্ট করে যা শুধুমাত্র টেস্ট APK-এ অন্তর্ভুক্ত করা হয়েছে:

কোটলিন

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 নির্ধারণ করে যে রানটাইমের প্রয়োজন হয় না। এই প্রক্রিয়াটি আপনার অ্যাপের আকারকে ব্যাপকভাবে হ্রাস করতে পারে যদি, উদাহরণস্বরূপ, আপনার অ্যাপটিতে অনেকগুলি লাইব্রেরি নির্ভরতা অন্তর্ভুক্ত থাকে তবে তাদের কার্যকারিতার একটি ছোট অংশ ব্যবহার করে।

আপনার অ্যাপের কোড সঙ্কুচিত করার জন্য, R8 প্রথমে কনফিগারেশন ফাইলের সম্মিলিত সেটের উপর ভিত্তি করে আপনার অ্যাপের কোডে সমস্ত এন্ট্রি পয়েন্ট নির্ধারণ করে। এই এন্ট্রি পয়েন্টগুলিতে সমস্ত ক্লাস অন্তর্ভুক্ত রয়েছে যা Android প্ল্যাটফর্ম আপনার অ্যাপের কার্যকলাপ বা পরিষেবাগুলি খুলতে ব্যবহার করতে পারে৷ প্রতিটি এন্ট্রি পয়েন্ট থেকে শুরু করে, R8 সমস্ত পদ্ধতি, সদস্য ভেরিয়েবল এবং আপনার অ্যাপ রানটাইমে অ্যাক্সেস করতে পারে এমন অন্যান্য ক্লাসের একটি গ্রাফ তৈরি করতে আপনার অ্যাপের কোড পরীক্ষা করে। যে কোডটি সেই গ্রাফের সাথে সংযুক্ত নয় সেটিকে পৌঁছানো যায় না বলে মনে করা হয় এবং অ্যাপ থেকে সরানো হতে পারে।

চিত্র 1 রানটাইম লাইব্রেরি নির্ভরতা সহ একটি অ্যাপ দেখায়। অ্যাপের কোড পরিদর্শন করার সময়, R8 নির্ধারণ করে যে মেথড foo() , faz() , এবং bar() MainActivity.class এন্ট্রি পয়েন্ট থেকে পৌঁছানো যায়। যাইহোক, ক্লাস OkayApi.class বা এর মেথড baz() কখনই আপনার অ্যাপ রানটাইমে ব্যবহার করে না এবং আপনার অ্যাপ সঙ্কুচিত করার সময় R8 সেই কোডটি সরিয়ে দেয়।

চিত্র 1. কম্পাইল-টাইমে, R8 আপনার প্রজেক্টের সম্মিলিত রাখা নিয়মের উপর ভিত্তি করে একটি গ্রাফ তৈরি করে যাতে নাগালযোগ্য কোড নির্ধারণ করা যায়।

R8 প্রজেক্টের R8 কনফিগারেশন ফাইলে -keep নিয়মের মাধ্যমে এন্ট্রি পয়েন্ট নির্ধারণ করে। অর্থাৎ, আপনার অ্যাপ সঙ্কুচিত করার সময় R8 বর্জন করা উচিত নয় এমন ক্লাসগুলি নির্দিষ্ট করে রাখুন, এবং R8 সেই ক্লাসগুলিকে আপনার অ্যাপে সম্ভাব্য প্রবেশ পয়েন্ট হিসাবে বিবেচনা করে। অ্যান্ড্রয়েড গ্রেডল প্লাগইন এবং AAPT2 স্বয়ংক্রিয়ভাবে এমন নিয়ম তৈরি করে যা আপনার জন্য বেশিরভাগ অ্যাপ প্রকল্পের জন্য প্রয়োজনীয়, যেমন আপনার অ্যাপের কার্যকলাপ, দর্শন এবং পরিষেবাগুলি। যাইহোক, যদি আপনাকে অতিরিক্ত রাখার নিয়মগুলির সাথে এই ডিফল্ট আচরণটি কাস্টমাইজ করতে হয় তবে কোন কোডটি রাখতে হবে তা কীভাবে কাস্টমাইজ করবেন সে সম্পর্কে বিভাগটি পড়ুন।

পরিবর্তে আপনি যদি শুধুমাত্র আপনার অ্যাপের সংস্থানগুলির আকার কমাতে আগ্রহী হন, তাহলে কীভাবে আপনার সংস্থানগুলি সঙ্কুচিত করবেন সে সম্পর্কে বিভাগে যান৷

মনে রাখবেন যে একটি লাইব্রেরি প্রকল্প সঙ্কুচিত হলে, সেই লাইব্রেরির উপর নির্ভর করে এমন একটি অ্যাপ সঙ্কুচিত লাইব্রেরি ক্লাস অন্তর্ভুক্ত করে। লাইব্রেরি APK-এ অনুপস্থিত ক্লাস থাকলে আপনাকে লাইব্রেরি রাখার নিয়মগুলি সামঞ্জস্য করতে হতে পারে। আপনি যদি AAR বিন্যাসে একটি লাইব্রেরি তৈরি এবং প্রকাশ করেন, আপনার লাইব্রেরির উপর নির্ভর করে এমন স্থানীয় JAR ফাইলগুলি AAR ফাইলে সঙ্কুচিত হয় না

কোন কোড রাখতে হবে তা কাস্টমাইজ করুন

বেশিরভাগ পরিস্থিতিতে, ডিফল্ট ProGuard নিয়ম ফাইল ( proguard-android-optimize.txt ) শুধুমাত্র অব্যবহৃত কোড অপসারণের জন্য R8 এর জন্য যথেষ্ট। যাইহোক, কিছু পরিস্থিতিতে R8 এর পক্ষে সঠিকভাবে বিশ্লেষণ করা কঠিন এবং এটি আপনার অ্যাপের প্রকৃতপক্ষে প্রয়োজনীয় কোডগুলি সরিয়ে ফেলতে পারে। যখন এটি ভুলভাবে কোড মুছে ফেলতে পারে তার কিছু উদাহরণ অন্তর্ভুক্ত:

  • যখন আপনার অ্যাপ জাভা নেটিভ ইন্টারফেস (JNI) থেকে একটি পদ্ধতি কল করে
  • যখন আপনার অ্যাপ রানটাইমে কোড দেখায় (যেমন প্রতিফলন সহ)

আপনার অ্যাপ পরীক্ষা করলে অনুপযুক্তভাবে সরানো কোডের কারণে সৃষ্ট কোনো ত্রুটি প্রকাশ করা উচিত, তবে আপনি সরানো কোডের একটি প্রতিবেদন তৈরি করে কোন কোডটি সরানো হয়েছে তাও পরিদর্শন করতে পারেন।

ত্রুটিগুলি ঠিক করতে এবং R8 কে নির্দিষ্ট কোড রাখতে বাধ্য করতে, ProGuard নিয়ম ফাইলে একটি -keep লাইন যোগ করুন। যেমন:

-keep public class MyClass

বিকল্পভাবে, আপনি যে কোডটি রাখতে চান তাতে @Keep টীকা যোগ করতে পারেন। একটি ক্লাসে @Keep যোগ করা পুরো ক্লাসটিকে যেমন আছে তেমন রাখে। এটি একটি পদ্ধতি বা ক্ষেত্রে যোগ করা পদ্ধতি/ক্ষেত্র (এবং এর নাম) পাশাপাশি ক্লাসের নাম অক্ষত রাখবে। মনে রাখবেন যে এই টীকাটি শুধুমাত্র AndroidX অ্যানোটেশন লাইব্রেরি ব্যবহার করার সময় পাওয়া যায় এবং যখন আপনি Android Gradle প্লাগইন দিয়ে প্যাকেজ করা ProGuard নিয়ম ফাইলটি অন্তর্ভুক্ত করেন, যেমন সঙ্কুচিত কিভাবে সক্ষম করবেন সে বিষয়ে বিভাগে বর্ণিত আছে।

-keep বিকল্পটি ব্যবহার করার সময় আপনার অনেক বিবেচনা করা উচিত; আপনার নিয়ম ফাইল কাস্টমাইজ করার বিষয়ে আরও তথ্যের জন্য, ProGuard ম্যানুয়াল পড়ুন। ট্রাবলশুটিং বিভাগটি অন্যান্য সাধারণ সমস্যার রূপরেখা দেয় যা আপনি সম্মুখীন হতে পারেন যখন আপনার কোডটি ছিনিয়ে নেওয়া হয়।

স্ট্রিপ নেটিভ লাইব্রেরি

ডিফল্টরূপে, নেটিভ কোড লাইব্রেরিগুলি আপনার অ্যাপের রিলিজ বিল্ডে ছিনতাই করা হয়। এই স্ট্রিপিংটিতে আপনার অ্যাপের দ্বারা ব্যবহৃত যেকোন নেটিভ লাইব্রেরিতে থাকা প্রতীক টেবিল এবং ডিবাগিং তথ্য অপসারণ করা হয়। নেটিভ কোড লাইব্রেরি খুলে ফেলার ফলে উল্লেখযোগ্য আকার সঞ্চয় হয়; যাইহোক, অনুপস্থিত তথ্যের (যেমন ক্লাস এবং ফাংশনের নাম) কারণে Google Play কনসোলে ক্র্যাশ নির্ণয় করা অসম্ভব।

নেটিভ ক্র্যাশ সমর্থন

Google Play Console Android ভাইটালগুলির অধীনে নেটিভ ক্র্যাশ রিপোর্ট করে৷ কয়েকটি ধাপে, আপনি আপনার অ্যাপের জন্য একটি নেটিভ ডিবাগ সিম্বল ফাইল তৈরি এবং আপলোড করতে পারেন। এই ফাইলটি আপনাকে আপনার অ্যাপকে প্রোডাকশনে ডিবাগ করতে সাহায্য করার জন্য অ্যান্ড্রয়েড ভাইটালগুলিতে সিম্বলিকেটেড নেটিভ ক্র্যাশ স্ট্যাক ট্রেস (যার মধ্যে ক্লাস এবং ফাংশনের নাম অন্তর্ভুক্ত) সক্ষম করে। আপনার প্রকল্পে ব্যবহৃত অ্যান্ড্রয়েড গ্রেডল প্লাগইনের সংস্করণ এবং আপনার প্রকল্পের বিল্ড আউটপুটের উপর নির্ভর করে এই পদক্ষেপগুলি পরিবর্তিত হয়।

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-এ নেটিভ ডিবাগ সিম্বল ফাইল ম্যানুয়ালি আপলোড করুন । বিল্ড প্রক্রিয়ার অংশ হিসাবে, অ্যান্ড্রয়েড গ্রেডল প্লাগইন এই ফাইলটিকে নিম্নলিখিত প্রকল্পের অবস্থানে আউটপুট করে:

app/build/outputs/native-debug-symbols/ variant-name /native-debug-symbols.zip

Android Gradle প্লাগইন সংস্করণ 4.0 বা তার আগের (এবং অন্যান্য বিল্ড সিস্টেম)

বিল্ড প্রক্রিয়ার অংশ হিসাবে, অ্যান্ড্রয়েড গ্রেডল প্লাগইন একটি প্রকল্প ডিরেক্টরিতে আনস্ট্রিপড লাইব্রেরিগুলির একটি অনুলিপি রাখে। এই ডিরেক্টরি গঠন নিম্নলিখিত অনুরূপ:

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
  1. এই ডিরেক্টরির বিষয়বস্তু জিপ আপ করুন:

    cd app/build/intermediates/cmake/universal/release/obj
    zip -r symbols.zip .
    
  2. Google Play Console-এ ম্যানুয়ালি symbols.zip ফাইল আপলোড করুন

আপনার সম্পদ সঙ্কুচিত

সম্পদ সঙ্কুচিত করা শুধুমাত্র কোড সঙ্কুচিত করার সাথে একত্রে কাজ করে। কোড সঙ্কুচিত সমস্ত অব্যবহৃত কোড মুছে ফেলার পরে, সংস্থান সংকোচকারী সনাক্ত করতে পারে যে অ্যাপটি এখনও কোন সংস্থান ব্যবহার করে। এটি বিশেষভাবে সত্য যখন আপনি কোড লাইব্রেরি যোগ করেন যাতে সম্পদ অন্তর্ভুক্ত থাকে—আপনাকে অবশ্যই অব্যবহৃত লাইব্রেরি কোড মুছে ফেলতে হবে যাতে লাইব্রেরি সংস্থানগুলি রেফারেন্সবিহীন হয়ে যায় এবং এইভাবে, রিসোর্স সঙ্কুচিত করে অপসারণযোগ্য।

রিসোর্স সঙ্কুচিত করা সক্ষম করতে, আপনার বিল্ড স্ক্রিপ্টে (কোড সঙ্কুচিত করার জন্য minifyEnabled এর পাশাপাশি) shrinkResources বৈশিষ্ট্যটিকে true হিসাবে সেট করুন। যেমন:

কোটলিন

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> ট্যাগ দিয়ে একটি XML ফাইল তৈরি করুন এবং প্রতিটি রিসোর্সকে 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 ফাইলের জন্য একটি অনন্য নাম ব্যবহার করতে ভুলবেন না। যখন বিভিন্ন লাইব্রেরি একসাথে সংযুক্ত হয় তখন তাদের রাখার নিয়মগুলি অন্যথায় বিরোধিতা করবে, উপেক্ষা করা নিয়ম বা অপ্রয়োজনীয় সংরক্ষিত সংস্থানগুলির সাথে সম্ভাব্য সমস্যা সৃষ্টি করবে।

কোন সংস্থানগুলি বাতিল করতে হবে তা উল্লেখ করা নির্বোধ বলে মনে হতে পারে যখন আপনি সেগুলি মুছে ফেলতে পারেন, তবে বিল্ড ভেরিয়েন্টগুলি ব্যবহার করার সময় এটি কার্যকর হতে পারে। উদাহরণস্বরূপ, আপনি সাধারণ প্রকল্প ডিরেক্টরিতে আপনার সমস্ত সংস্থান রাখতে পারেন, তারপর প্রতিটি বিল্ড ভেরিয়েন্টের জন্য একটি আলাদা 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 প্রপার্টি ব্যবহার করতে পারেন।

উদাহরণস্বরূপ, আপনি যদি এমন একটি লাইব্রেরি ব্যবহার করেন যাতে ভাষা সংস্থানগুলি অন্তর্ভুক্ত থাকে (যেমন অ্যাপকম্প্যাট বা Google Play পরিষেবাগুলি), তাহলে আপনার অ্যাপটি সেই লাইব্রেরির বার্তাগুলির জন্য সমস্ত অনুবাদিত ভাষা স্ট্রিং অন্তর্ভুক্ত করে তা আপনার বাকি অ্যাপ একই ভাষায় অনুবাদ করা হোক বা না আপনি যদি শুধুমাত্র সেই ভাষাগুলি রাখতে চান যেগুলি আপনার অ্যাপ আনুষ্ঠানিকভাবে সমর্থন করে, আপনি resConfig বৈশিষ্ট্য ব্যবহার করে সেই ভাষাগুলি নির্দিষ্ট করতে পারেন৷ নির্দিষ্ট না করা ভাষার জন্য কোনো সংস্থান সরানো হয়।

নিম্নলিখিত স্নিপেটটি দেখায় যে কীভাবে আপনার ভাষা সংস্থানগুলিকে শুধুমাত্র ইংরেজি এবং ফরাসি ভাষায় সীমাবদ্ধ করবেন:

কোটলিন

android {
    defaultConfig {
        ...
        resourceConfigurations.addAll(listOf("en", "fr"))
    }
}

গ্রোভি

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

অ্যান্ড্রয়েড অ্যাপ বান্ডেল ফর্ম্যাট ব্যবহার করে কোনও অ্যাপ প্রকাশ করার সময়, অ্যাপটি ইনস্টল করার সময় ডিফল্টরূপে শুধুমাত্র ব্যবহারকারীর ডিভাইসে কনফিগার করা ভাষাগুলি ডাউনলোড করা হয়। একইভাবে, শুধুমাত্র ডিভাইসের স্ক্রীনের ঘনত্বের সাথে মেলে এবং ডিভাইসের ABI-এর সাথে মেলে এমন নেটিভ লাইব্রেরিগুলি ডাউনলোডে অন্তর্ভুক্ত করা হয়েছে। আরও তথ্যের জন্য অ্যান্ড্রয়েড অ্যাপ বান্ডেল কনফিগারেশন পড়ুন।

APK-এর সাথে রিলিজ করা লিগ্যাসি অ্যাপগুলির জন্য (আগস্ট 2021 সালের আগে তৈরি), আপনি একাধিক APK তৈরি করে আপনার APK-এ কোন স্ক্রীনের ঘনত্ব বা ABI রিসোর্স অন্তর্ভুক্ত করতে হবে তা কাস্টমাইজ করতে পারেন যেগুলি প্রতিটি আলাদা ডিভাইস কনফিগারেশনকে লক্ষ্য করে।

ডুপ্লিকেট সম্পদ একত্রীকরণ

ডিফল্টরূপে, গ্রেডল অভিন্ন নামযুক্ত সংস্থানগুলিকে একত্রিত করে, যেমন একই নামের অঙ্কনযোগ্য যা বিভিন্ন সংস্থান ফোল্ডারে থাকতে পারে। এই আচরণটি shrinkResources সম্পত্তি দ্বারা নিয়ন্ত্রিত হয় না এবং নিষ্ক্রিয় করা যায় না, কারণ একাধিক সংস্থান আপনার কোডের নামের সাথে মেলে তখন ত্রুটি এড়াতে হবে।

রিসোর্স মার্জিং তখনই ঘটে যখন দুই বা ততোধিক ফাইল একটি অভিন্ন রিসোর্স নাম, প্রকার এবং কোয়ালিফায়ার ভাগ করে। Gradle কোন ফাইলটিকে ডুপ্লিকেটের মধ্যে সেরা পছন্দ বলে মনে করে তা নির্বাচন করে (নীচে বর্ণিত একটি অগ্রাধিকারের ভিত্তিতে) এবং চূড়ান্ত শিল্পকর্মে বিতরণের জন্য শুধুমাত্র একটি সংস্থান AAPT-কে পাস করে।

Gradle নিম্নলিখিত অবস্থানগুলিতে সদৃশ সংস্থানগুলি সন্ধান করে:

  • প্রধান সংস্থান, প্রধান উৎস সেটের সাথে যুক্ত, সাধারণত src/main/res/ তে অবস্থিত।
  • ভেরিয়েন্ট ওভারলে, বিল্ড টাইপ এবং বিল্ড ফ্লেভার থেকে।
  • লাইব্রেরি প্রকল্প নির্ভরতা.

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 স্টুডিও টিমকে আপনার সম্মুখীন হতে পারে এমন যেকোনো সমস্যা সহজেই সমাধান করতে এবং সমাধান করতে সহায়তা করে।

মনে রাখবেন যে অপ্টিমাইজেশান সক্ষম করা আপনার অ্যাপ্লিকেশনের জন্য স্ট্যাক ট্রেস পরিবর্তন করবে। উদাহরণস্বরূপ, ইনলাইনিং স্ট্যাক ফ্রেম মুছে ফেলবে। মূল স্ট্যাক ট্রেসগুলি কীভাবে পেতে হয় তা শিখতে রিট্রেসিংয়ের বিভাগটি দেখুন।

রানটাইম কর্মক্ষমতা উপর প্রভাব

সঙ্কুচিত করা, অস্পষ্টতা এবং অপ্টিমাইজেশান সবই সক্ষম থাকলে, R8 কোডের রানটাইম কর্মক্ষমতা (ইউআই থ্রেডে স্টার্টআপ এবং ফ্রেম টাইম সহ) 30% পর্যন্ত উন্নত করবে। এইগুলির যেকোনো একটি নিষ্ক্রিয় করা R8 ব্যবহার করা অপ্টিমাইজেশানগুলির সেটকে মারাত্মকভাবে সীমাবদ্ধ করে।

যদি R8 সক্ষম করা থাকে, তাহলে আরও ভাল স্টার্টআপ পারফরম্যান্সের জন্য আপনার স্টার্টআপ প্রোফাইলগুলিও তৈরি করা উচিত।

আরো আক্রমনাত্মক অপ্টিমাইজেশান সক্ষম করুন

R8 অতিরিক্ত অপ্টিমাইজেশনের একটি সেট অন্তর্ভুক্ত করে ("সম্পূর্ণ মোড" হিসাবে উল্লেখ করা হয়) যা এটিকে ProGuard থেকে ভিন্নভাবে আচরণ করে। অ্যান্ড্রয়েড গ্রেডল প্লাগইন সংস্করণ 8.0.0 থেকে এই অপ্টিমাইজেশনগুলি ডিফল্টরূপে সক্রিয় করা হয়েছে।

আপনি আপনার প্রকল্পের gradle.properties ফাইলে নিম্নলিখিতগুলি অন্তর্ভুক্ত করে এই অতিরিক্ত অপ্টিমাইজেশানগুলি অক্ষম করতে পারেন:

android.enableR8.fullMode=false

যেহেতু অতিরিক্ত অপ্টিমাইজেশানগুলি R8 কে ProGuard থেকে ভিন্নভাবে আচরণ করে, তাই আপনি যদি ProGuard-এর জন্য ডিজাইন করা নিয়মগুলি ব্যবহার করেন তবে রানটাইম সমস্যা এড়াতে আপনাকে অতিরিক্ত ProGuard নিয়মগুলি অন্তর্ভুক্ত করতে হতে পারে৷ উদাহরণস্বরূপ, বলুন যে আপনার কোড জাভা প্রতিফলন API এর মাধ্যমে একটি ক্লাস উল্লেখ করে। "সম্পূর্ণ মোড" ব্যবহার না করার সময়, R8 অনুমান করে যে আপনি রানটাইমে সেই ক্লাসের বস্তুগুলি পরীক্ষা এবং ম্যানিপুলেট করতে চান-এমনকি যদি আপনার কোডটি আসলে নাও থাকে-এবং এটি স্বয়ংক্রিয়ভাবে ক্লাস এবং এর স্ট্যাটিক ইনিশিয়ালাইজারকে রাখে।

যাইহোক, "ফুল মোড" ব্যবহার করার সময়, R8 এই অনুমান করে না এবং, যদি R8 দৃঢ় করে যে আপনার কোড অন্যথায় রানটাইমে কখনই ক্লাস ব্যবহার করে না, এটি আপনার অ্যাপের চূড়ান্ত DEX থেকে ক্লাসটি সরিয়ে দেয়। অর্থাৎ, আপনি যদি ক্লাস এবং এর স্ট্যাটিক ইনিশিয়ালাইজার রাখতে চান, তাহলে সেটি করার জন্য আপনাকে আপনার নিয়ম ফাইলে একটি Keep নিয়ম অন্তর্ভুক্ত করতে হবে।

আপনি যদি R8 এর "ফুল মোড" ব্যবহার করার সময় কোন সমস্যার সম্মুখীন হন, তাহলে সম্ভাব্য সমাধানের জন্য R8 FAQ পৃষ্ঠা দেখুন। আপনি সমস্যা সমাধান করতে অক্ষম হলে, একটি বাগ রিপোর্ট করুন .

স্ট্যাকট্রেস রিট্রেসিং

R8 দ্বারা প্রক্রিয়াকৃত কোড বিভিন্ন উপায়ে পরিবর্তিত হয় যা স্ট্যাক ট্রেসগুলি বোঝা কঠিন করে তোলে কারণ স্ট্যাক ট্রেসগুলি উত্স কোডের সাথে ঠিক মিলবে না। ডিবাগিং তথ্য রাখা না থাকলে লাইন নম্বর পরিবর্তনের ক্ষেত্রে এটি হতে পারে। এটি ইনলাইনিং এবং আউটলাইনিংয়ের মতো অপ্টিমাইজেশনের কারণে হতে পারে। সবচেয়ে বড় অবদান হল অস্পষ্টতা যেখানে এমনকি ক্লাস এবং পদ্ধতির নাম পরিবর্তন হবে।

মূল স্ট্যাক ট্রেস পুনরুদ্ধার করতে, R8 রিট্রেস কমান্ড-লাইন টুল প্রদান করে, যা কমান্ড-লাইন টুলস প্যাকেজের সাথে বান্ডিল করা হয়।

আপনার অ্যাপ্লিকেশানের স্ট্যাক ট্রেসগুলির পুনঃট্রেসিংকে সমর্থন করার জন্য, আপনার মডিউলের proguard-rules.pro ফাইলে নিম্নলিখিত নিয়মগুলি যোগ করে বিল্ডটি রিট্রেস করার জন্য পর্যাপ্ত তথ্য বজায় রাখে তা নিশ্চিত করা উচিত:

-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile

LineNumberTable অ্যাট্রিবিউট পদ্ধতিতে অবস্থানগত তথ্য ধরে রাখে যাতে সেই অবস্থানগুলি স্ট্যাক ট্রেসে মুদ্রিত হয়। SourceFile অ্যাট্রিবিউট নিশ্চিত করে যে সমস্ত সম্ভাব্য রানটাইম প্রকৃতপক্ষে অবস্থানগত তথ্য মুদ্রণ করে। -renamesourcefileattribute নির্দেশিকা স্ট্যাক ট্রেসে সোর্স ফাইলের নামকে শুধুমাত্র SourceFile এ সেট করে। রিট্রেস করার সময় প্রকৃত মূল উৎস ফাইলের নাম প্রয়োজন হয় না কারণ ম্যাপিং ফাইলে মূল উৎস ফাইল থাকে।

R8 প্রতিবার এটি চালানোর সময় একটি mapping.txt ফাইল তৈরি করে, যাতে স্ট্যাক ট্রেসগুলিকে মূল স্ট্যাকের ট্রেসে ফিরে ম্যাপ করার জন্য প্রয়োজনীয় তথ্য থাকে। Android স্টুডিও ফাইলটিকে <module-name> /build/outputs/mapping/ <build-type> / ডিরেক্টরিতে সংরক্ষণ করে।

Google Play-তে আপনার অ্যাপ প্রকাশ করার সময়, আপনি আপনার অ্যাপের প্রতিটি সংস্করণের জন্য mapping.txt ফাইল আপলোড করতে পারেন। Android App Bundles ব্যবহার করে প্রকাশ করার সময় এই ফাইলটি অ্যাপ বান্ডেল সামগ্রীর অংশ হিসেবে স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত হয়। তারপরে Google Play ব্যবহারকারীর রিপোর্ট করা সমস্যা থেকে ইনকামিং স্ট্যাকের ট্রেস রিট্রেস করবে যাতে আপনি Play Console-এ সেগুলো পর্যালোচনা করতে পারেন। আরও তথ্যের জন্য, ক্র্যাশ স্ট্যাক ট্রেসগুলিকে কীভাবে ডিঅফসকেট করা যায় সে সম্পর্কে সহায়তা কেন্দ্র নিবন্ধটি দেখুন।

R8 এর সাথে সমস্যা সমাধান করুন

এই বিভাগে R8 ব্যবহার করে সঙ্কুচিত, অস্পষ্টতা এবং অপ্টিমাইজেশন সক্ষম করার সময় সমস্যা সমাধানের জন্য কিছু কৌশল বর্ণনা করা হয়েছে। আপনি যদি নীচে আপনার সমস্যার সমাধান না পান তবে R8 FAQ পৃষ্ঠা এবং 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
...

সমস্যা সমাধানের সংস্থান সঙ্কুচিত

আপনি যখন সংস্থান সঙ্কুচিত করেন, বিল্ড উইন্ডো অ্যাপ্লিকেশন থেকে সরানো সংস্থানগুলির সংক্ষিপ্তসার দেখায়। (আপনাকে প্রথমে টগল ভিউ ক্লিক করতে হবে গ্রেড থেকে বিশদ পাঠ্য আউটপুট প্রদর্শন করতে উইন্ডোর বাম দিকে)) উদাহরণস্বরূপ:

:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning

গ্রেডল <module-name>/build/outputs/mapping/release/ (প্রোগুয়ার্ডের আউটপুট ফাইলগুলির মতো একই ফোল্ডার) এ resources.txt নামে একটি ডায়াগনস্টিক ফাইলও তৈরি করে। এই ফাইলটিতে বিশদ অন্তর্ভুক্ত রয়েছে যেমন কোন সংস্থানগুলি অন্যান্য সংস্থানগুলি উল্লেখ করে এবং কোন সংস্থানগুলি ব্যবহৃত হয় বা সরানো হয়।

উদাহরণস্বরূপ, কেন @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 এর একটি কোড রেফারেন্স রয়েছে (অর্থাত্ এর আর।

আপনি যদি কঠোর চেকিং ব্যবহার না করে থাকেন তবে রিসোর্স আইডিগুলি পৌঁছনীয় হিসাবে চিহ্নিত করা যেতে পারে যদি এমন স্ট্রিং ধ্রুবকগুলি থাকে যা দেখে মনে হয় যে তারা গতিশীলভাবে লোড হওয়া সংস্থানগুলির জন্য রিসোর্স নামগুলি তৈরি করতে ব্যবহৃত হতে পারে। সেক্ষেত্রে, আপনি যদি রিসোর্স নামের জন্য বিল্ড আউটপুট অনুসন্ধান করেন তবে আপনি এর মতো একটি বার্তা পেতে পারেন:

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 , কীভাবে করবেন সে সম্পর্কে বিভাগে বর্ণিত হিসাবে কোন সংস্থান রাখতে হবে তা কাস্টমাইজ করুন