Post updated on 4th March, 2018 at 08:21 am
একটা কেস স্টাডি দিয়ে শুরু করছি। ২০১৫ সালের দিকে যখন প্রথম অ্যান্ড্রয়েড শেখা শুরু করি তখনকার সময়ের কথা। সবে মাত্র App of Ramadan প্লেস্টোরে পাবলিশড হয়েছে। তখনকার অ্যাপের চেহারা অতীব বদখত ছিল! আমার নিজেরই তখন অ্যান্ড্রয়েড ফোন ছিল না। জানতামও না অ্যান্ড্রয়েড অ্যাপ কেমন হয়ে থাকে। সেই সময়ে মাথায় যা আসছিল তা দিয়ে কোনো মতে কিছু একটা বানিয়েছিলাম। এখন যেমন এই অ্যাপে ফায়ারবেজ দিয়ে লোকেশন অনুযায়ী সারা বছরের নামাজের সময়সূচী দেখানো হয় তখন সেরকম ছিল না। যাই হোক, মূল কথায় আসি। অ্যাপটা পাবলিশড করার কিছু দিনের মধ্যেই দেখলাম আমার অ্যাপের ক্লোন কপি একটা প্লে স্টোরে। শুধু ব্যাকগ্রাউন্ড কালারটা ভিন্ন। এছাড়া ভিতরের সব আইকন, স্ট্রিং, ফিচার যা আছে সব হুবহু আমার অ্যাপেরটা কপি করা। তো প্রথম বছরেই এমন ছ্যাচড়া চোরের সাক্ষাত পেলাম! 😛
একই অ্যাপের কথা, এই বছরের রমজান। অ্যান্ড্রয়েড ডেভেলপার গ্রুপে এক ভাই আমার পোস্টে কমেন্ট করে বললেন “অমুক ফিচারটা কিভাবে ইমপ্লিমেন্ট করেছেন বুঝতে পারছিলাম না। তাই অাপনার অ্যাপটা ডিকম্পাইল করলাম!” এই বলে তিনি আমার ঐ ফিচারের কোডটুকুর স্ক্রিনশট দিলেন! উনি যদিও কাজটা করেছেন শেখার জন্য, এরপরেও ওভারঅল বিষয়টা নিয়ে নতুন করে ভাবতে শুরু করলাম। ProGuard ব্যবহারের কথা আগে ভাসা ভাসা ধারণা ছিল। এই ঘটনায় সিরিয়াসলি দেখা শুরু করলাম। যত দূর মনে পড়ে ২ দিনের মধ্যে ProGuard এর সিসটেম শিখে অ্যাপ আপডেট দিয়েছিলাম। এর ২-১ দিনের মধ্যে কাছের এক ডেভেলপার ভাই নক দিয়ে বললেন “ভাই! আপনার অ্যাপটা শেখার উদ্দেশ্যে decompile করলাম। কিন্তু সব তো দেখি হিজিবিজি!” 😀
ProGuard কী ও কেন?
ProGuard হচ্ছে Java ও Android এর জন্য একটা জনপ্রিয় optimizer. এর কাজ হচ্ছে জাভা ও অ্যান্ড্রয়েড অ্যাপের কোডকে অপটিমাইজ করা। এটা কাজ করে Java’র bytecode level এ। এই tool আপনার প্রোজেক্টের অপ্রয়োজনীয় কোডগুলোকে detect করবে। যেই কোডগুলো আপনি মনের মাধুরী মিশিয়ে লিখেছেন কিন্তু পরে কোনো কারণে কমেন্ট করে রেখেছেন বা কোডটুকুর আসলে কোনো use নাই, কিছু রিসোর্স এড করেছেন প্রোজেক্টে কিন্তু সেটা ব্যবহার করেন নি। এসব ক্ষেত্রে ProGuard এই unused code-গুলোকে remove করে দেয়। ফলাফল হচ্ছে আপনার APK ফাইলের সাইজ কমতে পারে 90% পর্যন্ত আর অ্যাপ রান করতে পারে আগের চেয়ে 20% বেশি fast! আমাদের Playstore এ থাকা এই অ্যাপের সাইজ প্রায় 1.5 মেগাবাইট কমিয়ে নিয়ে এসেছি এই টুল ব্যবহার করে।
আরেকটা দারুণ কাজ করে! তা হচ্ছে আপনার ডেটা ও মেথডের নামগুলোকে obfuscate করে দেয়। অর্থাৎ ভেরিয়েবল, মেথড, ক্লাসের নাম ইত্যাদিকে পরিবর্তন করে হাবিজাবি কিছু একটা বানিয়ে দেয়। যাতে করে আপনার সোর্সকোড কেউ মেরে দিতে না পারে। ধরেন আপনি মেথডের নাম দিলেন getUserName(). এই tool আপনার সাধের এই মেথডের নাম চেঞ্জ করে হয়ত দিবে C13D(). ভয় নাই! আপনার প্রোজেক্টের কোড আগে যেমন ছিল তেমনই থাকবে! এই চেঞ্জটা হবে APK generate করার সময়। যে কোনো APK file চাইলে এই অনলাইন টুল দিয়ে ডিকম্পাইল করা যায়। APK টা যদি ProGuard tool enable করে build করা হয়ে থাকে তাহলে ডিকম্পাইল করার পর ঐ কোড দেখে কিছু বুঝা যাবে না। কিন্তু ProGuard ইউজ না করলে আপনি যেমন কোড করেছেন হুবহু ঐ কোড আপনি দেখতে পারবেন।
এক কথায় বললে বলা যায়, code shrink ও minify করার জন্য প্রো-গার্ড ইউজ করা হয়। যেন কেউ চাইলেই reverse engineering করে APK file থেকে সোর্স কোড দেখে সহজে বুঝতে না পারে।
ProGuard এর ব্যবহার বিধি
build.gradle file customization
gradle file এর ভিতরে যে কোনো প্রোজেক্টে নিচের অংশটা by default থাকেঃ
buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }
অর্থাৎ আপনার বিল্ডটা যদি release type এর হয় (অর্থাৎ যেই বিল্ড করার পর প্লেস্টোরে আপলোড করবেন) তাহলে তার ক্ষেত্রে minifyEnabled ফিচারটা false. এটা false থাকলে আপনার কোড minify করা হবে না। ফলে APK টা reverse engineering করা সহজ হবে। তাই রিলিজ টাইপের APK তে যেন এটা enable থাকে তাই এটাকে true করে দিতে হবে।
কাজের সুবিধার জন্য প্রয়োজন অনুযায়ী আমি debug APK build এর ক্ষেত্রেও এটা enable করে রাখি। প্র্যাক্টিসের জন্য Android Studio তে জাস্ট Hello World! প্রিন্ট করার একটা প্রোজেক্ট খুলেন। build.gradle ফাইলের buildTypes{} এ নিচের কোডটুকু কপি-পেস্ট করুনঃ
buildTypes { debug { shrinkResources true minifyEnabled true useProguard true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } release { shrinkResources true minifyEnabled true useProguard true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }
অর্থাৎ debug ও release উভয় মোডের জন্য আমি কনফিগারেশন বলে দিচ্ছি। shirnkResources যদি true করা থাকে তাহলে res ডিরেক্টরিতে আপনার add করা resource-গুলোকে এটা shrink করবে। আপনার জাভা কোডগুলোকে obfuscate ও minify করার জন্য minifyEnabled এর ভ্যালু true করে দিতে হবে। useProguard true করা থাকলে এটা আপনার প্রোজেক্টের unused code কে মুছে দিবে।
আপনি চাইলে ProGuard এর properties-গুলো debug mode এ disabled রাখতে পারেন। সেক্ষেত্রে shrinkResources, minifyEnabled ও useProguard এর ভ্যালুগুলোকে false করে দিবেন।
proguard-rules.pro file customization
আপনি যদি জাস্ট একটা Hello World অ্যাপ উপরের gradle এর কাস্টমাইজেশন দিয়ে রান করে থাকেন দেখবেন খুব সুন্দর মতই রান হচ্ছে। কিন্তু একটু পর যখন অ্যাপে বিভিন্ন ধরনের লাইব্রেরি অ্যাড করে কাজ করবেন তখন ঝামেলা করা শুরু করবে। যেমন ধরেন Retrofit Network Library‘র সাহায্যে অ্যাপ ও সার্ভারের মধ্যে API ব্যবহার করে ডেটা আদান-প্রদান করতে চান। অথবা JSOUP Library ব্যবহার করে API ছাড়াই অ্যাপ থেকে কোনো সাইটের ডেটা scrap করে নিয়ে আসতে চান। তখন দেখবেন proguard এর properties-গুলো enable করা থাকলে আপনার অ্যাপ হয়ত build-ই হবে না। বিচিত্র সব error এ আপনার লগ ভরে যাবে। সে দিন হঠাৎ করে দেখি Pretty Logger Library ঠিকঠাক কাজ করছে না। Log এ class name, method name দেখানোর কথা থাকলেও মেথডের নামগুলো সঠিক দেখাচ্ছিল না। এর কারণ হচ্ছে proguard যখন enable করা থাকে তখন সে কোড মিনিফাই করে আর সব ক্লাসের মেথড, ভেরিয়েবল সব কিছুর নাম পরিবর্তন করে হাবিজাবি কিছু একটা দিয়ে দেয়। তাই আপনার প্রোজেক্ট থেকে যখন কোনো লাইব্রেরির ফাংশনালিটির জন্য কল দেয়া হয় তখন সে ঐ নির্দিষ্ট মেথডগুলো বা ডেটাগুলোকে খুঁজে পায় না। ফলাফল হচ্ছে অ্যাপ crash! তাই যে কোনো লাইব্রেরি ব্যবহার করার সময় একটু সতর্ক থাকতে হবে। ডেভেলপারদের সুবিধার জন্য যারা লাইব্রিরিটি বানিয়েছেন তারা সাধারণত বলে দেন ProGuard rules এর মধ্যে কী টাইপের চেঞ্জ করা লাগবে। Picasso, Retrofit, JSOUP সবগুলোর অফিসিয়াল সাইট বা গিটহাব রিপোতে গেলে দেখতে পাবেন। তবে সব লাইব্রেরিতে proguard rules আমাদের কাস্টমাইজ করতে হবে না। যেগুলোতে দরকার হবে ঐ লাইব্রেরির রিপোতেই সেটা বলা থাকবে।
ProGuard যেন লাইব্রেরির ক্লাসগুলোতে কোনো ধরনের ঝামেলা না করে সে জন্য প্রয়োজনীয় নির্দেশনা তাকে দিতে হবে। গ্র্যাডলে আমরা প্রোগার্ড ঠিকই এনাবল করব, কিন্তু একই সাথে কিছু exceptional case এর কথাও বলে দিব। এই exceptional case-গুলোকে বলা হয় proGuard Rules. এই রুলসগুলো লিখতে হয় proguard-rules.pro নামের ফাইলে। এই ফাইলটি পাবেন project এর ভিতরের app folder এ। শুধু লাইব্রেরির ক্লাসই না, কোনো কারণে যদি আপনি আপনার কোনো ক্লাসকে obfuscate করতে না চান সেটাকেও proguard-rules.pro ফাইলের মধ্যে বলে দিতে হবে।
কমন কয়েকটি লাইব্রেরির জন্য proguard rules নিচে দেয়া হলোঃ
Retrofit
-dontwarn retrofit.** -keep class retrofit.** { *; } -keepattributes Signature -keepattributes Exceptions
GSON
-keep class sun.misc.Unsafe { *; } -keep class com.google.gson.stream.** { *; }
Butter Knife
-keep class butterknife.** { *; } -dontwarn butterknife.internal.** -keep class **$$ViewBinder { *; } -keepclasseswithmembernames class * { @butterknife.* <fields>; } -keepclasseswithmembernames class * { @butterknife.* <methods>; }
JSOUP
-keep public class org.jsoup.** { public *; } OR, -keeppackagenames org.jsoup.nodes
এছাড়াও আপনার নিজস্ব কোনো ক্লাসকেও চাইলে obfuscation এর আওতার বাইরে রাখতে পারেন। আপনার একটা ক্লাসের নাম যদি হয় MyClass আর এর প্যাকেজের নাম যদি হয় com.example.MyApp তাহলে proguard-rules.pro ফাইলে আপনি লিখবেনঃ
... -keep class com.example.MyApp.MyClass ...
ProGuard ব্যবহারে লক্ষ্যনীয় বিষয়
- Existing project এর মাঝ পথে ProGuard enable করলে খুব বেশি সম্ভাবনা আছে অ্যাপ ক্র্যাশ করার। তাই পর্যাপ্ত পরিমান টেস্ট করে নিতে ভুলবেন না। আমি এমনও দেখেছি যে এক ডিভাইসে চলে আরেক ডিভাইসে ক্র্যাশ করে। তাই অ্যাপ আপডেট দেয়ার পর চোখ রাখুন crash report এর দিকে।
- ডিবাগ মোডে প্রোগার্ড বন্ধ করা থাকলে নতুন কোনো লাইব্রেরি বা ফিচার এড করার পর অবশ্যই প্রোগার্ড চালু করে টেস্ট করে নিবেন। তা না হলে কোথায় গিয়ে ক্র্যাশ করছে সেটা ধরা মুশকিল হবে।
- ProGuard enable করা থাকলে প্রোজেক্ট build হতে স্বাভাবিকের চেয়ে একটু বেশি সময় নিতে পারে। তাই debug mode এ কাজ করার সময় proguard এর properties-গুলো disable (false) করে রাখতে পারেন। তবে released apk বিল্ড করার আগে অবশ্যই ডিবাগ মোডে proguard enable করে টেস্ট করে নিবেন কোথাও ঝামেলা হলো কিনা।
- প্রোগার্ড অন করার পর কোনো একটা ক্লাসে অজানা কারণে ক্র্যাশ হতে শুরু করলো। কিন্তু কোনো ভাবেই যদি ক্র্যাশ বন্ধ করতে না পারেন তাহলে স্পেসিফিক ঐ ক্লাসটাকে proguard-rules.pro ফাইলে obfuscate না করার জন্য বলে দিতে পারেন।
- আমরা প্লে স্টোরে অ্যাপ রিলিজ দেয়ার পর ক্র্যাশ করলে ক্র্যাশ রিপোর্টে দেখতে পাই যে অমুক ক্লাসের, অমুক মেথডে ক্র্যাশ করেছে। কিন্তু আমাদের apk file এ যদি সব কোড obfuscate করা থাকে তাহলে গুগল ক্র্যাশ রিপোর্ট পাঠানোর সময়েও ঐ obfuscated class name and method name দিয়েই ক্র্যাশ রিপোর্ট পাঠাবে। হয়ত বলবে klf86c.java ক্লাসের abc() মেথডে অ্যাপ ক্র্যাশ করেছে। এই ক্র্যাশ রিপোর্ট দেখে তখন আবার আপনার মাথা ক্র্যাশ করার জোগাড় হবে! তাই আমাদের জানা দরকার proguard কোন ক্লাসকে নতুন কোন নাম দিয়েছে? আসল ক্লাসের নাম, আসল ফিল্ডের নাম আর নতুন ক্লাসের নাম এবং নতুন ক্লাসের নামগুলোর লিস্ট গুগলকে জানাতে হবে। তাহলে গুগল রিপোর্ট পাঠানোর সময় original method and data field name দিয়ে ক্র্যাশ রিপোর্ট পাঠাবে। এই কাজের জন্য অ্যাপ বিল্ড করার পর obfuscate করা সকল ক্লাস, মেথড ও ডেটা ফিল্ডের নাম mapping.txt ফাইলে map করা থাকে। Release APK build করার পর এই ফাইলটা পাওয়া যাবে <module-name>/build/outputs/mapping/release/ এই ডিরেক্টরির ভিতরে। প্লেস্টোরের ডেভেলপার কনসোলে APK upload করার সময় এই ফাইলটাও আপলোড করে দিতে হবে। কিভাবে এবং কোথায় আপলোড করতে হবে সেটা একটু গুগল করলেই পেয়ে যাবেন।
Android App Development tutorial এর জন্য আমরা অনেক ব্লগ পড়ি, অনেক ভিডিও দেখি। কিন্তু শুরুর দিকে অ্যান্ড্রয়েডের অফিসিয়াল ডকুমেন্টেশন দেখতে ভয় লাগে। দেখলেও দেখা যায় বুঝা কঠিন হয়। কিন্তু অভ্যাসটা করা জরুরি। অ্যান্ড্রয়েডের যে কোনো বিষয়ের ক্লিয়ার নলেজের জন্য অফিসিয়াল ডকুমেন্টেশনের বিকল্প নাই। ProGuard ও Android code shrinking সম্পর্কে আরো বিস্তারিত জানার জন্য দেখুন অ্যান্ড্রয়েডের অফিসিয়াল ডকুমেন্টেশন।
It was really helpful. Thanks a lot.
You are most welcome 🙂
it’s important and very helpful brother!!
thank you for your feedback
it’s most important for every android developer and very helpful brother.
thank you for your feedback