আপনার অ্যাপটিকে যতটা সম্ভব ছোট এবং দ্রুত করতে, আপনার রিলিজ বিল্ডটিকে isMinifyEnabled = true
দিয়ে অপ্টিমাইজ করা এবং ছোট করা উচিত।
এটি করার ফলে সঙ্কুচিত হয়, যা অব্যবহৃত কোড এবং সংস্থানগুলিকে সরিয়ে দেয়; অস্পষ্টতা , যা আপনার অ্যাপের ক্লাস এবং সদস্যদের নাম ছোট করে; এবং অপ্টিমাইজেশান , যা আরও আক্রমনাত্মক কৌশল প্রয়োগ করে আকার আরও কমাতে এবং আপনার অ্যাপের কর্মক্ষমতা উন্নত করতে। এই পৃষ্ঠাটি বর্ণনা করে যে কীভাবে R8 আপনার প্রকল্পের জন্য এই কম্পাইল-টাইম কাজগুলি সম্পাদন করে এবং কীভাবে আপনি সেগুলি কাস্টমাইজ করতে পারেন।
আপনি যখন অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.4.0 বা উচ্চতর ব্যবহার করে আপনার প্রকল্প তৈরি করেন, তখন প্লাগইনটি আর কম্পাইল-টাইম কোড অপ্টিমাইজেশান সঞ্চালনের জন্য প্রোগার্ড ব্যবহার করে না। পরিবর্তে, প্লাগইন R8 কম্পাইলারের সাথে নিম্নলিখিত কম্পাইল-টাইম কাজগুলি পরিচালনা করতে কাজ করে:
- কোড সঙ্কুচিত করা (বা ট্রি-কাঁপানো): আপনার অ্যাপ এবং এর লাইব্রেরি নির্ভরতা থেকে অব্যবহৃত ক্লাস, ক্ষেত্র, পদ্ধতি এবং বৈশিষ্ট্যগুলি সনাক্ত করে এবং নিরাপদে সরিয়ে দেয় (এটি 64k রেফারেন্স সীমার কাছাকাছি কাজ করার জন্য একটি মূল্যবান হাতিয়ার তৈরি করে)। উদাহরণস্বরূপ, যদি আপনি একটি লাইব্রেরি নির্ভরতার শুধুমাত্র কয়েকটি API ব্যবহার করেন, তাহলে সঙ্কুচিত লাইব্রেরি কোড সনাক্ত করতে পারে যা আপনার অ্যাপ ব্যবহার করছে না এবং আপনার অ্যাপ থেকে শুধুমাত্র সেই কোডটি সরিয়ে ফেলতে পারে। আরও জানতে, কীভাবে আপনার কোড সঙ্কুচিত করবেন সে সম্পর্কে বিভাগে যান।
- রিসোর্স সঙ্কুচিত করা: আপনার প্যাকেজ করা অ্যাপ থেকে অব্যবহৃত রিসোর্স সরিয়ে দেয়, আপনার অ্যাপের লাইব্রেরি নির্ভরতাগুলির অব্যবহৃত রিসোর্স সহ। এটি কোড সঙ্কুচিত করার সাথে একত্রে কাজ করে যে একবার অব্যবহৃত কোড মুছে ফেলা হলে, যেকোন সংস্থান আর উল্লেখ করা হয় না নিরাপদে মুছে ফেলা যেতে পারে। আরও জানতে, কীভাবে আপনার সংস্থানগুলি সঙ্কুচিত করবেন সে সম্পর্কে বিভাগে যান৷
- অপ্টিমাইজেশান: রানটাইম পারফরম্যান্স উন্নত করতে এবং আপনার অ্যাপের DEX ফাইলের আকার আরও কমাতে আপনার কোড পরিদর্শন করে এবং পুনর্লিখন করে। এটি কোডের রানটাইম কর্মক্ষমতা 30% পর্যন্ত উন্নত করে, স্টার্টআপ এবং ফ্রেমের সময়কে ব্যাপকভাবে উন্নত করে। উদাহরণস্বরূপ, যদি R8 সনাক্ত করে যে প্রদত্ত if/else স্টেটমেন্টের জন্য
else {}
শাখাটি কখনই নেওয়া হয় না, R8else {}
শাখার কোডটি সরিয়ে দেয়। আরও জানতে, কোড অপ্টিমাইজেশন সম্পর্কে বিভাগে যান। - অস্পষ্টতা (বা আইডেন্টিফায়ার মিনিফিকেশন): ক্লাস এবং সদস্যদের নাম ছোট করে, যার ফলে 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 নিয়মের ফাইল অন্তর্ভুক্ত রয়েছে, তবে আপনাকে |
লাইব্রেরি নির্ভরতা | একটি AAR লাইব্রেরিতে: একটি JAR লাইব্রেরিতে: এই অবস্থানগুলি ছাড়াও, 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 সেই কোডটি সরিয়ে দেয়।
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
এই ডিরেক্টরির বিষয়বস্তু জিপ আপ করুন:
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
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 {}
শাখা না নেয়, তাহলে R8else {}
শাখার কোডটি সরিয়ে দিতে পারে। - যদি আপনার কোড শুধুমাত্র কয়েকটি জায়গায় একটি পদ্ধতি কল করে, 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
Gradle এছাড়াও <module-name>/build/outputs/mapping/release/
(ProGuard-এর আউটপুট ফাইলগুলির মতো একই ফোল্ডার) এ 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
, কীভাবে করবেন সে সম্পর্কে বিভাগে বর্ণিত হিসাবে কোন সংস্থান রাখতে হবে তা কাস্টমাইজ করুন ।
আপনার অ্যাপ্লিকেশনটিকে যথাসম্ভব ছোট এবং দ্রুত তৈরি করতে আপনার রিলিজ বিল্ডটি isMinifyEnabled = true
সাথে অনুকূলিত করা এবং মিনিফাই করা উচিত।
এটি করা সঙ্কুচিত করতে সক্ষম করে, যা অব্যবহৃত কোড এবং সংস্থানগুলি সরিয়ে দেয়; অবহেলা , যা আপনার অ্যাপের ক্লাস এবং সদস্যদের নাম সংক্ষিপ্ত করে; এবং অপ্টিমাইজেশন , যা আপনার অ্যাপ্লিকেশনটির আরও আকার হ্রাস করতে এবং আপনার অ্যাপ্লিকেশনটির কার্যকারিতা উন্নত করতে আরও আক্রমণাত্মক কৌশল প্রয়োগ করে। এই পৃষ্ঠাটি বর্ণনা করে যে কীভাবে আর 8 আপনার প্রকল্পের জন্য এই সংকলন-সময় কাজগুলি সম্পাদন করে এবং কীভাবে আপনি সেগুলি কাস্টমাইজ করতে পারেন।
আপনি যখন অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.4.0 বা তার বেশি ব্যবহার করে আপনার প্রকল্পটি তৈরি করেন, প্লাগইনটি আর সংকলন-সময় কোড অপ্টিমাইজেশন সম্পাদন করতে প্রোগার্ড ব্যবহার করে না। পরিবর্তে, প্লাগইনটি নিম্নলিখিত সংকলন-সময় কাজগুলি পরিচালনা করতে আর 8 সংকলকের সাথে কাজ করে:
- কোড সঙ্কুচিত (বা গাছ-কাঁপানো): আপনার অ্যাপ্লিকেশন এবং এর লাইব্রেরির নির্ভরতাগুলি থেকে অব্যবহৃত শ্রেণি, ক্ষেত্র, পদ্ধতি এবং বৈশিষ্ট্যগুলি সনাক্ত করে এবং নিরাপদে সরিয়ে দেয় (এটি 64 কে রেফারেন্স সীমাটির চারপাশে কাজ করার জন্য এটি একটি মূল্যবান সরঞ্জাম হিসাবে তৈরি করে)। উদাহরণস্বরূপ, আপনি যদি কোনও লাইব্রেরির নির্ভরতার কয়েকটি এপিআই ব্যবহার করেন তবে সঙ্কুচিত হওয়া লাইব্রেরির কোডটি সনাক্ত করতে পারে যা আপনার অ্যাপ্লিকেশনটি ব্যবহার করছে না এবং কেবল আপনার অ্যাপ্লিকেশন থেকে সেই কোডটি সরিয়ে ফেলবে। আরও জানতে, আপনার কোডটি কীভাবে সঙ্কুচিত করবেন সে সম্পর্কে বিভাগে যান।
- রিসোর্স সঙ্কুচিত: আপনার অ্যাপের লাইব্রেরির নির্ভরতাগুলিতে অব্যবহৃত সংস্থান সহ আপনার প্যাকেজড অ্যাপ্লিকেশন থেকে অব্যবহৃত সংস্থানগুলি সরিয়ে দেয়। এটি কোড সঙ্কুচিত হওয়ার সাথে একত্রে কাজ করে যে একবার অব্যবহৃত কোডটি সরানো হয়েছে, যে কোনও সংস্থান আর উল্লেখ করা হয়নি তা নিরাপদেও অপসারণ করা যেতে পারে। আরও জানতে, কীভাবে আপনার সংস্থানগুলি সঙ্কুচিত করবেন সে সম্পর্কে বিভাগে যান।
- অপ্টিমাইজেশন: রানটাইম পারফরম্যান্স উন্নত করতে এবং আপনার অ্যাপের ডেক্স ফাইলগুলির আকার আরও হ্রাস করতে আপনার কোডটি পরিদর্শন করে এবং পুনরায় লিখে। এটি কোডের রানটাইম পারফরম্যান্সকে 30%পর্যন্ত উন্নত করে, স্টার্টআপ এবং ফ্রেমের সময়কে মারাত্মকভাবে উন্নত করে। উদাহরণস্বরূপ, যদি আর 8 সনাক্ত করে যে কোনও প্রদত্ত যদি/অন্য বিবৃতি কখনই নেওয়া হয় না তার জন্য
else {}
শাখা, আর 8else {}
শাখার জন্য কোডটি সরিয়ে দেয়। আরও জানতে, কোড অপ্টিমাইজেশন সম্পর্কে বিভাগে যান। - Obfuscation (বা সনাক্তকারী মিনিফিকেশন): ক্লাস এবং সদস্যদের নাম সংক্ষিপ্ত করে, যার ফলে ডেক্স ফাইলের আকার হ্রাস পায়। আরও জানতে, কীভাবে আপনার কোডটি অবলম্বন করা যায় সে সম্পর্কে বিভাগে যান।
আপনার অ্যাপ্লিকেশনটির রিলিজ সংস্করণটি তৈরি করার সময়, আর 8 আপনার জন্য উপরে বর্ণিত সংকলন-সময় কাজগুলি সম্পাদন করতে কনফিগার করা যেতে পারে। আপনি নির্দিষ্ট কাজগুলি অক্ষম করতে পারেন বা প্রোগুয়ার্ড বিধি ফাইলগুলির মাধ্যমে আর 8 এর আচরণ কাস্টমাইজ করতে পারেন। প্রকৃতপক্ষে, আর 8 আপনার বিদ্যমান সমস্ত প্রোগুয়ার্ড বিধি ফাইলগুলির সাথে কাজ করে , তাই আর 8 ব্যবহার করার জন্য অ্যান্ড্রয়েড গ্রেডল প্লাগইন আপডেট করার জন্য আপনাকে আপনার বিদ্যমান নিয়মগুলি পরিবর্তন করার প্রয়োজন হবে না।
সঙ্কুচিত, অবহেলা এবং অপ্টিমাইজেশন সক্ষম করুন
আপনি যখন অ্যান্ড্রয়েড স্টুডিও 3.4 বা অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.4.0 এবং উচ্চতর ব্যবহার করেন, আর 8 হ'ল ডিফল্ট সংকলক যা আপনার প্রকল্পের জাভা বাইটকোডকে ডেক্স ফর্ম্যাটে রূপান্তর করে যা অ্যান্ড্রয়েড প্ল্যাটফর্মে চলে। যাইহোক, আপনি যখন অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে একটি নতুন প্রকল্প তৈরি করেন, সঙ্কুচিত, অবরুদ্ধকরণ এবং কোড অপ্টিমাইজেশন ডিফল্টরূপে সক্ষম করা হয় না। কারণ এই সংকলন-সময় অপ্টিমাইজেশনগুলি আপনার প্রকল্পের বিল্ড সময় বাড়িয়ে তোলে এবং আপনি যদি কোন কোডটি রাখতে পারেন তবে পর্যাপ্ত পরিমাণে কাস্টমাইজ না করে বাগগুলি প্রবর্তন করতে পারে।
সুতরাং, প্রকাশের আগে আপনি পরীক্ষা করা আপনার অ্যাপ্লিকেশনটির চূড়ান্ত সংস্করণটি তৈরি করার সময় এই সংকলন-সময় কাজগুলি সক্ষম করা ভাল। সঙ্কুচিত হওয়া, অবহেলা এবং অপ্টিমাইজেশন সক্ষম করতে আপনার প্রকল্প-স্তরের বিল্ড স্ক্রিপ্টে নিম্নলিখিতগুলি অন্তর্ভুক্ত করুন।
কোটলিন
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' } } ... }
আর 8 কনফিগারেশন ফাইল
আর 8 এর ডিফল্ট আচরণটি সংশোধন করার জন্য প্রোগুয়ার্ড বিধি ফাইলগুলি ব্যবহার করে এবং আপনার অ্যাপ্লিকেশনটির কাঠামোটি আরও ভালভাবে বুঝতে পারে যেমন আপনার অ্যাপ্লিকেশনটির কোডে প্রবেশের পয়েন্ট হিসাবে পরিবেশন করে এমন ক্লাসগুলি। যদিও আপনি এই বিধিগুলির কয়েকটি ফাইল সংশোধন করতে পারেন, কিছু বিধিগুলি সংকলন-সময় সরঞ্জামগুলি যেমন এএপিটি 2, বা আপনার অ্যাপের লাইব্রেরির নির্ভরতা থেকে উত্তরাধিকার সূত্রে স্বয়ংক্রিয়ভাবে উত্পন্ন হতে পারে। নীচের সারণীতে প্রোগুয়ার্ড বিধিগুলি ফাইলগুলির উত্সগুলি বর্ণনা করে যা আর 8 ব্যবহার করে।
উৎস | অবস্থান | বর্ণনা |
অ্যান্ড্রয়েড স্টুডিও | <module-dir>/proguard-rules.pro | আপনি যখন অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে একটি নতুন মডিউল তৈরি করেন, তখন আইডিই সেই মডিউলটির মূল ডিরেক্টরিতে একটি proguard-rules.pro ফাইল তৈরি করে।ডিফল্টরূপে, এই ফাইলটি কোনো নিয়ম প্রয়োগ করে না। সুতরাং, আপনার নিজস্ব প্রোগুয়ার্ড বিধিগুলি এখানে অন্তর্ভুক্ত করুন, যেমন আপনার কাস্টম রাখার নিয়মগুলি । |
অ্যান্ড্রয়েড গ্রেডল প্লাগইন | সংকলন সময়ে অ্যান্ড্রয়েড গ্রেডল প্লাগইন দ্বারা উত্পাদিত। | অ্যান্ড্রয়েড গ্রেডল প্লাগইন proguard-android-optimize.txt তৈরি করে, যার মধ্যে বেশিরভাগ অ্যান্ড্রয়েড প্রকল্পগুলির জন্য দরকারী নিয়মগুলি অন্তর্ভুক্ত করে এবং @Keep* জন্য সক্ষম করে।ডিফল্টরূপে, অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে একটি নতুন মডিউল তৈরি করার সময়, মডিউল-স্তরের বিল্ড স্ক্রিপ্টটিতে আপনার জন্য আপনার রিলিজ বিল্ডে এই নিয়ম ফাইল অন্তর্ভুক্ত রয়েছে। দ্রষ্টব্য: অ্যান্ড্রয়েড গ্রেডল প্লাগইনটিতে অতিরিক্ত পূর্বনির্ধারিত প্রোগুয়ার্ড বিধি ফাইলগুলি অন্তর্ভুক্ত রয়েছে তবে আপনি |
গ্রন্থাগার নির্ভরতা | একটি এআর লাইব্রেরিতে: একটি জার লাইব্রেরিতে: এই অবস্থানগুলি ছাড়াও, অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.6 বা উচ্চতরও লক্ষ্যযুক্ত সঙ্কুচিত নিয়মকে সমর্থন করে। | যদি কোনও এএআর বা জার লাইব্রেরি তার নিজস্ব নিয়ম ফাইলের সাথে প্রকাশিত হয় এবং আপনি সেই লাইব্রেরিটিকে একটি সংকলন-সময় নির্ভরতা হিসাবে অন্তর্ভুক্ত করেন, আর 8 আপনার প্রকল্পটি সংকলন করার সময় স্বয়ংক্রিয়ভাবে সেই নিয়মগুলি প্রয়োগ করে। প্রচলিত প্রোগুয়ার্ড বিধি ছাড়াও, অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.6 বা উচ্চতরও লক্ষ্যযুক্ত সঙ্কুচিত নিয়মকে সমর্থন করে। এগুলি এমন নিয়ম যা নির্দিষ্ট সঙ্কুচিতকারী (আর 8 বা প্রোগুয়ার্ড), পাশাপাশি নির্দিষ্ট সঙ্কুচিত সংস্করণগুলিকে লক্ষ্য করে। লাইব্রেরির সাথে প্যাকেজযুক্ত বিধি ফাইলগুলি ব্যবহার করা কার্যকর যদি লাইব্রেরির সঠিকভাবে কাজ করার জন্য নির্দিষ্ট নিয়মের প্রয়োজন হয় - অর্থাৎ গ্রন্থাগার বিকাশকারী আপনার জন্য সমস্যা সমাধানের পদক্ষেপগুলি সম্পাদন করেছেন। তবে, আপনার সচেতন হওয়া উচিত, যেহেতু নিয়মগুলি সংযোজনযুক্ত , এমন কিছু নিয়ম যা একটি লাইব্রেরির নির্ভরতা অন্তর্ভুক্ত করে তা অপসারণ করা যায় না এবং এটি আপনার অ্যাপ্লিকেশনটির অন্যান্য অংশগুলির সংকলনকে প্রভাবিত করতে পারে। উদাহরণস্বরূপ, যদি কোনও লাইব্রেরিতে কোড অপ্টিমাইজেশনগুলি অক্ষম করার কোনও নিয়ম অন্তর্ভুক্ত থাকে তবে সেই নিয়মটি আপনার পুরো প্রকল্পের জন্য অপ্টিমাইজেশনগুলি অক্ষম করে। |
অ্যান্ড্রয়েড অ্যাসেট প্যাকেজ সরঞ্জাম 2 (এএপিটি 2) | আপনার প্রকল্পটি minifyEnabled true : <module-dir>/build/intermediates/aapt_proguard_file/.../aapt_rules.txt | এএপিটি 2 আপনার অ্যাপের ম্যানিফেস্ট, লেআউট এবং অন্যান্য অ্যাপ্লিকেশন সংস্থানগুলির ক্লাসগুলির রেফারেন্সের ভিত্তিতে বিধিগুলি রাখে। উদাহরণস্বরূপ, এএপিটি 2 এ প্রতিটি ক্রিয়াকলাপের জন্য একটি রাখার নিয়ম অন্তর্ভুক্ত করে যা আপনি আপনার অ্যাপের ম্যানিফেস্টে প্রবেশের পয়েন্ট হিসাবে নিবন্ধভুক্ত করেন। |
কাস্টম কনফিগারেশন ফাইল | ডিফল্টরূপে, আপনি যখন অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে একটি নতুন মডিউল তৈরি করেন, আইডিই আপনার নিজস্ব নিয়ম যুক্ত করার জন্য <module-dir>/proguard-rules.pro তৈরি করে। | আপনি অতিরিক্ত কনফিগারেশনগুলি অন্তর্ভুক্ত করতে পারেন এবং আর 8 সেগুলি সংকলন-সময়ে প্রয়োগ করে। |
আপনি যখন minifyEnabled
সম্পত্তিটি true
সেট করেন, আর 8 উপরে তালিকাভুক্ত সমস্ত উপলভ্য উত্স থেকে বিধিগুলি একত্রিত করে। আপনি যখন আর 8 এর সাথে সমস্যা সমাধান করেন তখন এটি মনে রাখা গুরুত্বপূর্ণ, কারণ অন্যান্য সংকলন-সময় নির্ভরতা যেমন লাইব্রেরির নির্ভরতাগুলি, আপনি যে আর 8 আচরণ সম্পর্কে জানেন না তার পরিবর্তনগুলি প্রবর্তন করতে পারে।
আপনার প্রকল্পটি তৈরি করার সময় আর 8 প্রয়োগ করে এমন সমস্ত নিয়মের একটি সম্পূর্ণ প্রতিবেদন আউটপুট করতে, আপনার মডিউলটির proguard-rules.pro
ফাইলটিতে নিম্নলিখিতগুলি অন্তর্ভুক্ত করুন:
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt
লক্ষ্যবস্তু সঙ্কুচিত নিয়ম
অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.6 বা উচ্চতর লাইব্রেরির নিয়মকে সমর্থন করে যা নির্দিষ্ট সঙ্কুচিতকারী (আর 8 বা প্রোগুয়ার্ড), পাশাপাশি নির্দিষ্ট সঙ্কুচিত সংস্করণগুলিকে লক্ষ্য করে। এটি গ্রন্থাগার বিকাশকারীদের তাদের নিয়মগুলি সর্বোত্তমভাবে কাজ করার জন্য তাদের নিয়মগুলি তৈরি করতে দেয় যা নতুন সঙ্কুচিত সংস্করণ ব্যবহার করে, যখন বিদ্যমান নিয়মগুলি পুরানো সঙ্কুচিত সংস্করণগুলির সাথে প্রকল্পগুলিতে ব্যবহার চালিয়ে যেতে দেয়।
লক্ষ্যযুক্ত সঙ্কুচিত নিয়মগুলি নির্দিষ্ট করতে, গ্রন্থাগার বিকাশকারীদের নীচে বর্ণিত হিসাবে একটি এএআর বা জার লাইব্রেরির অভ্যন্তরে নির্দিষ্ট স্থানে অন্তর্ভুক্ত করতে হবে।
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>
এর অর্থ লক্ষ্যযুক্ত সঙ্কুচিত বিধিগুলি META-INF/com.android.tools
ডিরেক্টরিতে একটি জারের ডিরেক্টরিতে বা META-INF/com.android.tools
ডিরেক্টরিতে ক্লাস ইন classes.jar
এর মধ্যে সংরক্ষণ করা হয়।
সেই ডিরেক্টরিটির অধীনে, r8-from-<X>-upto-<Y>
বা proguard-from-<X>-upto-<Y>
কোন সংস্করণগুলির মধ্যে কোন সংস্করণগুলি সঙ্কুচিত করে তা নির্দেশ করতে ডিরেক্টরিগুলির ভিতরে নিয়মগুলির জন্য লেখা হয়। নোট করুন যে -from-<X>
এবং -upto-<Y>
অংশগুলি al চ্ছিক, <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 সহ নয় তবে R8 দ্বারা ব্যবহৃত হবে।
সেই তথ্য দেওয়া, অ্যান্ড্রয়েড গ্রেডল প্লাগইন 3.6 বা তার বেশি ম্যাচিং আর 8 ডিরেক্টরিগুলি থেকে নিয়মগুলি নির্বাচন করবে। যদি কোনও গ্রন্থাগার লক্ষ্যযুক্ত সঙ্কুচিত নিয়মগুলি নির্দিষ্ট না করে তবে অ্যান্ড্রয়েড গ্রেডল প্লাগইন উত্তরাধিকারের অবস্থানগুলি থেকে নিয়মগুলি নির্বাচন করবে ( proguard.txt
বা META-INF/proguard/<ProGuard-rules-file>
একটি জারের জন্য)।
গ্রন্থাগার বিকাশকারীরা তাদের গ্রন্থাগারগুলিতে লক্ষ্যযুক্ত সঙ্কুচিত নিয়ম বা উত্তরাধিকার প্রোগুয়ার্ড বিধিগুলি বা উভয় প্রকারের অন্তর্ভুক্ত করতে বেছে নিতে পারেন যদি তারা 3.6 বা অন্যান্য সরঞ্জামের চেয়ে পুরানো অ্যান্ড্রয়েড গ্রেডল প্লাগইনগুলির সাথে সামঞ্জস্যতা বজায় রাখতে চান।
অতিরিক্ত কনফিগারেশন অন্তর্ভুক্ত করুন
আপনি যখন অ্যান্ড্রয়েড স্টুডিও ব্যবহার করে একটি নতুন প্রকল্প বা মডিউল তৈরি করেন, তখন আইডিই আপনার নিজস্ব নিয়মগুলি অন্তর্ভুক্ত করার জন্য একটি <module-dir>/proguard-rules.pro
ফাইল তৈরি করে। আপনি অন্যান্য ফাইলগুলি থেকে আপনার মডিউলটির বিল্ড স্ক্রিপ্টে proguardFiles
সম্পত্তিতে যুক্ত করে অতিরিক্ত নিয়মগুলি অন্তর্ভুক্ত করতে পারেন।
উদাহরণস্বরূপ, আপনি সংশ্লিষ্ট productFlavor
ব্লকে অন্য proguardFiles
সম্পত্তি যুক্ত করে প্রতিটি বিল্ড বৈকল্পের সাথে সুনির্দিষ্ট নিয়ম যুক্ত করতে পারেন। নিম্নলিখিত গ্রেডল ফাইলটি flavor2-rules.pro
যুক্ত করে। flavor2
পণ্য স্বাদে প্রো। এখন, flavor2
তিনটি প্রোগুয়ার্ড বিধি ব্যবহার করে কারণ release
ব্লক থেকে আসাগুলিও প্রয়োগ করা হয়।
অতিরিক্তভাবে, আপনি testProguardFiles
সম্পত্তি যুক্ত করতে পারেন, যা কেবলমাত্র পরীক্ষার এপিকে অন্তর্ভুক্ত প্রোগুয়ার্ড ফাইলগুলির একটি তালিকা নির্দিষ্ট করে:
কোটলিন
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 নির্ধারণ করে যে রানটাইমের প্রয়োজন হয় না। এই প্রক্রিয়াটি আপনার অ্যাপ্লিকেশনটির আকারকে ব্যাপকভাবে হ্রাস করতে পারে যদি উদাহরণস্বরূপ, আপনার অ্যাপ্লিকেশনটিতে অনেকগুলি গ্রন্থাগার নির্ভরতা অন্তর্ভুক্ত থাকে তবে তাদের কার্যকারিতার একটি ছোট অংশই ব্যবহার করে।
আপনার অ্যাপ্লিকেশনটির কোড সঙ্কুচিত করতে, আর 8 প্রথমে কনফিগারেশন ফাইলগুলির সম্মিলিত সেটের উপর ভিত্তি করে আপনার অ্যাপের কোডে সমস্ত এন্ট্রি পয়েন্ট নির্ধারণ করে। এই এন্ট্রি পয়েন্টগুলিতে এমন সমস্ত শ্রেণি অন্তর্ভুক্ত রয়েছে যা অ্যান্ড্রয়েড প্ল্যাটফর্মটি আপনার অ্যাপের ক্রিয়াকলাপ বা পরিষেবাগুলি খোলার জন্য ব্যবহার করতে পারে। প্রতিটি এন্ট্রি পয়েন্ট থেকে শুরু করে, আর 8 আপনার অ্যাপ্লিকেশনটির কোডটি সমস্ত পদ্ধতি, সদস্য ভেরিয়েবল এবং অন্যান্য শ্রেণীর একটি গ্রাফ তৈরি করতে পরীক্ষা করে যা আপনার অ্যাপ্লিকেশনটি রানটাইমে অ্যাক্সেস করতে পারে। সেই গ্রাফের সাথে সংযুক্ত নয় এমন কোডটি অ্যাক্সেসযোগ্য হিসাবে বিবেচিত হয় এবং এটি অ্যাপ থেকে সরানো যেতে পারে।
চিত্র 1 রানটাইম লাইব্রেরির নির্ভরতা সহ একটি অ্যাপ্লিকেশন দেখায়। অ্যাপ্লিকেশনটির কোডটি পরিদর্শন করার সময়, আর 8 নির্ধারণ করে যে পদ্ধতিগুলি foo()
, faz()
, এবং bar()
MainActivity.class
থেকে পৌঁছনীয় Class ক্লাস এন্ট্রি পয়েন্ট। যাইহোক, ক্লাস OkayApi.class
বা এর পদ্ধতি baz()
আপনার অ্যাপ্লিকেশন দ্বারা রানটাইমে কখনই ব্যবহার করা হয় না এবং আর 8 আপনার অ্যাপ্লিকেশনটি সঙ্কুচিত করার সময় সেই কোডটি সরিয়ে দেয়।
আর 8 প্রকল্পের আর 8 কনফিগারেশন ফাইলগুলিতে -keep
বিধিগুলির মাধ্যমে এন্ট্রি পয়েন্টগুলি নির্ধারণ করে। এটি হ'ল, বিধিগুলি রাখুন এমন ক্লাসগুলি নির্দিষ্ট করুন যা আপনার অ্যাপ্লিকেশনটি সঙ্কুচিত করার সময় আর 8 বাতিল করা উচিত নয় এবং আর 8 সেই ক্লাসগুলিকে আপনার অ্যাপ্লিকেশনটিতে সম্ভাব্য এন্ট্রি পয়েন্ট হিসাবে বিবেচনা করে। অ্যান্ড্রয়েড গ্রেডল প্লাগইন এবং এএপিটি 2 স্বয়ংক্রিয়ভাবে আপনার জন্য বেশিরভাগ অ্যাপ্লিকেশন প্রকল্পগুলির দ্বারা প্রয়োজনীয় যেমন আপনার অ্যাপের ক্রিয়াকলাপ, দর্শন এবং পরিষেবাদিগুলির জন্য প্রয়োজনীয় বিধিগুলি তৈরি করে। তবে, যদি আপনাকে অতিরিক্ত রাখার নিয়মের সাথে এই ডিফল্ট আচরণটি কাস্টমাইজ করতে হয় তবে কোন কোডটি কীভাবে রাখতে হবে তা কাস্টমাইজ করতে হবে সে সম্পর্কে বিভাগটি পড়ুন।
পরিবর্তে যদি আপনি কেবল আপনার অ্যাপের সংস্থানগুলির আকার হ্রাস করতে আগ্রহী হন তবে কীভাবে আপনার সংস্থানগুলি সঙ্কুচিত করবেন সে সম্পর্কে বিভাগে এড়িয়ে যান।
মনে রাখবেন যে যদি কোনও গ্রন্থাগার প্রকল্প সঙ্কুচিত হয় তবে সেই লাইব্রেরির উপর নির্ভর করে এমন একটি অ্যাপ্লিকেশন সঙ্কুচিত লাইব্রেরি ক্লাস অন্তর্ভুক্ত করে। লাইব্রেরি এপিকে অনুপস্থিত ক্লাস থাকলে আপনার লাইব্রেরি রাখার নিয়মগুলি সামঞ্জস্য করতে হবে। আপনি যদি এএআর ফর্ম্যাটে একটি লাইব্রেরি তৈরি এবং প্রকাশ করছেন তবে স্থানীয় জার ফাইলগুলি যা আপনার লাইব্রেরির উপর নির্ভর করে এআর ফাইলটিতে সঙ্কুচিত হয় না ।
কোন কোড রাখতে হবে কাস্টমাইজ করুন
বেশিরভাগ পরিস্থিতিতে, ডিফল্ট প্রোগুয়ার্ড বিধিগুলি ফাইল ( proguard-android-optimize.txt
) কেবলমাত্র অব্যবহৃত কোড অপসারণ করতে আর 8 এর জন্য যথেষ্ট। যাইহোক, কিছু পরিস্থিতি আর 8 এর পক্ষে সঠিকভাবে বিশ্লেষণ করা কঠিন এবং এটি আপনার অ্যাপ্লিকেশনটি আসলে প্রয়োজনীয় কোডটি সরিয়ে ফেলতে পারে। এটি যখন ভুলভাবে কোডটি সরিয়ে ফেলতে পারে তার কয়েকটি উদাহরণ অন্তর্ভুক্ত রয়েছে:
- যখন আপনার অ্যাপ্লিকেশনটি জাভা নেটিভ ইন্টারফেস (জেএনআই) থেকে কোনও পদ্ধতি কল করে
- যখন আপনার অ্যাপ্লিকেশনটি রানটাইমে কোডটি দেখায় (যেমন প্রতিচ্ছবি সহ)
আপনার অ্যাপ্লিকেশনটি পরীক্ষা করা অনুপযুক্তভাবে সরানো কোডের কারণে যে কোনও ত্রুটি প্রকাশ করা উচিত, তবে আপনি সরানো কোডের একটি প্রতিবেদন তৈরি করে কোন কোডটি সরানো হয়েছিল তাও পরিদর্শন করতে পারেন।
ত্রুটিগুলি ঠিক করতে এবং নির্দিষ্ট কোড রাখতে আর 8 জোর করতে, প্রোগুয়ার্ড বিধি ফাইলটিতে একটি -keep
লাইন যুক্ত করুন। যেমন:
-keep public class MyClass
বিকল্পভাবে, আপনি যে কোডটি রাখতে চান তাতে @Keep
টীকা যুক্ত করতে পারেন। একটি ক্লাসে @Keep
কেআইপি যুক্ত করা পুরো ক্লাসটিকে যেমন থাকে তেমন রাখে। এটি কোনও পদ্ধতি বা ক্ষেত্রে যুক্ত করা পদ্ধতি/ক্ষেত্র (এবং এর নাম) পাশাপাশি শ্রেণীর নাম অক্ষত রাখবে। নোট করুন যে এই টীকাটি কেবল তখনই পাওয়া যায় যখন অ্যান্ড্রয়েডএক্স টীকাগুলি গ্রন্থাগারটি ব্যবহার করা হয় এবং যখন আপনি অ্যান্ড্রয়েড গ্রেডল প্লাগইন দিয়ে প্যাকেজযুক্ত প্রোগুয়ার্ড বিধি ফাইলটি অন্তর্ভুক্ত করেন, কীভাবে সঙ্কুচিত সক্ষম করবেন সে সম্পর্কে বিভাগে বর্ণিত।
-keep
বিকল্পটি ব্যবহার করার সময় আপনার অনেকগুলি বিবেচনা করা উচিত; আপনার নিয়ম ফাইল কাস্টমাইজ করার বিষয়ে আরও তথ্যের জন্য, প্রোগুয়ার্ড ম্যানুয়ালটি পড়ুন। সমস্যা সমাধানের বিভাগটি যখন আপনার কোডটি সরিয়ে ফেলা হয় তখন আপনার মুখোমুখি হতে পারে এমন অন্যান্য সাধারণ সমস্যার রূপরেখা দেয়।
স্ট্রিপ নেটিভ লাইব্রেরি
ডিফল্টরূপে, নেটিভ কোড লাইব্রেরিগুলি আপনার অ্যাপ্লিকেশনটির রিলিজ বিল্ডগুলিতে ছিনিয়ে নেওয়া হয়। এই স্ট্রিপিংটিতে আপনার অ্যাপ্লিকেশন দ্বারা ব্যবহৃত কোনও নেটিভ লাইব্রেরিতে থাকা প্রতীক সারণী অপসারণ এবং ডিবাগিং তথ্য রয়েছে। নেটিভ কোড লাইব্রেরিগুলি সরানোর ফলে উল্লেখযোগ্য আকারের সঞ্চয় হয়; তবে অনুপস্থিত তথ্যের (যেমন শ্রেণি এবং ফাংশন নাম) এর কারণে গুগল প্লে কনসোলে ক্র্যাশগুলি নির্ণয় করা অসম্ভব।
নেটিভ ক্র্যাশ সমর্থন
গুগল প্লে কনসোল অ্যান্ড্রয়েড ভাইটালসের অধীনে নেটিভ ক্র্যাশগুলি রিপোর্ট করেছে। কয়েকটি পদক্ষেপের সাহায্যে আপনি আপনার অ্যাপ্লিকেশনটির জন্য একটি নেটিভ ডিবাগ প্রতীক ফাইল তৈরি এবং আপলোড করতে পারেন। এই ফাইলটি অ্যান্ড্রয়েড ভাইটালগুলিতে প্রতীকী নেটিভ ক্র্যাশ স্ট্যাক ট্রেসগুলি (যার মধ্যে শ্রেণি এবং ফাংশন নাম অন্তর্ভুক্ত) সক্ষম করে যাতে আপনাকে উত্পাদনে আপনার অ্যাপটি ডিবাগ করতে সহায়তা করে। আপনার প্রকল্পে ব্যবহৃত অ্যান্ড্রয়েড গ্রেডল প্লাগইনের সংস্করণ এবং আপনার প্রকল্পের বিল্ড আউটপুটের উপর নির্ভর করে এই পদক্ষেপগুলি পরিবর্তিত হয়।
অ্যান্ড্রয়েড গ্রেডল প্লাগইন সংস্করণ 4.1 বা তার পরে
যদি আপনার প্রকল্পটি একটি অ্যান্ড্রয়েড অ্যাপ্লিকেশন বান্ডিল তৈরি করে তবে আপনি স্বয়ংক্রিয়ভাবে এতে নেটিভ ডিবাগ প্রতীক ফাইল অন্তর্ভুক্ত করতে পারেন। রিলিজ বিল্ডগুলিতে এই ফাইলটি অন্তর্ভুক্ত করতে, আপনার অ্যাপের build.gradle.kts
ফাইলটিতে নিম্নলিখিতগুলি যুক্ত করুন:
android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }
নিম্নলিখিত থেকে ডিবাগ প্রতীক স্তর নির্বাচন করুন:
- প্লে কনসোলের প্রতীকী স্ট্যাক ট্রেসগুলিতে ফাংশন নাম পেতে
SYMBOL_TABLE
ব্যবহার করুন। এই স্তরটি সমাধিস্থলগুলিকে সমর্থন করে। - প্লে কনসোলের প্রতীকী স্ট্যাক ট্রেসগুলিতে ফাংশন নাম, ফাইল এবং লাইন নম্বর পেতে
FULL
ব্যবহার করুন।
যদি আপনার প্রকল্পটি কোনও এপিকে তৈরি করে তবে দেশীয় ডিবাগ প্রতীক ফাইলগুলি আলাদাভাবে উত্পন্ন করতে পূর্বে প্রদর্শিত build.gradle.kts
বিল্ড সেটিংটি ব্যবহার করুন। গুগল প্লে কনসোলে ম্যানুয়ালি নেটিভ ডিবাগ প্রতীক ফাইল আপলোড করুন । বিল্ড প্রক্রিয়ার অংশ হিসাবে, অ্যান্ড্রয়েড গ্রেডল প্লাগইন এই ফাইলটিকে নিম্নলিখিত প্রকল্পের অবস্থানে আউটপুট করে:
app/build/outputs/native-debug-symbols/ variant-name /native-debug-symbols.zip
অ্যান্ড্রয়েড গ্রেডল প্লাগইন সংস্করণ 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
এই ডিরেক্টরির বিষয়বস্তু জিপ আপ করুন:
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
গুগল প্লে কনসোলে ম্যানুয়ালি
symbols.zip
ফাইল আপলোড করুন ।
আপনার সংস্থান সঙ্কুচিত
রিসোর্স সঙ্কুচিত হওয়া কেবল কোড সঙ্কুচিততার সাথে একত্রে কাজ করে। কোড সঙ্কুচিত সমস্ত অব্যবহৃত কোড অপসারণের পরে, রিসোর্স সঙ্কুচিতকারীটি অ্যাপটি এখনও কোন সংস্থান ব্যবহার করে তা সনাক্ত করতে পারে। এটি বিশেষত সত্য যখন আপনি কোড লাইব্রেরি যুক্ত করেন যার মধ্যে সংস্থানগুলি অন্তর্ভুক্ত থাকে - আপনাকে অবশ্যই অব্যবহৃত গ্রন্থাগার কোড অপসারণ করতে হবে যাতে গ্রন্থাগারের সংস্থানগুলি অপরিশোধিত হয়ে যায় এবং এইভাবে, রিসোর্স সঙ্কুচিত দ্বারা অপসারণযোগ্য।
রিসোর্স সঙ্কুচিত সক্ষম করতে, আপনার বিল্ড স্ক্রিপ্টে shrinkResources
সম্পত্তিটিকে true
সেট করুন (কোড সঙ্কুচিত করার জন্য minifyEnabled
পাশাপাশি)। যেমন:
কোটলিন
android { ... buildTypes { getByName("release") { isShrinkResources = true isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" ) } } }
গ্রোভি
android { ... buildTypes { release { shrinkResources true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
আপনি যদি ইতিমধ্যে কোড সঙ্কুচিত করার জন্য minifyEnabled
ব্যবহার করে আপনার অ্যাপটি তৈরি না করে থাকেন তবে shrinkResources
সক্ষম করার আগে এটি চেষ্টা করুন, কারণ আপনাকে আপনার proguard-rules.pro
বিউলস সম্পাদনা করতে হবে PRO ফাইলগুলি তৈরি করতে হবে যা ক্লাস বা পদ্ধতিগুলি রাখার জন্য যা তৈরি করা হয় বা গতিশীলভাবে আহ্বান করা হয় আপনি অপসারণ শুরু করার আগে আপনি অপসারণ শুরু করার আগে সম্পদ
কোন সংস্থান রাখতে হবে তা কাস্টমাইজ করুন
যদি আপনি রাখতে বা বাতিল করতে চান এমন নির্দিষ্ট সংস্থানগুলি থাকে তবে আপনার প্রকল্পে একটি <resources>
ট্যাগ দিয়ে একটি এক্সএমএল ফাইল তৈরি করুন এবং tools:keep
tools:discard
। উভয় বৈশিষ্ট্য সম্পদের নামগুলির একটি কমা-বিচ্ছিন্ন তালিকা গ্রহণ করে। আপনি বন্য কার্ড হিসাবে তারকাচিহ্ন চরিত্রটি ব্যবহার করতে পারেন।
যেমন:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*" tools:discard="@layout/unused2" />
আপনার প্রকল্পের সংস্থানগুলিতে এই ফাইলটি সংরক্ষণ করুন, উদাহরণস্বরূপ, res/raw/my.package.keep.xml
এ। বিল্ডটি আপনার অ্যাপ্লিকেশনটিতে এই ফাইলটি প্যাকেজ করে না।
দ্রষ্টব্য: keep
ফাইলের জন্য একটি অনন্য নাম ব্যবহার করার বিষয়টি নিশ্চিত করুন। যখন বিভিন্ন লাইব্রেরি একসাথে সংযুক্ত হয়ে যায় তখন তাদের রাখার নিয়মগুলি অন্যথায় বিরোধ করে, উপেক্ষা করা নিয়মগুলি বা অপ্রয়োজনীয় রক্ষিত সংস্থানগুলির সাথে সম্ভাব্য সমস্যা সৃষ্টি করে।
কোন সংস্থানগুলি বাতিল করতে হবে তা নির্দিষ্ট করে আপনি যখন সেগুলি মুছতে পারেন তখন নির্বোধ মনে হতে পারে তবে বিল্ড ভেরিয়েন্টগুলি ব্যবহার করার সময় এটি কার্যকর হতে পারে। উদাহরণস্বরূপ, আপনি আপনার সমস্ত সংস্থানগুলি সাধারণ প্রকল্প ডিরেক্টরিতে রাখতে পারেন, তারপরে প্রতিটি বিল্ড বৈকল্পের জন্য একটি পৃথক my.package.build.variant.keep.xml
ফাইল তৈরি করতে পারেন যখন আপনি জানেন যে প্রদত্ত সংস্থান কোড (এবং সুতরাং সঙ্কুচিত দ্বারা সরানো হয়নি) তবে আপনি জানেন যে এটি আসলে প্রদত্ত বিল্ড বৈকল্পিকের জন্য ব্যবহার করা হবে না। এটিও সম্ভব যে বিল্ড সরঞ্জামগুলি প্রয়োজনীয় হিসাবে একটি সংস্থানকে ভুলভাবে চিহ্নিত করেছে, যা সম্ভব কারণ সংকলকটি রিসোর্স আইডিগুলি ইনলাইন যুক্ত করে এবং তারপরে রিসোর্স বিশ্লেষক সম্ভবত একটি সত্যিকারের রেফারেন্সযুক্ত সংস্থান এবং কোডের মধ্যে একটি পূর্ণসংখ্যার মান জানেন না যা ঘটে একই মান আছে।
কঠোর রেফারেন্স চেক সক্ষম করুন
সাধারণত, রিসোর্স সঙ্কুচিতকারী কোনও সংস্থান ব্যবহৃত হয় কিনা তা সঠিকভাবে নির্ধারণ করতে পারে। তবে , যদি আপনার কোডটি Resources.getIdentifier()
কল করে get আপনি যখন এটি করেন, রিসোর্স সঙ্কুচিতকারী ডিফল্টরূপে ডিফেন্সিয়ালি আচরণ করে এবং সম্ভাব্যভাবে ব্যবহৃত এবং অপসারণের জন্য অনুপলব্ধ হিসাবে একটি মিলের নাম ফর্ম্যাট সহ সমস্ত সংস্থান চিহ্নিত করে।
উদাহরণস্বরূপ, নিম্নলিখিত কোডটি 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
ফাইলে strict
shrinkMode
সেট করুন, নিম্নলিখিত হিসাবে:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />
আপনি যদি কঠোর সঙ্কুচিত মোড সক্ষম করেন এবং আপনার কোডটি উপরে বর্ণিত হিসাবে গতিশীল-উত্পাদিত স্ট্রিংগুলির সাথে সংস্থানগুলিও উল্লেখ করে, তবে আপনাকে অবশ্যই tools:keep
।
অব্যবহৃত বিকল্প সংস্থান সরান
গ্রেডল রিসোর্স সঙ্কুচিত কেবলমাত্র এমন সংস্থানগুলি সরিয়ে দেয় যা আপনার অ্যাপ্লিকেশন কোড দ্বারা উল্লেখ করা হয় না, যার অর্থ এটি বিভিন্ন ডিভাইস কনফিগারেশনের জন্য বিকল্প সংস্থানগুলি সরিয়ে ফেলবে না। যদি প্রয়োজন হয় তবে আপনার অ্যাপ্লিকেশনটির প্রয়োজন নেই এমন বিকল্প সংস্থান ফাইলগুলি অপসারণ করতে আপনি অ্যান্ড্রয়েড গ্রেডল প্লাগইনের resConfigs
সম্পত্তি ব্যবহার করতে পারেন।
উদাহরণস্বরূপ, আপনি যদি এমন একটি গ্রন্থাগার ব্যবহার করছেন যাতে ভাষার সংস্থানগুলি অন্তর্ভুক্ত থাকে (যেমন অ্যাপকম্প্যাট বা গুগল প্লে পরিষেবাদি), তবে আপনার অ্যাপ্লিকেশনটিতে সেই লাইব্রেরিতে থাকা বার্তাগুলির জন্য সমস্ত অনুবাদ করা ভাষার স্ট্রিং অন্তর্ভুক্ত রয়েছে যা আপনার বাকী অ্যাপ্লিকেশন একই ভাষায় অনুবাদ করা হয়েছে বা না আপনি যদি কেবল আপনার অ্যাপ্লিকেশনটিকে আনুষ্ঠানিকভাবে সমর্থন করে এমন ভাষাগুলি রাখতে চান তবে আপনি resConfig
সম্পত্তি ব্যবহার করে সেই ভাষাগুলি নির্দিষ্ট করতে পারেন। নির্দিষ্ট না করা ভাষার জন্য যে কোনও সংস্থান সরানো হয়।
নিম্নলিখিত স্নিপেটটি দেখায় যে কীভাবে আপনার ভাষার সংস্থানগুলি কেবল ইংরেজি এবং ফরাসিদের মধ্যে সীমাবদ্ধ করতে পারে:
কোটলিন
android { defaultConfig { ... resourceConfigurations.addAll(listOf("en", "fr")) } }
গ্রোভি
android { defaultConfig { ... resConfigs "en", "fr" } }
অ্যান্ড্রয়েড অ্যাপ্লিকেশন বান্ডিল ফর্ম্যাট ব্যবহার করে কোনও অ্যাপ্লিকেশন প্রকাশ করার সময়, ডিফল্টরূপে কেবল কোনও ব্যবহারকারীর ডিভাইসে কনফিগার করা ভাষাগুলি অ্যাপটি ইনস্টল করার সময় ডাউনলোড হয়। একইভাবে, কেবল ডিভাইসের স্ক্রিনের ঘনত্বের সাথে মিলে যাওয়া সংস্থানগুলি এবং ডিভাইসের এবিআইয়ের সাথে মেলে নেটিভ লাইব্রেরিগুলি ডাউনলোডের অন্তর্ভুক্ত। আরও তথ্যের জন্য অ্যান্ড্রয়েড অ্যাপ্লিকেশন বান্ডিল কনফিগারেশনটি দেখুন।
এপিকেএসের সাথে প্রকাশিত উত্তরাধিকার অ্যাপ্লিকেশনগুলির জন্য (2021 আগস্টের আগে তৈরি), আপনি কোন স্ক্রিনের ঘনত্ব বা এবিআই সংস্থানগুলি আপনার এপিকে অন্তর্ভুক্ত করতে একাধিক APKs তৈরি করে প্রতিটি আলাদা ডিভাইস কনফিগারেশনকে লক্ষ্য করে কাস্টমাইজ করতে পারেন।
সদৃশ সংস্থানগুলি মার্জ করুন
ডিফল্টরূপে, গ্রেডল একই নামের সাথে একই নামের মতো একই নামযুক্ত সংস্থানগুলিও একত্রিত করে যা বিভিন্ন রিসোর্স ফোল্ডারে থাকতে পারে। এই আচরণটি shrinkResources
সম্পত্তি দ্বারা নিয়ন্ত্রিত হয় না এবং এটি অক্ষম করা যায় না, কারণ একাধিক সংস্থান যখন আপনার কোডটি সন্ধান করছে তার সাথে মেলে তখন ত্রুটিগুলি এড়াতে হবে।
রিসোর্স মার্জিং কেবল তখনই ঘটে যখন দুটি বা ততোধিক ফাইল একটি অভিন্ন সংস্থান নাম, প্রকার এবং বাছাইপর্ব ভাগ করে। গ্রেডল নির্বাচন করে কোন ফাইল এটি নকলগুলির মধ্যে সেরা পছন্দ হিসাবে বিবেচনা করে (নীচে বর্ণিত একটি অগ্রাধিকার আদেশের ভিত্তিতে) এবং চূড়ান্ত নিদর্শনটিতে বিতরণের জন্য এএপিতে কেবল সেই একটি সংস্থান পাস করে।
গ্রেডল নিম্নলিখিত স্থানগুলিতে সদৃশ সংস্থানগুলি সন্ধান করে:
- প্রধান উত্স সেটের সাথে যুক্ত প্রধান সংস্থানগুলি সাধারণত
src/main/res/
এ অবস্থিত। - বিল্ড টাইপ এবং বিল্ড স্বাদগুলি থেকে বৈকল্পিক ওভারলেগুলি।
- গ্রন্থাগার প্রকল্প নির্ভরতা।
গ্রেডল নিম্নলিখিত ক্যাসকেডিং অগ্রাধিকার আদেশে সদৃশ সংস্থানগুলিকে একীভূত করে:
নির্ভরতা → প্রধান → বিল্ড স্বাদ → বিল্ড টাইপ
উদাহরণস্বরূপ, যদি আপনার মূল সংস্থান এবং একটি বিল্ড স্বাদে কোনও সদৃশ সংস্থান উপস্থিত হয় তবে গ্রেডল বিল্ড স্বাদে একটি নির্বাচন করে।
যদি অভিন্ন সংস্থানগুলি একই উত্স সেটে উপস্থিত হয় তবে গ্রেডল সেগুলি মার্জ করতে পারে না এবং একটি সংস্থান মার্জ ত্রুটি নির্গত করে। আপনি যদি আপনার build.gradle.kts
ফাইলের sourceSet
সম্পত্তিতে একাধিক উত্স সেটগুলি সংজ্ঞায়িত src/main/res2/
src/main/res/
ঘটতে পারে example
আপনার কোডটি obfuscate
অপব্যবহারের উদ্দেশ্য হ'ল আপনার অ্যাপের ক্লাস, পদ্ধতি এবং ক্ষেত্রগুলির নাম সংক্ষিপ্ত করে আপনার অ্যাপ্লিকেশন আকার হ্রাস করা। নিম্নলিখিতটি আর 8 ব্যবহার করে অবহেলা করার একটি উদাহরণ:
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
যদিও অবরুদ্ধকরণ আপনার অ্যাপ্লিকেশন থেকে কোড সরিয়ে দেয় না, ডেক্স ফাইলগুলির সাথে অ্যাপ্লিকেশনগুলিতে উল্লেখযোগ্য আকারের সঞ্চয় দেখা যায় যা অনেকগুলি শ্রেণি, পদ্ধতি এবং ক্ষেত্রগুলিকে সূচক করে। যাইহোক, অবহেলা যেমন আপনার কোডের বিভিন্ন অংশের নামকরণ করে, নির্দিষ্ট কাজগুলি যেমন স্ট্যাক ট্রেসগুলি পরিদর্শন করার জন্য অতিরিক্ত সরঞ্জামগুলির প্রয়োজন হয়। অবজ্ঞার পরে আপনার স্ট্যাকট্রেস বুঝতে, কীভাবে একটি অবরুদ্ধ স্ট্যাক ট্রেস ডিকোড করবেন সে সম্পর্কে বিভাগটি পড়ুন।
অধিকন্তু, যদি আপনার কোডটি আপনার অ্যাপ্লিকেশনটির পদ্ধতি এবং ক্লাসগুলির জন্য অনুমানযোগ্য নামকরণের উপর নির্ভর করে - যখন প্রতিবিম্ব ব্যবহার করে, উদাহরণস্বরূপ, আপনার এই স্বাক্ষরগুলি প্রবেশের পয়েন্ট হিসাবে বিবেচনা করা উচিত এবং তাদের জন্য বিধিগুলি নির্দিষ্ট করা উচিত, যেমনটি কোন কোডটি কাস্টমাইজ করবেন সে সম্পর্কে বিভাগে বর্ণিত হিসাবে রাখা এই নিয়মগুলি আর 8 কে কেবল আপনার অ্যাপ্লিকেশনটির চূড়ান্ত ডেক্সে সেই কোডটি রাখতে পারে না তবে এর মূল নামকরণটি ধরে রাখতে পারে।
একটি অবহেলিত স্ট্যাক ট্রেস ডিকোড
আর 8 আপনার কোডটিকে অবহেলা করার পরে, একটি স্ট্যাক ট্রেস বোঝা কঠিন (যদি অসম্ভব না হয়) কারণ ক্লাস এবং পদ্ধতির নাম পরিবর্তন করা যেতে পারে। মূল স্ট্যাক ট্রেস পেতে আপনার স্ট্যাক ট্রেসটি প্রত্যাহার করা উচিত।
কোড অপ্টিমাইজেশান
আপনার অ্যাপ্লিকেশনটিকে আরও অপ্টিমাইজ করার জন্য, আর 8 আপনার কোডটি আরও অব্যবহৃত কোড অপসারণ করতে আরও গভীর স্তরে বা যেখানে সম্ভব, আপনার কোডটিকে কম ভার্বোজ করার জন্য পুনরায় লিখুন। নিম্নলিখিত এই জাতীয় অপ্টিমাইজেশনের কয়েকটি উদাহরণ রয়েছে:
- যদি আপনার কোডটি কোনও প্রদত্ত আইএফ/অন্য বিবৃতিটির জন্য
else {}
শাখা কখনও গ্রহণ করে না, আর 8else {}
শাখার জন্য কোডটি সরিয়ে ফেলতে পারে। - যদি আপনার কোডটি কেবল কয়েকটি জায়গায় কোনও পদ্ধতি কল করে তবে আর 8 পদ্ধতিটি সরিয়ে ফেলতে পারে এবং কয়েকটি কল সাইটে এটি ইনলাইন করতে পারে।
- যদি আর 8 নির্ধারণ করে যে কোনও শ্রেণীর কেবলমাত্র একটি অনন্য সাবক্লাস রয়েছে, এবং শ্রেণি নিজেই তাত্ক্ষণিক হয় না (উদাহরণস্বরূপ, কেবল একটি কংক্রিট বাস্তবায়ন শ্রেণীর দ্বারা ব্যবহৃত একটি বিমূর্ত বেস শ্রেণি), তবে আর 8 দুটি শ্রেণিকে একত্রিত করতে পারে এবং অ্যাপ্লিকেশন থেকে একটি শ্রেণি অপসারণ করতে পারে .
- আরও জানতে, জ্যাক ওয়ার্টনের আর 8 অপ্টিমাইজেশন ব্লগ পোস্টগুলি পড়ুন।
আর 8 আপনাকে বিচ্ছিন্ন অপ্টিমাইজেশনগুলি অক্ষম বা সক্ষম করতে বা কোনও অপ্টিমাইজেশনের আচরণ সংশোধন করতে দেয় না। প্রকৃতপক্ষে, আর 8 এমন কোনও অগ্রণী নিয়মকে উপেক্ষা করে যা ডিফল্ট অপ্টিমাইজেশনগুলিকে সংশোধন করার চেষ্টা করে, যেমন -optimizations
এবং -optimizationpasses
। এই বিধিনিষেধটি গুরুত্বপূর্ণ কারণ, আর 8 যেমন উন্নতি অব্যাহত রেখেছে, অপ্টিমাইজেশনের জন্য একটি স্ট্যান্ডার্ড আচরণ বজায় রাখা অ্যান্ড্রয়েড স্টুডিও দলকে সহজেই সমস্যা সমাধান করতে এবং আপনার মুখোমুখি হতে পারে এমন কোনও সমস্যা সমাধান করতে সহায়তা করে।
নোট করুন যে সক্ষমকরণ অপ্টিমাইজেশন আপনার অ্যাপ্লিকেশনটির জন্য স্ট্যাক ট্রেসগুলি পরিবর্তন করবে। উদাহরণস্বরূপ, ইনলাইনিং স্ট্যাক ফ্রেমগুলি সরিয়ে ফেলবে। মূল স্ট্যাক ট্রেসগুলি কীভাবে পেতে হয় তা শিখতে retracing সম্পর্কিত বিভাগটি দেখুন।
রানটাইম পারফরম্যান্সে প্রভাব
যদি সঙ্কুচিত হওয়া, অবহেলা এবং অপ্টিমাইজেশন সমস্ত সক্ষম হয় তবে আর 8 কোডের রানটাইম পারফরম্যান্স (ইউআই থ্রেডে স্টার্টআপ এবং ফ্রেম সময় সহ) 30%পর্যন্ত উন্নত করবে। এর মধ্যে যে কোনও একটি অক্ষম করা অপ্টিমাইজেশন আর 8 ব্যবহারের সেটকে সীমাবদ্ধ করে।
যদি আর 8 সক্ষম করা থাকে তবে আপনার আরও ভাল স্টার্টআপ পারফরম্যান্সের জন্য স্টার্টআপ প্রোফাইলও তৈরি করা উচিত।
আরও আক্রমণাত্মক অপ্টিমাইজেশন সক্ষম করুন
আর 8 এ অতিরিক্ত অপ্টিমাইজেশনের একটি সেট অন্তর্ভুক্ত করে ("সম্পূর্ণ মোড" হিসাবে পরিচিত) যা এটি প্রোগুয়ার্ড থেকে আলাদা আচরণ করে। অ্যান্ড্রয়েড গ্রেডল প্লাগইন সংস্করণ 8.0.0 থেকে এই অপ্টিমাইজেশনগুলি ডিফল্টরূপে সক্ষম করা হয়েছে।
আপনি আপনার প্রকল্পের gradle.properties
নিম্নলিখিতগুলি অন্তর্ভুক্ত করে এই অতিরিক্ত অপ্টিমাইজেশনগুলি অক্ষম করতে পারেন opproperties ফাইল:
android.enableR8.fullMode=false
যেহেতু অতিরিক্ত অপ্টিমাইজেশনগুলি আর 8 কে প্রোগুয়ার্ড থেকে আলাদাভাবে আচরণ করে, আপনি যদি প্রোগুয়ার্ডের জন্য ডিজাইন করা বিধিগুলি ব্যবহার করেন তবে রানটাইম সমস্যাগুলি এড়াতে তাদের অতিরিক্ত অগ্রগতি বিধিগুলি অন্তর্ভুক্ত করার প্রয়োজন হতে পারে। উদাহরণস্বরূপ, বলুন যে আপনার কোডটি জাভা রিফ্লেকশন এপিআইয়ের মাধ্যমে একটি শ্রেণীর উল্লেখ করে। "ফুল মোড" ব্যবহার না করার সময়, আর 8 ধরে নেয় যে আপনি রানটাইমে সেই শ্রেণীর অবজেক্টগুলি পরীক্ষা করতে এবং ম্যানিপুলেট করতে চান - এমনকি আপনার কোডটি আসলে না হলেও - এবং এটি স্বয়ংক্রিয়ভাবে শ্রেণি এবং এর স্ট্যাটিক ইনিশিয়ালাইজারকে রাখে।
যাইহোক, "ফুল মোড" ব্যবহার করার সময়, আর 8 এই ধারণাটি তৈরি করে না এবং, যদি আর 8 দৃ ser ়ভাবে জানায় যে আপনার কোডটি অন্যথায় রানটাইমে ক্লাসটি কখনও ব্যবহার করে না, তবে এটি আপনার অ্যাপের চূড়ান্ত ডেক্স থেকে ক্লাসটি সরিয়ে দেয়। এটি হ'ল, আপনি যদি ক্লাস এবং এর স্ট্যাটিক ইনিশিয়ালাইজার রাখতে চান তবে এটি করার জন্য আপনাকে আপনার নিয়ম ফাইলের একটি রাখার নিয়ম অন্তর্ভুক্ত করতে হবে।
আপনি যদি আর 8 এর "পূর্ণ মোড" ব্যবহার করার সময় কোনও সমস্যার মুখোমুখি হন তবে কোনও সম্ভাব্য সমাধানের জন্য আর 8 এফএকিউ পৃষ্ঠাটি দেখুন। আপনি যদি সমস্যাটি সমাধান করতে অক্ষম হন তবে দয়া করে একটি বাগের প্রতিবেদন করুন ।
স্ট্যাকট্রেসগুলি retracing
আর 8 দ্বারা প্রক্রিয়াজাত কোডটি বিভিন্ন উপায়ে পরিবর্তন করা হয়েছে যা স্ট্যাক ট্রেসগুলি বুঝতে আরও শক্ত করে তুলতে পারে কারণ স্ট্যাক ট্রেসগুলি সোর্স কোডের সাথে হুবহু মিলবে না। ডিবাগিংয়ের তথ্য না রাখা হলে লাইন সংখ্যাগুলিতে পরিবর্তনের ক্ষেত্রে এটি হতে পারে। এটি ইনলাইনিং এবং রূপরেখার মতো অপ্টিমাইজেশনের কারণে হতে পারে। বৃহত্তম অবদানকারী হ'ল অবহেলা যেখানে ক্লাস এবং পদ্ধতিগুলিও নাম পরিবর্তন করবে।
মূল স্ট্যাক ট্রেসটি পুনরুদ্ধার করতে, আর 8 রিট্রেস কমান্ড-লাইন সরঞ্জাম সরবরাহ করে, যা কমান্ড-লাইন সরঞ্জাম প্যাকেজের সাথে বান্ডিলযুক্ত।
আপনার অ্যাপ্লিকেশনটির স্ট্যাক ট্রেসগুলি প্রত্যাহার সমর্থন করার জন্য, আপনার মডিউলটির proguard-rules.pro
ফাইলটিতে নিম্নলিখিত নিয়মগুলি যুক্ত করে বিল্ডটি প্রত্যাহার করার জন্য পর্যাপ্ত তথ্য ধরে রাখার বিষয়টি নিশ্চিত করা উচিত:
-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile
LineNumberTable
অ্যাট্রিবিউট এমন পদ্ধতিগুলিতে অবস্থানগত তথ্য ধরে রাখে যেমন সেই অবস্থানগুলি স্ট্যাক ট্রেসগুলিতে মুদ্রিত হয়। SourceFile
বৈশিষ্ট্যটি নিশ্চিত করে যে সমস্ত সম্ভাব্য রানটাইমগুলি আসলে অবস্থানগত তথ্য মুদ্রণ করে। -renamesourcefileattribute
নির্দেশিকা স্ট্যাক ট্রেসগুলিতে উত্স ফাইলের নামটি কেবল SourceFile
সেট করে। রিট্রাকিংয়ের সময় আসল আসল উত্স ফাইলের নামটি প্রয়োজন হয় না কারণ ম্যাপিং ফাইলটিতে মূল উত্স ফাইল রয়েছে।
আর 8 প্রতিবার এটি চালানোর সময় একটি mapping.txt
ফাইল তৈরি করে, এতে মূল স্ট্যাক ট্রেসগুলিতে স্ট্যাক ট্রেসগুলি ম্যাপ করার জন্য প্রয়োজনীয় তথ্য রয়েছে। অ্যান্ড্রয়েড স্টুডিও <module-name> /build/outputs/mapping/ <build-type> /
ডিরেক্টরিতে ফাইলটি সংরক্ষণ করে।
গুগল প্লেতে আপনার অ্যাপ্লিকেশন প্রকাশ করার সময়, আপনি আপনার অ্যাপের প্রতিটি সংস্করণের জন্য mapping.txt
ফাইলটি আপলোড করতে পারেন। অ্যান্ড্রয়েড অ্যাপ্লিকেশন বান্ডিলগুলি ব্যবহার করে প্রকাশের সময় এই ফাইলটি অ্যাপ বান্ডিল সামগ্রীর অংশ হিসাবে স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত করা হয়। তারপরে গুগল প্লে ব্যবহারকারী-প্রতিবেদনিত সমস্যাগুলি থেকে আগত স্ট্যাক ট্রেসগুলি প্রত্যাহার করবে যাতে আপনি এগুলি প্লে কনসোলে পর্যালোচনা করতে পারেন। আরও তথ্যের জন্য, ক্র্যাশ স্ট্যাক ট্রেসগুলি কীভাবে ডিওবফাসেট করা যায় সে সম্পর্কে সহায়তা কেন্দ্রের নিবন্ধটি দেখুন।
আর 8 এর সাথে সমস্যা সমাধান করুন
এই বিভাগটি আর 8 ব্যবহার করে সঙ্কুচিত হওয়া, অবহেলা এবং অপ্টিমাইজেশন সক্ষম করার সময় সমস্যা সমাধানের বিষয়গুলির জন্য কিছু কৌশল বর্ণনা করে। আপনি যদি নীচে আপনার ইস্যুটির কোনও সমাধান খুঁজে না পান তবে আর 8 এফএকিউ পৃষ্ঠা এবং প্রোগুয়ার্ডের সমস্যা সমাধানের গাইডও পড়ুন।
সরানো (বা রাখা) কোডের একটি প্রতিবেদন তৈরি করুন
আপনাকে কিছু আর 8 ইস্যু সমস্যা সমাধানে সহায়তা করতে, আর 8 আপনার অ্যাপ্লিকেশন থেকে সরানো সমস্ত কোডের একটি প্রতিবেদন দেখতে কার্যকর হতে পারে। প্রতিটি মডিউল যার জন্য আপনি এই প্রতিবেদনটি তৈরি করতে চান তার জন্য, আপনার কাস্টম বিধি ফাইলটিতে -printusage <output-dir>/usage.txt
যুক্ত করুন। When you enable R8 and build your app, R8 outputs a report with the path and file name you specified. The report of removed code looks similar to the following:
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
...
If instead you want to see a report of the entry points that R8 determines from your project's keep rules , include -printseeds <output-dir>/seeds.txt
in your custom rules file. When you enable R8 and build your app, R8 outputs a report with the path and file name you specified. The report of kept entry points looks similar to the following:
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
...
Troubleshoot resource shrinking
When you shrink resources, the Build window shows a summary of the resources that are removed from the app. (You need to first click Toggle view on the left side of the window to display detailed text output from Gradle.) For example:
:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
Gradle also creates a diagnostic file named resources.txt
in <module-name>/build/outputs/mapping/release/
(the same folder as ProGuard's output files). This file includes details such as which resources reference other resources and which resources are used or removed.
For example, to find out why @drawable/ic_plus_anim_016
is still in your app, open the resources.txt
file and search for that file name. You might find that it's referenced from another resource, as follows:
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
You now need to know why @drawable/add_schedule_fab_icon_anim
is reachable—and if you search upwards you'll find that resource is listed under "The root reachable resources are:". This means there is a code reference to add_schedule_fab_icon_anim
(that is, its R.drawable ID was found in the reachable code).
If you are not using strict checking, resource IDs can be marked as reachable if there are string constants that look like they might be used to construct resource names for dynamically loaded resources. In that case, if you search the build output for the resource name, you might find a message like this:
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.
If you see one of these strings and you are certain that the string is not being used to load the given resource dynamically, you can use the tools:discard
attribute to inform the build system to remove it, as described in the section about how to customize which resources to keep .
To make your app as small and fast as possible, you should optimize and minify your release build with isMinifyEnabled = true
.
Doing so enables shrinking , which removes unused code and resources; obfuscation , which shortens the names of your app's classes and members; and optimization , which applies more aggressive strategies to further reduce the size and improve the performance of your app. This page describes how R8 performs these compile-time tasks for your project and how you can customize them.
When you build your project using Android Gradle plugin 3.4.0 or higher, the plugin no longer uses ProGuard to perform compile-time code optimization. Instead, the plugin works with the R8 compiler to handle the following compile-time tasks:
- Code shrinking (or tree-shaking): detects and safely removes unused classes, fields, methods, and attributes from your app and its library dependencies (making it a valuable tool for working around the 64k reference limit ). For example, if you use only a few APIs of a library dependency, shrinking can identify library code that your app is not using and remove only that code from your app. To learn more, go to the section about how to shrink your code .
- Resource shrinking: removes unused resources from your packaged app, including unused resources in your app's library dependencies. It works in conjunction with code shrinking such that once unused code has been removed, any resources no longer referenced can be safely removed as well. To learn more, go to the section about how to shrink your resources .
- Optimization: inspects and rewrites your code to improve runtime performance and further reduce the size of your app's DEX files. This improves runtime performance of code by up to 30%, drastically improving startup and frame timing. For example, if R8 detects that the
else {}
branch for a given if/else statement is never taken, R8 removes the code for theelse {}
branch. To learn more, go to the section about code optimization . - Obfuscation (or identifier minification): shortens the name of classes and members, which results in reduced DEX file sizes. To learn more, go to the section about how to obfuscate your code .
When building the release version of your app, R8 can be configured to perform the compile-time tasks described above for you. You can also disable certain tasks or customize R8's behavior through ProGuard rules files. In fact, R8 works with all of your existing ProGuard rules files , so updating the Android Gradle plugin to use R8 should not require you to change your existing rules.
Enable shrinking, obfuscation, and optimization
When you use Android Studio 3.4 or Android Gradle plugin 3.4.0 and higher, R8 is the default compiler that converts your project's Java bytecode into the DEX format that runs on the Android platform. However, when you create a new project using Android Studio, shrinking, obfuscation, and code optimization is not enabled by default. That's because these compile-time optimizations increase the build time of your project and might introduce bugs if you do not sufficiently customize which code to keep .
So, it's best to enable these compile-time tasks when building the final version of your app that you test prior to publishing. To enable shrinking, obfuscation, and optimization, include the following in your project-level build script.
কোটলিন
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 configuration files
R8 uses ProGuard rules files to modify its default behavior and better understand your app's structure, such as the classes that serve as entry points into your app's code. Although you can modify some of these rules files, some rules may be generated automatically by compile-time tools, such as AAPT2, or inherited from your app's library dependencies. The table below describes the sources of ProGuard rules files that R8 uses.
উৎস | অবস্থান | বর্ণনা |
অ্যান্ড্রয়েড স্টুডিও | <module-dir>/proguard-rules.pro | When you create a new module using Android Studio, the IDE creates a proguard-rules.pro file in the root directory of that module.ডিফল্টরূপে, এই ফাইলটি কোনো নিয়ম প্রয়োগ করে না। So, include your own ProGuard rules here, such as your custom keep rules . |
Android Gradle plugin | Generated by the Android Gradle plugin at compile time. | The Android Gradle plugin generates proguard-android-optimize.txt , which includes rules that are useful to most Android projects and enables @Keep* annotations .By default, when creating a new module using Android Studio, the module-level build script includes this rules file in your release build for you. Note: The Android Gradle plugin includes additional predefined ProGuard rules files, but it is recommended that you use |
Library dependencies | In an AAR library: In a JAR library: In addition to these locations, Android Gradle plugin 3.6 or higher also supports targeted shrink rules . | If an AAR or JAR library is published with its own rules file, and you include that library as a compile-time dependency, R8 automatically applies those rules when compiling your project. In addition to conventional ProGuard rules, Android Gradle plugin 3.6 or higher also supports targeted shrink rules . These are rules that target specific shrinkers (R8 or ProGuard), as well as specific shrinker versions. Using rules files that are packaged with libraries is useful if certain rules are required for the library to function properly—that is, the library developer has performed the troubleshooting steps for you. However, you should be aware that, because the rules are additive , certain rules that a library dependency includes cannot be removed and might impact the compilation of other parts of your app. For example, if a library includes a rule to disable code optimizations, that rule disables optimizations for your entire project. |
Android Asset Package Tool 2 (AAPT2) | After building your project with minifyEnabled true : <module-dir>/build/intermediates/aapt_proguard_file/.../aapt_rules.txt | AAPT2 generates keep rules based on references to classes in your app's manifest, layouts, and other app resources. For example, AAPT2 includes a keep rule for each Activity that you register in your app's manifest as an entry point. |
কাস্টম কনফিগারেশন ফাইল | By default, when you create a new module using Android Studio, the IDE creates <module-dir>/proguard-rules.pro for you to add your own rules. | You can include additional configurations , and R8 applies them at compile-time. |
When you set the minifyEnabled
property to true
, R8 combines rules from all the available sources listed above. This is important to remember when you troubleshoot with R8 , because other compile-time dependencies, such as library dependencies, may introduce changes to the R8 behavior that you do not know about.
To output a full report of all the rules that R8 applies when building your project, include the following in your module's proguard-rules.pro
file:
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt
Targeted shrink rules
Android Gradle plugin 3.6 or higher supports libraries' rules that target specific shrinkers (R8 or ProGuard), as well as specific shrinker versions. This allows library developers to tailor their rules to work optimally in projects that use new shrinker versions, while allowing existing rules to continue to be used in projects with older shrinker versions.
To specify targeted shrink rules, library developers will need to include them at specific locations inside an AAR or JAR library, as described below.
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>
That means targeted shrink rules are stored in the META-INF/com.android.tools
directory of a JAR or in the META-INF/com.android.tools
directory inside classes.jar
of an AAR.
Under that directory, there can be multiple directories with names in the form of r8-from-<X>-upto-<Y>
or proguard-from-<X>-upto-<Y>
to indicate which versions of which shrinker the rules inside the directories are written for. Note that the -from-<X>
and -upto-<Y>
parts are optional, the <Y>
version is exclusive , and the version ranges must be continuous.
For example, r8-upto-8.0.0
, r8-from-8.0.0-upto-8.2.0
, and r8-from-8.2.0
form a valid set of targeted shrink rules. The rules under the r8-from-8.0.0-upto-8.2.0
directory will be used by R8 from version 8.0.0 up to but not including version 8.2.0.
Given that information, Android Gradle plugin 3.6 or higher will select the rules from the matching R8 directories. If a library does not specify targeted shrink rules, the Android Gradle plugin will select the rules from the legacy locations ( proguard.txt
for an AAR or META-INF/proguard/<ProGuard-rules-file>
for a JAR).
Library developers can choose to include either targeted shrink rules or legacy ProGuard rules in their libraries, or both types if they want to maintain compatibility with Android Gradle plugin older than 3.6 or other tools.
Include additional configurations
When you create a new project or module using Android Studio, the IDE creates a <module-dir>/proguard-rules.pro
file for you to include your own rules. You can also include additional rules from other files by adding them to the proguardFiles
property in your module's build script.
For example, you can add rules that are specific to each build variant by adding another proguardFiles
property in the corresponding productFlavor
block. The following Gradle file adds flavor2-rules.pro
to the flavor2
product flavor. Now, flavor2
uses all three ProGuard rules because those from the release
block are also applied.
Additionally, you can add the testProguardFiles
property, which specifies a list of ProGuard files that are included in the test APK only:
কোটলিন
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' } } }
Shrink your code
আপনি যখন minifyEnabled
প্রপার্টি true
সেট করেন তখন R8 দিয়ে কোড সঙ্কুচিত করা ডিফল্টরূপে সক্রিয় থাকে।
কোড সঙ্কুচিত (বৃক্ষ কাঁপানো নামেও পরিচিত), হল কোড অপসারণের প্রক্রিয়া যা R8 নির্ধারণ করে যে রানটাইমের প্রয়োজন হয় না। This process can greatly reduce your app's size if, for example, your app includes many library dependencies but utilizes only a small part of their functionality.
To shrink your app's code, R8 first determines all entry points into your app's code based on the combined set of configuration files . These entry points include all classes that the Android platform may use to open your app's Activities or services. Starting from each entry point, R8 inspects your app's code to build a graph of all methods, member variables, and other classes that your app might access at runtime. Code that is not connected to that graph is considered unreachable and may be removed from the app.
Figure 1 shows an app with a runtime library dependency. While inspecting the app's code, R8 determines that methods foo()
, faz()
, and bar()
are reachable from the MainActivity.class
entry point. However, class OkayApi.class
or its method baz()
is never used by your app at runtime, and R8 removes that code when shrinking your app.
R8 determines entry points through -keep
rules in the project's R8 configuration files . That is, keep rules specify classes that R8 should not discard when shrinking your app, and R8 considers those classes as possible entry points into your app. The Android Gradle plugin and AAPT2 automatically generate keep rules that are required by most app projects for you, such as your app's activities, views, and services. However, if you need to customize this default behavior with additional keep rules, read the section about how to customize which code to keep .
If instead you are interested only in reducing the size of your app's resources, skip to the section about how to shrink your resources .
Note that if a library project is shrunk, an app that depends on that library includes shrunk library classes. You might need to adjust library keep rules if there are missing classes in the library APK. If you're building and publishing a library in AAR format, local JAR files that your library depends on aren't shrunk in the AAR file.
Customize which code to keep
For most situations, the default ProGuard rules file ( proguard-android-optimize.txt
) is sufficient for R8 to remove only the unused code. However, some situations are difficult for R8 to analyze correctly and it might remove code your app actually needs. Some examples of when it might incorrectly remove code include:
- When your app calls a method from the Java Native Interface (JNI)
- When your app looks up code at runtime (such as with reflection)
Testing your app should reveal any errors caused by inappropriately removed code, but you can also inspect what code was removed by generating a report of removed code .
To fix errors and force R8 to keep certain code, add a -keep
line in the ProGuard rules file. যেমন:
-keep public class MyClass
Alternatively, you can add the @Keep
annotation to the code you want to keep. Adding @Keep
on a class keeps the entire class as-is. Adding it on a method or field will keep the method/field (and its name) as well as the class name intact. Note that this annotation is available only when using the AndroidX Annotations Library and when you include the ProGuard rules file that is packaged with the Android Gradle plugin, as described in the section about how to enable shrinking .
There are many considerations you should make when using the -keep
option; for more information about customizing your rules file, read the ProGuard Manual . The Troubleshooting section outlines other common problems you might encounter when your code gets stripped away.
Strip native libraries
By default, native code libraries are stripped in release builds of your app. This stripping consists of removing the symbol table and debugging information contained in any native libraries used by your app. Stripping native code libraries results in significant size savings; however, it's impossible to diagnose crashes on the Google Play Console due to the missing information (such as class and function names).
Native crash support
The Google Play Console reports native crashes under Android vitals . With a few steps, you can generate and upload a native debug symbols file for your app. This file enables symbolicated native crash stack traces (that include class and function names) in Android vitals to help you debug your app in production. These steps vary depending on the version of the Android Gradle plugin used in your project and the build output of your project.
Android Gradle plugin version 4.1 or later
If your project builds an Android App Bundle, you can automatically include the native debug symbols file in it. To include this file in release builds, add the following to your app's build.gradle.kts
file:
android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }
Select the debug symbol level from the following:
- Use
SYMBOL_TABLE
to get function names in the Play Console's symbolicated stack traces. This level supports tombstones . - Use
FULL
to get function names, files, and line numbers in the Play Console's symbolicated stack traces.
If your project builds an APK, use the build.gradle.kts
build setting shown earlier to generate the native debug symbols file separately. Manually upload the native debug symbols file to the Google Play Console. বিল্ড প্রক্রিয়ার অংশ হিসাবে, অ্যান্ড্রয়েড গ্রেডল প্লাগইন এই ফাইলটিকে নিম্নলিখিত প্রকল্পের অবস্থানে আউটপুট করে:
app/build/outputs/native-debug-symbols/ variant-name /native-debug-symbols.zip
Android Gradle plugin version 4.0 or earlier (and other build systems)
As part of the build process, the Android Gradle plugin keeps a copy of the unstripped libraries in a project directory. This directory structure is similar to the following:
app/build/intermediates/cmake/universal/release/obj/
├── armeabi-v7a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── arm64-v8a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── x86/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
└── x86_64/
├── libgameengine.so
├── libothercode.so
└── libvideocodec.so
এই ডিরেক্টরির বিষয়বস্তু জিপ আপ করুন:
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
Manually upload the
symbols.zip
file to the Google Play Console.
Shrink your resources
Resource shrinking works only in conjunction with code shrinking. After the code shrinker removes all unused code, the resource shrinker can identify which resources the app still uses. This is especially true when you add code libraries that include resources—you must remove unused library code so the library resources become unreferenced and, thus, removable by the resource shrinker.
To enable resource shrinking, set the shrinkResources
property to true
in your build script (alongside minifyEnabled
for code shrinking). যেমন:
কোটলিন
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' } } }
If you haven't already built your app using minifyEnabled
for code shrinking, then try that before enabling shrinkResources
, because you might need to edit your proguard-rules.pro
file to keep classes or methods that are created or invoked dynamically before you start removing সম্পদ
Customize which resources to keep
If there are specific resources you wish to keep or discard, create an XML file in your project with a <resources>
tag and specify each resource to keep in the tools:keep
attribute and each resource to discard in the tools:discard
attribute. Both attributes accept a comma-separated list of resource names. You can use the asterisk character as a wild card.
যেমন:
<?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" />
Save this file in your project resources, for example, at res/raw/my.package.keep.xml
. The build does not package this file into your app.
Note: Make sure to use a unique name for the keep
file. When different libraries get linked together their keep rules would conflict otherwise, causing potential issues with ignored rules or unneeded kept resources.
Specifying which resources to discard might seem silly when you could instead delete them, but this can be useful when using build variants. For example, you might put all your resources into the common project directory, then create a different my.package.build.variant.keep.xml
file for each build variant when you know that a given resource appears to be used in code (and therefore not removed by the shrinker) but you know it actually won't be used for the given build variant. It's also possible that the build tools incorrectly identified a resource as needed, which is possible because the compiler adds the resource IDs inline and then the resource analyzer might not know the difference between a genuinely referenced resource and an integer value in the code that happens to একই মান আছে।
Enable strict reference checks
Normally, the resource shrinker can accurately determine whether a resource is used. However, if your code makes a call to Resources.getIdentifier()
(or if any of your libraries do that—the AppCompat library does), that means your code is looking up resource names based on dynamically-generated strings. When you do this, the resource shrinker behaves defensively by default and marks all resources with a matching name format as potentially used and unavailable for removal.
For example, the following code causes all resources with the img_
prefix to be marked as used.
কোটলিন
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());
The resource shrinker also looks through all the string constants in your code, as well as various res/raw/
resources, looking for resource URLs in a format similar to file:///android_res/drawable//ic_plus_anim_016.png
. If it finds strings like this or others that look like they could be used to construct URLs like this, it doesn't remove them.
These are examples of the safe shrinking mode that is enabled by default. You can, however, turn off this "better safe than sorry" handling, and specify that the resource shrinker keep only resources that it's certain are used. To do this, set shrinkMode
to strict
in the keep.xml
file, as follows:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />
If you do enable strict shrinking mode and your code also references resources with dynamically-generated strings, as shown above, then you must manually keep those resources using the tools:keep
attribute.
Remove unused alternative resources
The Gradle resource shrinker removes only resources that are not referenced by your app code, which means it will not remove alternative resources for different device configurations. If necessary, you can use the Android Gradle plugin's resConfigs
property to remove alternative resource files that your app does not need.
For example, if you are using a library that includes language resources (such as AppCompat or Google Play Services), then your app includes all translated language strings for the messages in those libraries whether the rest of your app is translated to the same languages or না If you'd like to keep only the languages that your app officially supports, you can specify those languages using the resConfig
property. Any resources for languages not specified are removed.
The following snippet shows how to limit your language resources to just English and French:
কোটলিন
android { defaultConfig { ... resourceConfigurations.addAll(listOf("en", "fr")) } }
গ্রোভি
android { defaultConfig { ... resConfigs "en", "fr" } }
When releasing an app using the Android App Bundle format, by default only languages configured on a user's device are downloaded when installing the app. Similarly, only resources matching the device's screen density, and native libraries matching the device's ABI are included in the download. For more information refer to the Android App Bundle configuration .
For legacy apps releasing with APKs (created before August 2021), you can customize which screen density or ABI resources to include in your APK by building multiple APKs that each target a different device configuration.
Merge duplicate resources
By default, Gradle also merges identically named resources, such as drawables with the same name that might be in different resource folders. This behavior is not controlled by the shrinkResources
property and cannot be disabled, because it is necessary to avoid errors when multiple resources match the name your code is looking up.
Resource merging occurs only when two or more files share an identical resource name, type, and qualifier. Gradle selects which file it considers to be the best choice among the duplicates (based on a priority order described below) and passes only that one resource to the AAPT for distribution in the final artifact.
Gradle looks for duplicate resources in the following locations:
- The main resources, associated with the main source set, generally located in
src/main/res/
. - The variant overlays, from the build type and build flavors.
- The library project dependencies.
Gradle merges duplicate resources in the following cascading priority order:
Dependencies → Main → Build flavor → Build type
For example, if a duplicate resource appears in both your main resources and a build flavor, Gradle selects the one in the build flavor.
If identical resources appear in the same source set, Gradle cannot merge them and emits a resource merge error. This can happen if you define multiple source sets in the sourceSet
property of your build.gradle.kts
file—for example if both src/main/res/
and src/main/res2/
contain identical resources.
Obfuscate your code
The purpose of obfuscation is to reduce your app size by shortening the names of your app's classes, methods, and fields. The following is an example of obfuscation using 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
While obfuscation does not remove code from your app, significant size savings can be seen in apps with DEX files that index many classes, methods, and fields. However, as obfuscation renames different parts of your code, certain tasks, such as inspecting stack traces, require additional tools. To understand your stacktrace after obfuscation, read the section about how to decode an obfuscated stack trace .
Additionally, if your code relies on predictable naming for your app's methods and classes—when using reflection, for example, you should treat those signatures as entry points and specify keep rules for them, as described in the section about how to customize which code to রাখা Those keep rules tell R8 to not only keep that code in your app's final DEX but also retain its original naming.
Decode an obfuscated stack trace
After R8 obfuscates your code, understanding a stack trace is difficult (if not impossible) because names of classes and methods might have been changed. To obtain the original stack trace you should retrace the stack trace .
কোড অপ্টিমাইজেশান
In order to optimize your app even further, R8 inspects your code at a deeper level to remove more unused code or, where possible, rewrite your code to make it less verbose. The following are a few examples of such optimizations:
- If your code never takes the
else {}
branch for a given if/else statement, R8 might remove the code for theelse {}
branch. - If your code calls a method in only a few places, R8 might remove the method and inline it at the few call sites.
- If R8 determines that a class has only one unique subclass, and the class itself is not instantiated (for example, an abstract base class only used by one concrete implementation class), then R8 can combine the two classes and remove a class from the app .
- To learn more, read the R8 optimization blog posts by Jake Wharton.
R8 does not allow you to disable or enable discrete optimizations, or modify the behavior of an optimization. In fact, R8 ignores any ProGuard rules that attempt to modify default optimizations, such as -optimizations
and -optimizationpasses
. This restriction is important because, as R8 continues to improve, maintaining a standard behavior for optimizations helps the Android Studio team easily troubleshoot and resolve any issues that you might encounter.
Note that enabling optimization will change the stack traces for your application. For example, inlining will remove stack frames. See the section on retracing to learn how to obtain the original stack traces.
Impact on runtime performance
If shrinking, obfuscation, and optimization are all enabled, R8 will improve runtime performance of code (including startup and frame time on the UI thread) by up to 30%. Disabling any of these drastically limits the set of optimizations R8 uses.
If R8 is enabled, you should also create Startup Profiles for even better startup performance.
Enable more aggressive optimizations
R8 includes a set of additional optimizations (referred to as "full mode") which makes it behave differently from ProGuard. These optimizations are enabled by default since Android Gradle plugin version 8.0.0 .
You can disable these additional optimizations by including the following in your project's gradle.properties
file:
android.enableR8.fullMode=false
Because the additional optimizations make R8 behave differently from ProGuard, they may require you to include additional ProGuard rules to avoid runtime issues if you're using rules designed for ProGuard. For example, say that your code references a class through the Java Reflection API. When not using "full mode," R8 assumes that you intend to examine and manipulate objects of that class at runtime—even if your code actually does not—and it automatically keeps the class and its static initializer.
However, when using "full mode", R8 does not make this assumption and, if R8 asserts that your code otherwise never uses the class at runtime, it removes the class from your app's final DEX. That is, if you want to keep the class and its static initializer, you need to include a keep rule in your rules file to do that.
If you encounter any issues while using R8's "full mode", refer to the R8 FAQ page for a possible solution. If you are unable to resolve the issue, please report a bug .
Retracing stacktraces
Code processed by R8 is changed in various ways that can make stack traces harder to understand because the stack traces won't exactly correspond to the source code. This can be the case for changes to the line numbers when debugging information is not kept. It can be due to optimizations such as inlining and outlining. The largest contributor is obfuscation where even the classes and methods will change names.
To recover the original stack trace, R8 provides the retrace command-line tool, which is bundled with the command-line tools package .
To support retracing of your application's stack traces, you should ensure the build retains sufficient information to retrace with by adding the following rules to your module's proguard-rules.pro
file:
-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile
The LineNumberTable
attribute retains positional information in methods such that those positions are printed in stack traces. The SourceFile
attribute ensures that all potential runtimes actually print the positional info. The -renamesourcefileattribute
directive sets the source file name in stack traces to just SourceFile
. The actual original source file name is not required when retracing because the mapping file contains the original source file.
R8 creates a mapping.txt
file each time it runs, which contains the information needed to map stack traces back to the original stack traces. Android Studio saves the file in the <module-name> /build/outputs/mapping/ <build-type> /
directory.
When publishing your app on Google Play, you can upload the mapping.txt
file for each version of your app. When publishing using Android App Bundles this file is included automatically as part of the app bundle content. Then Google Play will retrace incoming stack traces from user-reported issues so you can review them in the Play Console. For more information, see the Help Center article about how to deobfuscate crash stack traces .
Troubleshoot with R8
This section describes some strategies for troubleshooting issues when enabling shrinking, obfuscation, and optimization using R8. If you do not find a solution to your issue below, also read the R8 FAQ page and ProGuard's troubleshooting guide .
Generate a report of removed (or kept) code
To help you troubleshoot certain R8 issues, it may be useful to see a report of all the code that R8 removed from your app. For each module for which you want to generate this report, add -printusage <output-dir>/usage.txt
to your custom rules file. When you enable R8 and build your app, R8 outputs a report with the path and file name you specified. The report of removed code looks similar to the following:
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
...
If instead you want to see a report of the entry points that R8 determines from your project's keep rules , include -printseeds <output-dir>/seeds.txt
in your custom rules file. When you enable R8 and build your app, R8 outputs a report with the path and file name you specified. The report of kept entry points looks similar to the following:
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
...
Troubleshoot resource shrinking
When you shrink resources, the Build window shows a summary of the resources that are removed from the app. (You need to first click Toggle view on the left side of the window to display detailed text output from Gradle.) For example:
:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
Gradle also creates a diagnostic file named resources.txt
in <module-name>/build/outputs/mapping/release/
(the same folder as ProGuard's output files). This file includes details such as which resources reference other resources and which resources are used or removed.
For example, to find out why @drawable/ic_plus_anim_016
is still in your app, open the resources.txt
file and search for that file name. You might find that it's referenced from another resource, as follows:
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
You now need to know why @drawable/add_schedule_fab_icon_anim
is reachable—and if you search upwards you'll find that resource is listed under "The root reachable resources are:". This means there is a code reference to add_schedule_fab_icon_anim
(that is, its R.drawable ID was found in the reachable code).
If you are not using strict checking, resource IDs can be marked as reachable if there are string constants that look like they might be used to construct resource names for dynamically loaded resources. In that case, if you search the build output for the resource name, you might find a message like this:
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.
If you see one of these strings and you are certain that the string is not being used to load the given resource dynamically, you can use the tools:discard
attribute to inform the build system to remove it, as described in the section about how to customize which resources to keep .
To make your app as small and fast as possible, you should optimize and minify your release build with isMinifyEnabled = true
.
Doing so enables shrinking , which removes unused code and resources; obfuscation , which shortens the names of your app's classes and members; and optimization , which applies more aggressive strategies to further reduce the size and improve the performance of your app. This page describes how R8 performs these compile-time tasks for your project and how you can customize them.
When you build your project using Android Gradle plugin 3.4.0 or higher, the plugin no longer uses ProGuard to perform compile-time code optimization. Instead, the plugin works with the R8 compiler to handle the following compile-time tasks:
- Code shrinking (or tree-shaking): detects and safely removes unused classes, fields, methods, and attributes from your app and its library dependencies (making it a valuable tool for working around the 64k reference limit ). For example, if you use only a few APIs of a library dependency, shrinking can identify library code that your app is not using and remove only that code from your app. To learn more, go to the section about how to shrink your code .
- Resource shrinking: removes unused resources from your packaged app, including unused resources in your app's library dependencies. It works in conjunction with code shrinking such that once unused code has been removed, any resources no longer referenced can be safely removed as well. To learn more, go to the section about how to shrink your resources .
- Optimization: inspects and rewrites your code to improve runtime performance and further reduce the size of your app's DEX files. This improves runtime performance of code by up to 30%, drastically improving startup and frame timing. For example, if R8 detects that the
else {}
branch for a given if/else statement is never taken, R8 removes the code for theelse {}
branch. To learn more, go to the section about code optimization . - Obfuscation (or identifier minification): shortens the name of classes and members, which results in reduced DEX file sizes. To learn more, go to the section about how to obfuscate your code .
When building the release version of your app, R8 can be configured to perform the compile-time tasks described above for you. You can also disable certain tasks or customize R8's behavior through ProGuard rules files. In fact, R8 works with all of your existing ProGuard rules files , so updating the Android Gradle plugin to use R8 should not require you to change your existing rules.
Enable shrinking, obfuscation, and optimization
When you use Android Studio 3.4 or Android Gradle plugin 3.4.0 and higher, R8 is the default compiler that converts your project's Java bytecode into the DEX format that runs on the Android platform. However, when you create a new project using Android Studio, shrinking, obfuscation, and code optimization is not enabled by default. That's because these compile-time optimizations increase the build time of your project and might introduce bugs if you do not sufficiently customize which code to keep .
So, it's best to enable these compile-time tasks when building the final version of your app that you test prior to publishing. To enable shrinking, obfuscation, and optimization, include the following in your project-level build script.
কোটলিন
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 configuration files
R8 uses ProGuard rules files to modify its default behavior and better understand your app's structure, such as the classes that serve as entry points into your app's code. Although you can modify some of these rules files, some rules may be generated automatically by compile-time tools, such as AAPT2, or inherited from your app's library dependencies. The table below describes the sources of ProGuard rules files that R8 uses.
উৎস | অবস্থান | বর্ণনা |
অ্যান্ড্রয়েড স্টুডিও | <module-dir>/proguard-rules.pro | When you create a new module using Android Studio, the IDE creates a proguard-rules.pro file in the root directory of that module.ডিফল্টরূপে, এই ফাইলটি কোনো নিয়ম প্রয়োগ করে না। So, include your own ProGuard rules here, such as your custom keep rules . |
Android Gradle plugin | Generated by the Android Gradle plugin at compile time. | The Android Gradle plugin generates proguard-android-optimize.txt , which includes rules that are useful to most Android projects and enables @Keep* annotations .By default, when creating a new module using Android Studio, the module-level build script includes this rules file in your release build for you. Note: The Android Gradle plugin includes additional predefined ProGuard rules files, but it is recommended that you use |
Library dependencies | In an AAR library: In a JAR library: In addition to these locations, Android Gradle plugin 3.6 or higher also supports targeted shrink rules . | If an AAR or JAR library is published with its own rules file, and you include that library as a compile-time dependency, R8 automatically applies those rules when compiling your project. In addition to conventional ProGuard rules, Android Gradle plugin 3.6 or higher also supports targeted shrink rules . These are rules that target specific shrinkers (R8 or ProGuard), as well as specific shrinker versions. Using rules files that are packaged with libraries is useful if certain rules are required for the library to function properly—that is, the library developer has performed the troubleshooting steps for you. However, you should be aware that, because the rules are additive , certain rules that a library dependency includes cannot be removed and might impact the compilation of other parts of your app. For example, if a library includes a rule to disable code optimizations, that rule disables optimizations for your entire project. |
Android Asset Package Tool 2 (AAPT2) | After building your project with minifyEnabled true : <module-dir>/build/intermediates/aapt_proguard_file/.../aapt_rules.txt | AAPT2 generates keep rules based on references to classes in your app's manifest, layouts, and other app resources. For example, AAPT2 includes a keep rule for each Activity that you register in your app's manifest as an entry point. |
কাস্টম কনফিগারেশন ফাইল | By default, when you create a new module using Android Studio, the IDE creates <module-dir>/proguard-rules.pro for you to add your own rules. | You can include additional configurations , and R8 applies them at compile-time. |
When you set the minifyEnabled
property to true
, R8 combines rules from all the available sources listed above. This is important to remember when you troubleshoot with R8 , because other compile-time dependencies, such as library dependencies, may introduce changes to the R8 behavior that you do not know about.
To output a full report of all the rules that R8 applies when building your project, include the following in your module's proguard-rules.pro
file:
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt
Targeted shrink rules
Android Gradle plugin 3.6 or higher supports libraries' rules that target specific shrinkers (R8 or ProGuard), as well as specific shrinker versions. This allows library developers to tailor their rules to work optimally in projects that use new shrinker versions, while allowing existing rules to continue to be used in projects with older shrinker versions.
To specify targeted shrink rules, library developers will need to include them at specific locations inside an AAR or JAR library, as described below.
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>
That means targeted shrink rules are stored in the META-INF/com.android.tools
directory of a JAR or in the META-INF/com.android.tools
directory inside classes.jar
of an AAR.
Under that directory, there can be multiple directories with names in the form of r8-from-<X>-upto-<Y>
or proguard-from-<X>-upto-<Y>
to indicate which versions of which shrinker the rules inside the directories are written for. Note that the -from-<X>
and -upto-<Y>
parts are optional, the <Y>
version is exclusive , and the version ranges must be continuous.
For example, r8-upto-8.0.0
, r8-from-8.0.0-upto-8.2.0
, and r8-from-8.2.0
form a valid set of targeted shrink rules. The rules under the r8-from-8.0.0-upto-8.2.0
directory will be used by R8 from version 8.0.0 up to but not including version 8.2.0.
Given that information, Android Gradle plugin 3.6 or higher will select the rules from the matching R8 directories. If a library does not specify targeted shrink rules, the Android Gradle plugin will select the rules from the legacy locations ( proguard.txt
for an AAR or META-INF/proguard/<ProGuard-rules-file>
for a JAR).
Library developers can choose to include either targeted shrink rules or legacy ProGuard rules in their libraries, or both types if they want to maintain compatibility with Android Gradle plugin older than 3.6 or other tools.
Include additional configurations
When you create a new project or module using Android Studio, the IDE creates a <module-dir>/proguard-rules.pro
file for you to include your own rules. You can also include additional rules from other files by adding them to the proguardFiles
property in your module's build script.
For example, you can add rules that are specific to each build variant by adding another proguardFiles
property in the corresponding productFlavor
block. The following Gradle file adds flavor2-rules.pro
to the flavor2
product flavor. Now, flavor2
uses all three ProGuard rules because those from the release
block are also applied.
Additionally, you can add the testProguardFiles
property, which specifies a list of ProGuard files that are included in the test APK only:
কোটলিন
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' } } }
Shrink your code
আপনি যখন minifyEnabled
প্রপার্টি true
সেট করেন তখন R8 দিয়ে কোড সঙ্কুচিত করা ডিফল্টরূপে সক্রিয় থাকে।
কোড সঙ্কুচিত (বৃক্ষ কাঁপানো নামেও পরিচিত), হল কোড অপসারণের প্রক্রিয়া যা R8 নির্ধারণ করে যে রানটাইমের প্রয়োজন হয় না। This process can greatly reduce your app's size if, for example, your app includes many library dependencies but utilizes only a small part of their functionality.
To shrink your app's code, R8 first determines all entry points into your app's code based on the combined set of configuration files . These entry points include all classes that the Android platform may use to open your app's Activities or services. Starting from each entry point, R8 inspects your app's code to build a graph of all methods, member variables, and other classes that your app might access at runtime. Code that is not connected to that graph is considered unreachable and may be removed from the app.
Figure 1 shows an app with a runtime library dependency. While inspecting the app's code, R8 determines that methods foo()
, faz()
, and bar()
are reachable from the MainActivity.class
entry point. However, class OkayApi.class
or its method baz()
is never used by your app at runtime, and R8 removes that code when shrinking your app.
R8 determines entry points through -keep
rules in the project's R8 configuration files . That is, keep rules specify classes that R8 should not discard when shrinking your app, and R8 considers those classes as possible entry points into your app. The Android Gradle plugin and AAPT2 automatically generate keep rules that are required by most app projects for you, such as your app's activities, views, and services. However, if you need to customize this default behavior with additional keep rules, read the section about how to customize which code to keep .
If instead you are interested only in reducing the size of your app's resources, skip to the section about how to shrink your resources .
Note that if a library project is shrunk, an app that depends on that library includes shrunk library classes. You might need to adjust library keep rules if there are missing classes in the library APK. If you're building and publishing a library in AAR format, local JAR files that your library depends on aren't shrunk in the AAR file.
Customize which code to keep
For most situations, the default ProGuard rules file ( proguard-android-optimize.txt
) is sufficient for R8 to remove only the unused code. However, some situations are difficult for R8 to analyze correctly and it might remove code your app actually needs. Some examples of when it might incorrectly remove code include:
- When your app calls a method from the Java Native Interface (JNI)
- When your app looks up code at runtime (such as with reflection)
Testing your app should reveal any errors caused by inappropriately removed code, but you can also inspect what code was removed by generating a report of removed code .
To fix errors and force R8 to keep certain code, add a -keep
line in the ProGuard rules file. যেমন:
-keep public class MyClass
Alternatively, you can add the @Keep
annotation to the code you want to keep. Adding @Keep
on a class keeps the entire class as-is. Adding it on a method or field will keep the method/field (and its name) as well as the class name intact. Note that this annotation is available only when using the AndroidX Annotations Library and when you include the ProGuard rules file that is packaged with the Android Gradle plugin, as described in the section about how to enable shrinking .
There are many considerations you should make when using the -keep
option; for more information about customizing your rules file, read the ProGuard Manual . The Troubleshooting section outlines other common problems you might encounter when your code gets stripped away.
Strip native libraries
By default, native code libraries are stripped in release builds of your app. This stripping consists of removing the symbol table and debugging information contained in any native libraries used by your app. Stripping native code libraries results in significant size savings; however, it's impossible to diagnose crashes on the Google Play Console due to the missing information (such as class and function names).
Native crash support
The Google Play Console reports native crashes under Android vitals . With a few steps, you can generate and upload a native debug symbols file for your app. This file enables symbolicated native crash stack traces (that include class and function names) in Android vitals to help you debug your app in production. These steps vary depending on the version of the Android Gradle plugin used in your project and the build output of your project.
Android Gradle plugin version 4.1 or later
If your project builds an Android App Bundle, you can automatically include the native debug symbols file in it. To include this file in release builds, add the following to your app's build.gradle.kts
file:
android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }
Select the debug symbol level from the following:
- Use
SYMBOL_TABLE
to get function names in the Play Console's symbolicated stack traces. This level supports tombstones . - Use
FULL
to get function names, files, and line numbers in the Play Console's symbolicated stack traces.
If your project builds an APK, use the build.gradle.kts
build setting shown earlier to generate the native debug symbols file separately. Manually upload the native debug symbols file to the Google Play Console. বিল্ড প্রক্রিয়ার অংশ হিসাবে, অ্যান্ড্রয়েড গ্রেডল প্লাগইন এই ফাইলটিকে নিম্নলিখিত প্রকল্পের অবস্থানে আউটপুট করে:
app/build/outputs/native-debug-symbols/ variant-name /native-debug-symbols.zip
Android Gradle plugin version 4.0 or earlier (and other build systems)
As part of the build process, the Android Gradle plugin keeps a copy of the unstripped libraries in a project directory. This directory structure is similar to the following:
app/build/intermediates/cmake/universal/release/obj/
├── armeabi-v7a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── arm64-v8a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── x86/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
└── x86_64/
├── libgameengine.so
├── libothercode.so
└── libvideocodec.so
এই ডিরেক্টরির বিষয়বস্তু জিপ আপ করুন:
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
Manually upload the
symbols.zip
file to the Google Play Console.
Shrink your resources
Resource shrinking works only in conjunction with code shrinking. After the code shrinker removes all unused code, the resource shrinker can identify which resources the app still uses. This is especially true when you add code libraries that include resources—you must remove unused library code so the library resources become unreferenced and, thus, removable by the resource shrinker.
To enable resource shrinking, set the shrinkResources
property to true
in your build script (alongside minifyEnabled
for code shrinking). যেমন:
কোটলিন
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' } } }
If you haven't already built your app using minifyEnabled
for code shrinking, then try that before enabling shrinkResources
, because you might need to edit your proguard-rules.pro
file to keep classes or methods that are created or invoked dynamically before you start removing সম্পদ
Customize which resources to keep
If there are specific resources you wish to keep or discard, create an XML file in your project with a <resources>
tag and specify each resource to keep in the tools:keep
attribute and each resource to discard in the tools:discard
attribute. Both attributes accept a comma-separated list of resource names. You can use the asterisk character as a wild card.
যেমন:
<?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" />
Save this file in your project resources, for example, at res/raw/my.package.keep.xml
. The build does not package this file into your app.
Note: Make sure to use a unique name for the keep
file. When different libraries get linked together their keep rules would conflict otherwise, causing potential issues with ignored rules or unneeded kept resources.
Specifying which resources to discard might seem silly when you could instead delete them, but this can be useful when using build variants. For example, you might put all your resources into the common project directory, then create a different my.package.build.variant.keep.xml
file for each build variant when you know that a given resource appears to be used in code (and therefore not removed by the shrinker) but you know it actually won't be used for the given build variant. It's also possible that the build tools incorrectly identified a resource as needed, which is possible because the compiler adds the resource IDs inline and then the resource analyzer might not know the difference between a genuinely referenced resource and an integer value in the code that happens to একই মান আছে।
Enable strict reference checks
Normally, the resource shrinker can accurately determine whether a resource is used. However, if your code makes a call to Resources.getIdentifier()
(or if any of your libraries do that—the AppCompat library does), that means your code is looking up resource names based on dynamically-generated strings. When you do this, the resource shrinker behaves defensively by default and marks all resources with a matching name format as potentially used and unavailable for removal.
For example, the following code causes all resources with the img_
prefix to be marked as used.
কোটলিন
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());
The resource shrinker also looks through all the string constants in your code, as well as various res/raw/
resources, looking for resource URLs in a format similar to file:///android_res/drawable//ic_plus_anim_016.png
. If it finds strings like this or others that look like they could be used to construct URLs like this, it doesn't remove them.
These are examples of the safe shrinking mode that is enabled by default. You can, however, turn off this "better safe than sorry" handling, and specify that the resource shrinker keep only resources that it's certain are used. To do this, set shrinkMode
to strict
in the keep.xml
file, as follows:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />
If you do enable strict shrinking mode and your code also references resources with dynamically-generated strings, as shown above, then you must manually keep those resources using the tools:keep
attribute.
Remove unused alternative resources
The Gradle resource shrinker removes only resources that are not referenced by your app code, which means it will not remove alternative resources for different device configurations. If necessary, you can use the Android Gradle plugin's resConfigs
property to remove alternative resource files that your app does not need.
For example, if you are using a library that includes language resources (such as AppCompat or Google Play Services), then your app includes all translated language strings for the messages in those libraries whether the rest of your app is translated to the same languages or না If you'd like to keep only the languages that your app officially supports, you can specify those languages using the resConfig
property. Any resources for languages not specified are removed.
The following snippet shows how to limit your language resources to just English and French:
কোটলিন
android { defaultConfig { ... resourceConfigurations.addAll(listOf("en", "fr")) } }
গ্রোভি
android { defaultConfig { ... resConfigs "en", "fr" } }
When releasing an app using the Android App Bundle format, by default only languages configured on a user's device are downloaded when installing the app. Similarly, only resources matching the device's screen density, and native libraries matching the device's ABI are included in the download. For more information refer to the Android App Bundle configuration .
For legacy apps releasing with APKs (created before August 2021), you can customize which screen density or ABI resources to include in your APK by building multiple APKs that each target a different device configuration.
Merge duplicate resources
By default, Gradle also merges identically named resources, such as drawables with the same name that might be in different resource folders. This behavior is not controlled by the shrinkResources
property and cannot be disabled, because it is necessary to avoid errors when multiple resources match the name your code is looking up.
Resource merging occurs only when two or more files share an identical resource name, type, and qualifier. Gradle selects which file it considers to be the best choice among the duplicates (based on a priority order described below) and passes only that one resource to the AAPT for distribution in the final artifact.
Gradle looks for duplicate resources in the following locations:
- The main resources, associated with the main source set, generally located in
src/main/res/
. - The variant overlays, from the build type and build flavors.
- The library project dependencies.
Gradle merges duplicate resources in the following cascading priority order:
Dependencies → Main → Build flavor → Build type
For example, if a duplicate resource appears in both your main resources and a build flavor, Gradle selects the one in the build flavor.
If identical resources appear in the same source set, Gradle cannot merge them and emits a resource merge error. This can happen if you define multiple source sets in the sourceSet
property of your build.gradle.kts
file—for example if both src/main/res/
and src/main/res2/
contain identical resources.
Obfuscate your code
The purpose of obfuscation is to reduce your app size by shortening the names of your app's classes, methods, and fields. The following is an example of obfuscation using 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
While obfuscation does not remove code from your app, significant size savings can be seen in apps with DEX files that index many classes, methods, and fields. However, as obfuscation renames different parts of your code, certain tasks, such as inspecting stack traces, require additional tools. To understand your stacktrace after obfuscation, read the section about how to decode an obfuscated stack trace .
Additionally, if your code relies on predictable naming for your app's methods and classes—when using reflection, for example, you should treat those signatures as entry points and specify keep rules for them, as described in the section about how to customize which code to রাখা Those keep rules tell R8 to not only keep that code in your app's final DEX but also retain its original naming.
Decode an obfuscated stack trace
After R8 obfuscates your code, understanding a stack trace is difficult (if not impossible) because names of classes and methods might have been changed. To obtain the original stack trace you should retrace the stack trace .
কোড অপ্টিমাইজেশান
In order to optimize your app even further, R8 inspects your code at a deeper level to remove more unused code or, where possible, rewrite your code to make it less verbose. The following are a few examples of such optimizations:
- If your code never takes the
else {}
branch for a given if/else statement, R8 might remove the code for theelse {}
branch. - If your code calls a method in only a few places, R8 might remove the method and inline it at the few call sites.
- If R8 determines that a class has only one unique subclass, and the class itself is not instantiated (for example, an abstract base class only used by one concrete implementation class), then R8 can combine the two classes and remove a class from the app .
- To learn more, read the R8 optimization blog posts by Jake Wharton.
R8 does not allow you to disable or enable discrete optimizations, or modify the behavior of an optimization. In fact, R8 ignores any ProGuard rules that attempt to modify default optimizations, such as -optimizations
and -optimizationpasses
. This restriction is important because, as R8 continues to improve, maintaining a standard behavior for optimizations helps the Android Studio team easily troubleshoot and resolve any issues that you might encounter.
Note that enabling optimization will change the stack traces for your application. For example, inlining will remove stack frames. See the section on retracing to learn how to obtain the original stack traces.
Impact on runtime performance
If shrinking, obfuscation, and optimization are all enabled, R8 will improve runtime performance of code (including startup and frame time on the UI thread) by up to 30%. Disabling any of these drastically limits the set of optimizations R8 uses.
If R8 is enabled, you should also create Startup Profiles for even better startup performance.
Enable more aggressive optimizations
R8 includes a set of additional optimizations (referred to as "full mode") which makes it behave differently from ProGuard. These optimizations are enabled by default since Android Gradle plugin version 8.0.0 .
You can disable these additional optimizations by including the following in your project's gradle.properties
file:
android.enableR8.fullMode=false
Because the additional optimizations make R8 behave differently from ProGuard, they may require you to include additional ProGuard rules to avoid runtime issues if you're using rules designed for ProGuard. For example, say that your code references a class through the Java Reflection API. When not using "full mode," R8 assumes that you intend to examine and manipulate objects of that class at runtime—even if your code actually does not—and it automatically keeps the class and its static initializer.
However, when using "full mode", R8 does not make this assumption and, if R8 asserts that your code otherwise never uses the class at runtime, it removes the class from your app's final DEX. That is, if you want to keep the class and its static initializer, you need to include a keep rule in your rules file to do that.
If you encounter any issues while using R8's "full mode", refer to the R8 FAQ page for a possible solution. If you are unable to resolve the issue, please report a bug .
Retracing stacktraces
Code processed by R8 is changed in various ways that can make stack traces harder to understand because the stack traces won't exactly correspond to the source code. This can be the case for changes to the line numbers when debugging information is not kept. It can be due to optimizations such as inlining and outlining. The largest contributor is obfuscation where even the classes and methods will change names.
To recover the original stack trace, R8 provides the retrace command-line tool, which is bundled with the command-line tools package .
To support retracing of your application's stack traces, you should ensure the build retains sufficient information to retrace with by adding the following rules to your module's proguard-rules.pro
file:
-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile
The LineNumberTable
attribute retains positional information in methods such that those positions are printed in stack traces. The SourceFile
attribute ensures that all potential runtimes actually print the positional info. The -renamesourcefileattribute
directive sets the source file name in stack traces to just SourceFile
. The actual original source file name is not required when retracing because the mapping file contains the original source file.
R8 creates a mapping.txt
file each time it runs, which contains the information needed to map stack traces back to the original stack traces. Android Studio saves the file in the <module-name> /build/outputs/mapping/ <build-type> /
directory.
When publishing your app on Google Play, you can upload the mapping.txt
file for each version of your app. When publishing using Android App Bundles this file is included automatically as part of the app bundle content. Then Google Play will retrace incoming stack traces from user-reported issues so you can review them in the Play Console. For more information, see the Help Center article about how to deobfuscate crash stack traces .
Troubleshoot with R8
This section describes some strategies for troubleshooting issues when enabling shrinking, obfuscation, and optimization using R8. If you do not find a solution to your issue below, also read the R8 FAQ page and ProGuard's troubleshooting guide .
Generate a report of removed (or kept) code
To help you troubleshoot certain R8 issues, it may be useful to see a report of all the code that R8 removed from your app. For each module for which you want to generate this report, add -printusage <output-dir>/usage.txt
to your custom rules file. When you enable R8 and build your app, R8 outputs a report with the path and file name you specified. The report of removed code looks similar to the following:
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
...
If instead you want to see a report of the entry points that R8 determines from your project's keep rules , include -printseeds <output-dir>/seeds.txt
in your custom rules file. When you enable R8 and build your app, R8 outputs a report with the path and file name you specified. The report of kept entry points looks similar to the following:
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
...
Troubleshoot resource shrinking
When you shrink resources, the Build window shows a summary of the resources that are removed from the app. (You need to first click Toggle view on the left side of the window to display detailed text output from Gradle.) For example:
:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
Gradle also creates a diagnostic file named resources.txt
in <module-name>/build/outputs/mapping/release/
(the same folder as ProGuard's output files). This file includes details such as which resources reference other resources and which resources are used or removed.
For example, to find out why @drawable/ic_plus_anim_016
is still in your app, open the resources.txt
file and search for that file name. You might find that it's referenced from another resource, as follows:
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
You now need to know why @drawable/add_schedule_fab_icon_anim
is reachable—and if you search upwards you'll find that resource is listed under "The root reachable resources are:". This means there is a code reference to add_schedule_fab_icon_anim
(that is, its R.drawable ID was found in the reachable code).
If you are not using strict checking, resource IDs can be marked as reachable if there are string constants that look like they might be used to construct resource names for dynamically loaded resources. In that case, if you search the build output for the resource name, you might find a message like this:
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.
If you see one of these strings and you are certain that the string is not being used to load the given resource dynamically, you can use the tools:discard
attribute to inform the build system to remove it, as described in the section about how to customize which resources to keep .