যখন আপনি অ্যাপ অপ্টিমাইজেশন চালু করেন , তখন R8-এর বিভিন্ন সংস্করণের জন্য অপ্টিমাইজারের ডিফল্ট আচরণ ভিন্ন হয়।
- AGP 9.3 এবং তার পরবর্তী সংস্করণ থেকে উপলব্ধ আপডেট করা DSL-এর সাথে, অপটিমাইজেশন সক্রিয় করা হলে রিসোর্স শ্রিংকিং ডিফল্টরূপে সক্রিয় থাকে। উল্লেখ্য যে, লিগ্যাসি DSL, যার জন্য কোড এবং রিসোর্স অপটিমাইজেশন আলাদাভাবে সক্রিয় করার প্রয়োজন হয়, সেটি এখনও সমর্থিত।
AGP 9.3-এর পূর্ববর্তী সংস্করণগুলির জন্য,
isShrinkResources = trueসেটিংটি অপটিমাইজারকে অব্যবহৃত রিসোর্সগুলি সরিয়ে ফেলার নির্দেশ দেয়, যা আপনার অ্যাপের আকার কমাতে সাহায্য করে। রিসোর্স সঙ্কুচিতকরণ শুধুমাত্র কোড সঙ্কুচিতকরণের সাথে একত্রে কাজ করে, তাই আপনি যদি রিসোর্স অপটিমাইজ করেন,isMinifyEnabled = trueও সেট করুন।
এজিপি ৯.৩+ (কোটলিন)
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
এজিপি ৯.৩+ (গ্রুভি)
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
লিগ্যাসি ডিএসএল (কোটলিন)
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
...
}
}
লিগ্যাসি ডিএসএল (গ্রুভি)
buildTypes {
release {
minifyEnabled = true
shrinkResources = true
...
}
}
আপনি যদি নির্দিষ্ট রিসোর্স রাখতে বা বাদ দিতে চান, তাহলে আপনার প্রজেক্ট রিসোর্সের মধ্যে একটি XML keep ফাইল তৈরি করুন, যেমন res/raw/my.package.keep.xml । keep ফাইলটিতে নিম্নলিখিত উপাদানগুলো থাকে:
-
<resources>ট্যাগ — এর মধ্যে সকল চাইল্ড রিসোর্স এলিমেন্ট এবং কিপ/ডিসকার্ড অ্যাট্রিবিউট থাকে। -
tools:keepঅ্যাট্রিবিউট — সংরক্ষণ করার জন্য রিসোর্সগুলোর নাম কমা দিয়ে আলাদা করে একটি তালিকা হিসেবে গ্রহণ করে। -
tools:discardঅ্যাট্রিবিউট — বাতিল করার জন্য রিসোর্স শনাক্তকারী রিসোর্স নামগুলোর একটি কমা-বিভক্ত তালিকা গ্রহণ করে।
একই ফোল্ডারে একাধিক রিসোর্স উল্লেখ করতে ওয়াইল্ডকার্ড হিসেবে অ্যাস্টারিস্ক (asterisk) অক্ষরটি ব্যবহার করুন, উদাহরণস্বরূপ:
<?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" />
কোন রিসোর্সগুলো বাদ দিতে হবে তা নির্দিষ্ট করে দেওয়া অপ্রয়োজনীয় মনে হতে পারে, যখন আপনি সেগুলোর পরিবর্তে ডিলিট করে দিতে পারেন; কিন্তু বিল্ড ভ্যারিয়েন্ট ব্যবহার করার সময় রিসোর্স বাদ দেওয়াটা কার্যকর হতে পারে।
নির্দিষ্ট বিল্ড ভ্যারিয়েন্টগুলিকে লক্ষ্য করুন
শুধুমাত্র কিছু বিল্ড ভ্যারিয়েন্ট থেকে রিসোর্স অপসারণ করতে, আপনার সমস্ত রিসোর্স কমন প্রজেক্ট ডিরেক্টরিতে রাখুন, তারপর প্রতিটি বিল্ড ভ্যারিয়েন্টের রিসোর্স ডিরেক্টরিতে তার জন্য একটি ভিন্ন my.package.build.variant.keep.xml ফাইল তৈরি করুন। keep ফাইলে, ম্যানুয়ালি সেইসব রিসোর্স নির্দিষ্ট করে দিন যা অপসারণ করতে হবে, যখন কোনো নির্দিষ্ট রিসোর্স কোডে ব্যবহৃত হচ্ছে বলে মনে হয় (এবং সেই কারণে shrinker দ্বারা অপসারিত হয় না), কিন্তু আপনি জানেন যে এটি আসলে নির্দিষ্ট বিল্ড ভ্যারিয়েন্টের জন্য ব্যবহৃত হবে না।
অব্যবহৃত বিকল্প সম্পদ অপসারণ করুন
অপ্টিমাইজার শুধুমাত্র সেইসব রিসোর্স মুছে ফেলে যেগুলো আপনার অ্যাপ কোডে ব্যবহৃত হয় না, যার মানে হলো এটি বিভিন্ন ডিভাইস কনফিগারেশনের জন্য থাকা বিকল্প রিসোর্সগুলো মুছে ফেলবে না।
আপনার অ্যাপের মডিউল build.gradle ফাইলে Android Gradle-এর resConfigs প্রপার্টি ব্যবহার করে, আপনার অ্যাপের অপ্রয়োজনীয় বিকল্প রিসোর্স ফাইলগুলো সরিয়ে ফেলুন।
উদাহরণস্বরূপ, আপনি যদি এমন কোনো লাইব্রেরি ব্যবহার করেন যাতে ভাষার রিসোর্স অন্তর্ভুক্ত থাকে (যেমন গুগল প্লে সার্ভিসেস), তাহলে আপনার অ্যাপের বাকি অংশ একই ভাষায় অনূদিত হোক বা না হোক, সেই লাইব্রেরির মেসেজগুলোর জন্য আপনার অ্যাপে সমস্ত অনূদিত ভাষার স্ট্রিং অন্তর্ভুক্ত হয়ে যায়। আপনার অ্যাপ আনুষ্ঠানিকভাবে যে ভাষাগুলো সমর্থন করে, শুধু সেগুলোই রাখতে resConfigs প্রপার্টি ব্যবহার করে সেই ভাষাগুলো নির্দিষ্ট করে দিন। যে ভাষাগুলো নির্দিষ্ট করা হয়নি, সেগুলোর যেকোনো রিসোর্স মুছে ফেলা হয়।
নিম্নলিখিত কোড স্নিপেটগুলি দেখায় কিভাবে আপনার ভাষার রিসোর্সগুলিকে শুধুমাত্র ইংরেজি এবং ফরাসিতে সীমাবদ্ধ করা যায়:
android {
defaultConfig {
...
resourceConfigurations.addAll(listOf("en", "fr"))
}
}
অথবা
android {
defaultConfig {
...
resConfigs "en", "fr"
}
}
আপনি যখন অ্যান্ড্রয়েড অ্যাপ বান্ডেল (AAB) ফরম্যাট ব্যবহার করে কোনো অ্যাপ প্রকাশ করেন, তখন ডিফল্টরূপে ব্যবহারকারী অ্যাপটি ইনস্টল করার সময় শুধুমাত্র তার ডিভাইসে কনফিগার করা ভাষাগুলোই ডাউনলোড হয়। একইভাবে, ডাউনলোডে শুধুমাত্র ডিভাইসের স্ক্রিন ডেনসিটির সাথে মেলে এমন রিসোর্স এবং ডিভাইসের ABI-এর সাথে মেলে এমন নেটিভ লাইব্রেরি অন্তর্ভুক্ত থাকে। আরও তথ্যের জন্য, কনফিগারেশন APK-এর প্রকারভেদ পুনরায় সক্রিয় বা নিষ্ক্রিয় করা দেখুন।
যেসব লিগ্যাসি অ্যাপ APK সহ রিলিজ করা হচ্ছে (আগস্ট ২০২১-এর আগে তৈরি), সেগুলোর ক্ষেত্রে আপনি বিভিন্ন ডিভাইস কনফিগারেশনকে লক্ষ্য করে একাধিক APK তৈরি করার মাধ্যমে আপনার APK-তে অন্তর্ভুক্ত করার জন্য স্ক্রিন ডেনসিটি বা ABI রিসোর্স কাস্টমাইজ করতে পারেন।
রিসোর্স একত্রিত করার সময় দ্বন্দ্ব এড়িয়ে চলুন
ডিফল্টরূপে, অ্যান্ড্রয়েড গ্রেডল প্লাগইন (AGP) একই নামের রিসোর্সগুলোকে একত্রিত করে, যেমন বিভিন্ন রিসোর্স ফোল্ডারে থাকা একই নামের ড্রয়েবল। এই আচরণটি shrinkResources প্রপার্টি দ্বারা নিয়ন্ত্রিত হয় না এবং এটি নিষ্ক্রিয় করা যায় না, কারণ আপনার কোড যে নামটি ব্যবহার করছে, সেই নামে একাধিক রিসোর্স থাকলে ত্রুটি এড়াতে এই আচরণটি প্রয়োজনীয়।
রিসোর্স একত্রীকরণ তখনই ঘটে যখন দুই বা ততোধিক ফাইলের একটি অভিন্ন রিসোর্স নাম, টাইপ এবং কোয়ালিফায়ার থাকে। AGP ডুপ্লিকেট ফাইলগুলোর মধ্যে থেকে (নীচে বর্ণিত অগ্রাধিকার ক্রম অনুসারে) সেরা ফাইলটি নির্বাচন করে এবং চূড়ান্ত বিল্ড আর্টিফ্যাক্টে বিতরণের জন্য শুধুমাত্র সেই একটি রিসোর্স AAPT-এর কাছে পাঠায়।
AGP নিম্নলিখিত স্থানগুলিতে সদৃশ রিসোর্স খুঁজে থাকে:
- মূল উৎস সেটের সাথে সম্পর্কিত প্রধান রিসোর্সসমূহ সাধারণত
src/main/res/ফোল্ডারে অবস্থিত। - বিল্ড টাইপ এবং বিল্ড ফ্লেভার থেকে ভ্যারিয়েন্ট ওভারলে
- লাইব্রেরি প্রকল্পের নির্ভরতা
AGP নিম্নলিখিত ক্রমিক অগ্রাধিকার অনুসারে সদৃশ রিসোর্সগুলিকে একত্রিত করে:
উদাহরণস্বরূপ, যদি আপনার প্রধান রিসোর্স এবং একটি বিল্ড ফ্লেভার উভয় স্থানেই একটি সদৃশ রিসোর্স থাকে, তাহলে গ্রেডল বিল্ড ফ্লেভারের রিসোর্সটি নির্বাচন করে।
যদি একই সোর্স সেটে অভিন্ন রিসোর্স থাকে, তাহলে গ্রেডল সেগুলোকে মার্জ করতে পারে না এবং একটি রিসোর্স মার্জ এরর দেখায়। এমনটা হতে পারে যদি আপনি আপনার মডিউলের build.gradle ফাইলের sourceSet প্রপার্টিতে একাধিক সোর্স সেট সংজ্ঞায়িত করেন; উদাহরণস্বরূপ, যদি src/main/res/ এবং src/main/res2/ উভয়টিতেই অভিন্ন রিসোর্স থাকে।
রিসোর্স সঙ্কুচিত হওয়ার সমস্যা সমাধান করুন
যখন আপনি রিসোর্স সংকুচিত করেন, তখন বিল্ড উইন্ডোটি অ্যাপ থেকে সরানো রিসোর্সগুলির একটি সারাংশ দেখায়। (গ্রেডল থেকে বিস্তারিত টেক্সট আউটপুট দেখতে উইন্ডোর বাম দিকে থাকা ‘টগল ভিউ’- তে ক্লিক করুন।) উদাহরণস্বরূপ:
: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 অ্যাক্সেসযোগ্য; এবং আপনি যদি উপরের দিকে খোঁজেন, তাহলে resources.txt ফাইলে "The root reachable resources are:" শিরোনামের অধীনে রিসোর্সটি খুঁজে পাবেন।
এর মানে হলো, add_schedule_fab_icon_anim এর একটি কোড রেফারেন্স রয়েছে, অর্থাৎ, এর R.drawable ID-টি অ্যাক্সেসযোগ্য কোডের মধ্যে পাওয়া গেছে।
আপনি যদি কঠোর চেকিং ব্যবহার না করেন, তাহলে রিসোর্স আইডিগুলোকে অ্যাক্সেসযোগ্য হিসেবে চিহ্নিত করা যেতে পারে যদি এমন স্ট্রিং কনস্ট্যান্ট থাকে যা দেখে মনে হয় ডাইনামিকভাবে লোড হওয়া রিসোর্সের নাম তৈরি করতে ব্যবহৃত হতে পারে। সেক্ষেত্রে, আপনি যদি বিল্ড আউটপুটে রিসোর্সের নামটি খোঁজেন, তাহলে আপনি এই ধরনের একটি বার্তা দেখতে পারেন:
10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
used because its format-string matches string pool constant ic_plus_anim_%1$d.
আপনি যদি এই স্ট্রিংগুলির মধ্যে কোনো একটি দেখতে পান এবং নিশ্চিত হন যে স্ট্রিংটি প্রদত্ত রিসোর্সটি ডায়নামিকভাবে লোড করার জন্য ব্যবহৃত হচ্ছে না, তাহলে বিল্ড সিস্টেমকে রিসোর্সটি সরিয়ে ফেলার নির্দেশ দিতে আপনার keep ফাইলে tools:discard অ্যাট্রিবিউটটি ব্যবহার করুন।