چرا و چطور پروژه‌هات رو چند ماژوله کنی؟ (راهنمای قدم‌به‌قدم برای اندروید – 2025)

چرا و چطور پروژه‌هات رو چند ماژوله کنی؟ (راهنمای قدم‌به‌قدم برای اندروید - 2025)
در این پست می‌خوانید:

توی این مطلب میخوایم کاملا عملی و پروژه محور یادبگیریم که چطور میتونم یه پروژه چند ماژوله یا MultiModule رو توی برنامه نویسی اندروید درست کنیم.

چند ماژوله کردن پروژه های اندروید استودیو

چرا پروژه‌ات باید چند ماژوله باشه؟

یه پروژه‌ی چند ماژوله مزایای زیادی داره، که بعضیاش اینان:

  • می‌تونی قابلیت‌ها (features) رو منطقی‌تر و بهتر تقسیم‌بندی کنی
  • هر فیچر (حداقل باید) مستقل‌تر باشه که این باعث می‌شه پروژه بهتر مقیاس‌پذیر بشه
  • اگه بخوای الگوهایی مثل MVVM رو پیاده‌سازی کنی، نیاز به چند ماژول داری
  • تست گرفتن راحت‌تر می‌شه

چجوری این کار رو تو یه اپلیکیشن اندرویدی انجام بدیم؟

توی Android Studio می‌تونیم چندتا ماژول بسازیم، درست مثل همون ماژولی که وقتی پروژه رو تازه می‌سازیم وجود داره و اسمش معمولاً app هست.

بعد از اینکه یه پروژه جدید ساختیم، مراحل زیر رو انجام بده تا اپلیکیشنت چند ماژوله بشه:

تغییر نمای پروژه

تو پنجره‌ی سمت چپ، ویو (نمای) پروژه رو از حالت app یا Android به Project تغییر بده.

ساخت ماژول جدید

روی پوشه‌ای که اسم پروژه‌ات روشه (مثلاً TrainNavigation) راست‌کلیک کن و برو روی New -> Module.

در این مرحله ما وارد منو ساخت module میشیم :

بله ، به صورت تیتر وار این قسمت ها رو توضیح بدم :

ابتدا سمت راست رو توضیح میدم :

  • Module name (نام ماژول)
    • مثلاً: features

    • این نام پوشه‌ای است که ماژول شما داخل پروژه در آن قرار می‌گیرد.

    • می‌تونید بسته به کاربرد ماژول، اسمش رو دقیق‌تر بذارید مثل feature_home یا feature_auth.

  • Package name (نام پکیج)
    • این به صورت خودکار بر اساس نام ماژول تولید می‌شه.

    • مثلاً: ir.brazandeh.features

    • می‌تونه همون بمونه یا اگر ساختار خاصی برای پکیج‌ها دارید، اصلاحش کنید (مثلاً ir.brazandeh.feature.home)

  • Language
    • Kotlin که زبان این پروژه است ، میتونید جاوا هم java انتخاب کنید

  • Minimum SDK
    • API 24 (Android 7.0) که مناسب به نظر می‌رسه، مگر اینکه بخواید اپلیکیشن‌تون روی نسخه‌های پایین‌تر هم کار کنه. این یعنی چی ؟

      • وقتی در یک ماژول (feature module) جدید حداقل SDK را روی API 24 (Android 7) تنظیم می‌کنیم، به این معنی است که فقط همان ماژول روی دستگاه‌هایی با اندروید ۷ به بالا اجرا می‌شود. اما اپلیکیشن اصلی همچنان می‌تواند روی نسخه‌های پایین‌تر مانند Android 4 نصب و اجرا شود. این قابلیت به ما اجازه می‌دهد برخی امکانات خاص را فقط برای کاربران با نسخه‌های جدید اندروید فعال کنیم، دقیقاً مانند برخی ویژگی‌های تلگرام که تنها در Android 8 و بالاتر در دسترس هستند.
  • Build Configuration Language
    • Kotlin DSL (build.gradle.kts) که حالت مدرن و پیشنهادی هست.

منو های سمت چپ :

  • Phone &Tablet  ( اگر هدف ساخت یه ماژول مستقل با activity اصلیه (مثلاً نسخه‌ی جدا یا app مجزا برای testing)
    • این نوع ماژول می‌تونه Activity اصلی داشته باشه.

    • به درد testing جدا، standalone module یا اپلیکیشن‌های کاملاً جدا می‌خوره.

    • ولی معمولاً در اپ‌های ماژولار استفاده نمی‌شه (مگر برای dev/test)

  • Android Library ( اگر هدف ساخت یک بخش از اپلیکیشن اصلیه (مثل login، profile، calendar و…) )
    • این گزینه ماژولی می‌سازه که خودش app نیست ولی می‌تونه layout، ViewModel، Fragment یا Composable داشته باشه.

    • برای معماری feature-based بهترین انتخابه.

    • به راحتی می‌تونی از این ماژول در app اصلی import بگیری.

  • Dynamic Feature (اگر دنبال ماژول featureای هستی که فقط توی بعضی نسخه‌ها یا شرایط خاص load بشه (dynamic delivery))
    • مخصوص modular app + Play Feature Delivery هست.

    • اگه از Base module استفاده می‌کنی و می‌خوای featureها فقط در صورت نیاز دانلود بشن (مثل Google Maps Navigation یا تلگرام animated emoji pack)، این گزینه عالیه.

    • لازمه که از Play Store App Bundle استفاده کنی.

    • توضیح این قسمت :
      • Dynamic Delivery یا همان ویژگی “قابلیت تحویل پویا” به شما اجازه می‌دهد که بخش‌هایی از اپلیکیشن را به‌صورت ماژول‌های جداگانه ایجاد کرده و فقط زمانی دانلود و نصب کنید که کاربر به آن نیاز دارد. دقیقاً مثل بازی‌هایی که دیتای مراحل یا منابع خاص را جداگانه دانلود می‌کنند، اما در Dynamic Feature این مدیریت توسط Google Play و ساختار App Bundle انجام می‌شود، نه به‌صورت دستی. برای مثال، اگر اپلیکیشن شما بخشی با آموزش اولیه دارد که فقط یک بار استفاده می‌شود، می‌توانید آن را در یک Dynamic Feature Module قرار دهید تا فقط در صورت نیاز دانلود شود. این کار باعث سبک‌تر شدن نصب اولیه و کاهش مصرف منابع می‌شود.
  • Automotive
    • ساخت ماژول برای Android Auto (مثلاً اپ‌های خودرو).

    • اگر اپ شما قراره در خودرو اجرا بشه از این استفاده می‌شه.

  • Wear OS
    • ساخت اپ یا ماژول مخصوص ساعت‌های هوشمند.

    • مخصوص نسخه‌های اندروید روی گجت‌های پوشیدنی.

  • Television
    • ماژول مخصوص Android TV.

    • اگه اپ‌تون قراره روی تلویزیون‌های اندرویدی اجرا بشه، این رو انتخاب می‌کنید.

  • Java or Kotlin Library
    • ساخت یک کتابخانه ساده (بدون کامپایل شدن به عنوان Android Library).

    • مناسب برای لایه‌هایی مثل data layer یا shared utils.

    • این کتابخانه وابستگی به Android نداره. (مثل my-utils, data-converter, encryption-lib)

  • Baseline Profile Generator
    • بهینه‌سازی عملکرد اپ در زمان اجرا (runtime performance).

    • برای بهینه‌سازی شروع اولیه اپ یا transition animation.

    • بیشتر برای Benchmark + Performance Tuning استفاده می‌شه.

    • توضیح : Baseline Profile Generator یه ابزار خیلی به درد بخوره‌ست برای این‌که اپلیکیشن‌ت سریع‌تر بالا بیاد و روون‌تر کار کنه. میاد مسیرهای پرکاربردی مثل باز شدن صفحه‌ی اصلی یا ورود رو بررسی می‌کنه، ازشون یه نقشه می‌سازه و می‌ذاره توی اپ. وقتی کاربر اپ رو نصب می‌کنه، اندروید با کمک این نقشه از قبل بخش‌های مهم رو آماده می‌کنه و باعث می‌شه اجرا سریع‌تر و تجربه کاربری بهتر باشه.

  • Benchmark
    • ماژولی برای نوشتن تست‌های performance.

    • باهاش می‌تونی اندازه‌گیری کنی کدها چقدر سریع اجرا می‌شن.

    • خیلی خوبه برای اپ‌های سنگین یا زمان‌هایی که performance مهمه.

  • Kotlin Multiplatform Shared Module
    • ساخت ماژول مشترک بین Android و iOS (یا JVM و JS).

    • مخصوص پروژه‌هایی که قراره با Kotlin Multiplatform نوشته بشن.

    • مناسب اگر قراره منطق بیزینس بین چند پلتفرم به اشتراک گذاشته بشه (مثلاً: model, repository, validation).

سر انجام ما Android Library می کنیم و اگه از اینجا یه ماژول جدید بسازی، در همون سطح ماژول app ساخته می‌شه، ولی می‌تونی هرجایی که خواستی بسازیش.

حالا یه ماژول جدید داریم به اسم features.

تنظیم فایل‌های گریدل (gradle)

توی این پروژه، ماژول app ماژول اصلی حساب می‌شه و ماژول features جاییه که بقیه‌ی ماژول‌های مربوط به هر قابلیت (feature) قراره اونجا اضافه بشن.

 مشخص کردن ماژول اصلی

برای اینکه مشخص کنیم app ماژول اصلی پروژه‌ست، باید خط اول فایل gradle ماژول features رو تغییر بدیم.

بخش plugins توی ماژول app باید این شکلی باشه:

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
}

و بخش plugins توی ماژول features باید اینجوری باشه:

plugins {
    alias(libs.plugins.android.library)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
}

 اضافه کردن وابستگی (Dependency)

اگه ماژول درست ساخته شده باشه پروژه تو نمای app به این صورت است که  پوشه features و همچنین فایل گردل این ماژول رو به صورت جداگانه مشاهده میکنید :

از اونجایی که همه‌ی قابلیت‌ها قراره توی ماژول features قرار بگیرن، باید ماژول app وابستگی به features داشته باشه تا بتونه از امکاناتش استفاده کنه.

برای این کار، این خط رو به بخش dependencies فایل گریدل ماژول app اضافه می‌کنیم:

implementation(project(":features"))

به جای features اسم ماژولی که ساختی رو بنویس.

 اضافه کردن بقیه‌ی وابستگی‌های لازم

چون داریم از Compose استفاده می‌کنیم، باید این خط رو توی بخش android فایل‌های گریدل هر دو ماژول اضافه کنیم:

buildFeatures {

    compose = true

}

نکته :

در این فایل های گردل  از این خط استفاده شده است :

alias(libs.plugins.kotlin.compose)

دلیل این کار ، از Kotlin 2.0 به بعد، دیگر کافی نیست فقط compose = true رو توی buildFeatures فعال کنی — باید پلاگین کامپایلر Compose رو هم به صورت مشخص به پروژه‌ت اضافه کنی.

فایل libs.version.toml به این صورت است :

[versions]
agp = "8.10.1"
kotlin = "2.0.21"
coreKtx = "1.10.1"
junit = "4.13.2"
junitVersion = "1.1.5"
espressoCore = "3.5.1"
lifecycleRuntimeKtx = "2.6.1"
activityCompose = "1.8.0"
composeBom = "2024.09.00"
appcompat = "1.6.1"
material = "1.10.0"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
android-library = { id = "com.android.library", version.ref = "agp" }

و این خطوط رو هم توی بخش dependencies هر دو ماژول بذار:

implementation(libs.androidx.lifecycle.runtime.ktx)

implementation(libs.androidx.activity.compose)

implementation(platform(libs.androidx.compose.bom))

implementation(libs.androidx.ui)

implementation(libs.androidx.ui.graphics)

implementation(libs.androidx.ui.tooling.preview)

implementation(libs.androidx.material3)

مرحله آخر ، تست کردن پروژه 

حالا که همه‌ی مراحل رو انجام دادیم، بیایم ببینیم چطوری توی یه پروژه چندماژوله کار می‌کنیم — با یه مثال ساده.

توی ماژول features یه کلاس جدید به اسم SimpleText درست می‌کنیم که فقط یه متن ساده رو وسط صفحه نشون بده.

بعد برمی‌گردیم به module app و این صفحه رو نشون می‌دیم.
چون توی فایل گریدل، وابستگی رو اضافه کرده بودیم، فقط کافیه ازش استفاده کنیم (اگه نیاز بود ایمپورتش هم بکنیم).

حالا توی module app که داریم این SimpleText را استفاده میکنم که از یه ماژول دیگه میاد ، نشون میدیم .

و تموم شد! این هم یه پروژه چند ماژوله که ساخته شد و  اصلا هم سخت نبود 😁
امیدوارم برات مفید بوده باشه 😊

دیدگاه‌ها ۰
ارسال دیدگاه جدید