<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های محمد جواد صفاتاج</title>
        <link>https://virgool.io/feed/@mjsafatajmj</link>
        <description>من برنامه نویس اندروید و kmp هستم  با 2 الی 3 سال تحقیق و تجربه و دوست دارم به یک برنامه نویس حرفه‌ای تبدیل بشم</description>
        <language>fa</language>
        <pubDate>2026-06-16 06:40:57</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/3319578/avatar/766Fcx.jpg?height=120&amp;width=120</url>
            <title>محمد جواد صفاتاج</title>
            <link>https://virgool.io/@mjsafatajmj</link>
        </image>

                    <item>
                <title>استفاده از gradle convention plugin در KMP</title>
                <link>https://virgool.io/@mjsafatajmj/how-to-use-gradle-convention-plugin-in-kmp-n8oqxuy2woep</link>
                <description>1-مقدمهمن چندماهی میشه که مشغول ساخت پروژه های کراس پلتفرم با kmp بودم و زمانی که تصمیم گرفتم که همون build-logic یا build-src معروف که توی اندروید برای مدیریت وابستگی ها در اپ های ماژولار از اون استفاده میکردیم را برای kmp پیاده سازی کنم بعد از کنار هم قرار دادن چند تا سورس کد و این مقاله و ساعت ها تست و آزمایش تونستم کارو انجام بدم،دلایلی زیادی وجود داشت که به چالش خوردم مثلا مقاله بالا import ها را نیاورده بود و اندروید استادیو کد را شناسایی نمیکرد و عملا پیدا کردن پکیج هر کلاس خیلی سخت بود، علت دیگه اینکه مقاله بالا یکسری اشتباهات انجام داده بود و دیگه اینکه نسخه gradle ، کاتلین و خلاصه هیچ چیزی را عنوان نکرده بود که بشه مشکلات را برطرف کرد.امیدوارم این مقاله به شما کمک کنه زودتر به نتیجه برسین.2-آماده کردن پروژهاول پوشه build-logic را به پوشه root پروژه خودتون اضافه کنید هر چند مکان این پوشه دلخواههدر پوشه build-logic یک فایل به نام settings.gradle.kts اضافه کنید و کدهای زیر در اون بنویسید:dependencyResolutionManagement {    repositories {        google()        mavenCentral()    }    versionCatalogs {        create(&quot;libs&quot;) {            from(files(&quot;../gradle/libs.versions.toml&quot;))        }    }}rootProject.name = &quot;build-logic&quot;include(&quot;:convention&quot;)سپس فایل gradle.properties را هم با کد زیر به اون اضافه کنید:org.gradle.parallel=trueorg.gradle.caching=trueorg.gradle.configureondemand=trueسپس یک ماژول به نام convention ایجاد کنید و یک پکیج دلخواه به اون اضافه کنید تا اینجای کار باید پوشه build-logic به این صورت باشه:خب حالا به فایل settings.gradle.kts در مسیر اصلی پروژه خودتون برین و به شکل زیر پوشه build-logic را به عنوان build script وارد کنید:حالا به فایل build.gradle.kts در ماژول convention برین و کد زیر را درون اون بنویسید:plugins {    &#x60;kotlin-dsl&#x60;}group = &quot;com.example.upfiles.buildlogic&quot; //your module namedependencies {    compileOnly(libs.android.gradlePlugin) //if targetting Android    compileOnly(libs.kotlin.gradlePlugin)    compileOnly(libs.compose.gradlePlugin) //if you are using Compose Multiplatform}اگه در پروژه تون از version catalog استفاده نکردین لازمه ابتدا Version catalog را به پروژه تون اضافه کنید و گرنه در کد بالا به خطا برمیخورینحالا لازمه مواردی که در کد بالا استفاده کردیم را در version catalog خودمون اضافه کنیم یعنی فایل  libs.versions.toml  در قسمت [libraries] :android-gradlePlugin = { module = &amp;quotcom.android.tools.build:gradle&amp;quot, version.ref = &amp;quotagp&amp;quot }
kotlin-gradlePlugin = { module = &amp;quotorg.jetbrains.kotlin:kotlin-gradle-plugin&amp;quot, version.ref = &amp;quotkotlin&amp;quot }
compose-gradlePlugin = { module = &amp;quotorg.jetbrains.compose:org.jetbrains.compose.gradle.plugin&amp;quot, version.ref = &amp;quotcompose&amp;quot }3-شروع به کد نویسیدر ابتدا باید به version catalog هامون دسترسی داشته باشیم تا راحت تر کد بنویسیم پس در ماژول convention یک فایل ایجاد کنید تا دسترسی به اون را فراهم کنیم:package com.example.upfilesimport org.gradle.api.Projectimport org.gradle.api.artifacts.VersionCatalogimport org.gradle.api.artifacts.VersionCatalogsExtensionimport org.gradle.kotlin.dsl.getByTypeval Project.libs    get(): VersionCatalog = extensions.getByType&lt;VersionCatalogsExtension&gt;().named(&quot;libs&quot;)// if using android libraries//val Project.androidLibs//    get(): VersionCatalog =extensions.getByType&lt;VersionCatalogsExtension&gt;().named(&quot;androidLibs&quot;)حالا نیاز داریم به یک extension فانکشن تا سورس ست های اندروید را کانفیگ کنیم و از شر کد تکراری خلاص بشیم پس فایل جدیدی میسازیم و کد زیر را به اون اضافه میکنیم:import com.android.build.api.dsl.LibraryExtensionimport com.example.upfiles.libsimport org.gradle.api.Projectimport org.gradle.api.JavaVersioninternal fun Project.configureKotlinAndroid(    extension: LibraryExtension) = extension.apply {    //    get module name from module path    val moduleName = path.split(&quot;:&quot;).drop(2).joinToString(&quot;.&quot;)    namespace = if(moduleName.isNotEmpty()) &quot;com.example.upfiles.$moduleName&quot; else &quot;com.example.upfiles&quot;    compileSdk = libs.findVersion(&quot;compileSdk&quot;).get().requiredVersion.toInt()    defaultConfig {        minSdk = libs.findVersion(&quot;minSdk&quot;).get().requiredVersion.toInt()    }    compileOptions {        sourceCompatibility = JavaVersion.VERSION_17        targetCompatibility = JavaVersion.VERSION_17    }    packaging {        resources {            excludes += &quot;/META-INF/{AL2.0,LGPL2.1}&quot;        }    }}کد بالا تمام کانفیگ های سمت اندروید را انجام میده از min sdk و compile sdk گرفته تا نسخه جاوا و حتی namespace البته میتونین طبق سلیقتون تغییرش بدین یا قسمتیش را حذف کنید.حالا همون کار بالا را برای  Cocoapods هم تکرار میکنیم:import org.gradle.api.Projectimport org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtensioninternal fun Project.configureKotlinCocoapods(    extension: CocoapodsExtension) = extension.apply {    val moduleName = this@configureKotlinCocoapods.path        .split(&quot;:&quot;)        .drop(1)        .joinToString(&quot;-&quot;)    summary = &quot;Some description for the Shared Module&quot;    homepage = &quot;Link to the Shared Module homepage&quot;    version = &quot;1.0&quot; //your cocoapods version    ios.deploymentTarget = &quot;14.1&quot; //your iOS deployment target    name = moduleName    framework {        isStatic = true //static or dynamic according to your project        baseName = moduleName    }}و در آخر نوبت به kotlin multiplatform  میرسه مثل قبل فایل جدید ایجاد میکنیم و کدهای زیر را به اون اضافه میکنیم:import com.example.upfiles.libsimport org.gradle.api.Projectimport org.gradle.api.plugins.ExtensionAwareimport org.gradle.kotlin.dsl.configureimport org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtensionimport org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtensioninternal fun Project.configureKotlinMultiplatform(    extension: KotlinMultiplatformExtension) = extension.apply {    jvmToolchain(17)//     targets    androidTarget()    iosArm64()    iosX64()    iosSimulatorArm64()    //common dependencies    sourceSets.apply {       getByName(&quot;commonMain&quot;)  {            dependencies {                implementation(libs.findLibrary(&quot;koin.core&quot;).get())                implementation(libs.findLibrary(&quot;coroutines.core&quot;).get())                implementation(libs.findLibrary(&quot;kotlinx-dateTime&quot;).get())                implementation(libs.findLibrary(&quot;napier&quot;).get())            }        }        getByName(&quot;androidMain&quot;) {            dependencies {                implementation(libs.findLibrary(&quot;koin.android&quot;).get() )            }        }    }//    applying the Cocoapods Configuration we made    (this as ExtensionAware).extensions.configure&lt;CocoapodsExtension&gt;(::configureKotlinCocoapods)}خب کار ما تموم شد فقط باید کدهایی که نوشتیم را تبدیل به کاستوم پلاگین کنیم تا بتونیم توی ماژول هامون ازشون استفاده کنیم.یک کلاس به اسم KotlinMultiplatformPlugin میسازیم با کد زیر:package com.example.upfilesimport com.android.build.api.dsl.LibraryExtensionimport configureKotlinMultiplatformimport configureKotlinAndroidimport org.gradle.api.Pluginimport org.gradle.api.Projectimport org.gradle.kotlin.dsl.configureimport org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtensionclass KotlinMultiplatformPlugin: Plugin&lt;Project&gt; {    override fun apply(target: Project):Unit = with(target){        with(pluginManager){            apply(libs.findPlugin(&quot;kotlinMultiplatform&quot;).get().get().pluginId)            apply(libs.findPlugin(&quot;kotlinCocoapods&quot;).get().get().pluginId)            apply(libs.findPlugin(&quot;androidLibrary&quot;).get().get().pluginId)        }        extensions.configure&lt;KotlinMultiplatformExtension&gt;(::configureKotlinMultiplatform)        extensions.configure&lt;LibraryExtension&gt;(::configureKotlinAndroid)    }}و یک کلاس دیگه به اسم ComposeMultiplatformPlugin :package com.example.upfilesimport org.gradle.api.Pluginimport org.gradle.api.Projectimport org.gradle.kotlin.dsl.configureimport org.gradle.kotlin.dsl.getByTypeimport org.jetbrains.compose.ComposeExtensionimport org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtensionclass ComposeMultiplatformPlugin : Plugin&lt;Project&gt; {    override fun apply(target: Project) = with(target) {        with(pluginManager) {            apply(libs.findPlugin(&quot;composeMultiplatform&quot;).get().get().pluginId)        }        val composeDeps = extensions.getByType&lt;ComposeExtension&gt;().dependencies        extensions.configure&lt;KotlinMultiplatformExtension&gt; {            sourceSets.apply {                getByName(&quot;commonMain&quot;) {                    dependencies {                        implementation(composeDeps.runtime)                        implementation(composeDeps.foundation)                        implementation(composeDeps.material3)                        implementation(composeDeps.materialIconsExtended)                        implementation(libs.findLibrary(&quot;androidx-activity-compose&quot;).get())                    }                }            }        }    }}نوبت به رجیستر کردن پلاگین هامون رسید، کد فایل build.gradle.kts از ماژول convention را به صورت زیر آپدیت میکنیم:plugins {    &#x60;kotlin-dsl&#x60;}group = &quot;com.example.upfiles.buildlogic&quot;dependencies {    compileOnly(libs.android.gradlePlugin)    compileOnly(libs.kotlin.gradlePlugin)    compileOnly(libs.compose.gradlePlugin)}gradlePlugin {    plugins {        register(&quot;kotlinMultiplatform&quot;){            id = &quot;com.example.upfiles.kotlinMultiplatform&quot;            implementationClass = &quot;com.example.upfiles.KotlinMultiplatformPlugin&quot;        }        register(&quot;composeMultiplatform&quot;){            id = &quot;com.example.upfiles.composeMultiplatform&quot;            implementationClass = &quot;com.example.upfiles.ComposeMultiplatformPlugin&quot;        }    }}میتونیم برای زیباتر شدن کدهامون دو تا پلاگینی که رجیستر کردیم یعنی com.example.upfiles.KotlinMultiplatformPlugincom.example.upfiles.composeMultiplatformرا هم ببریم توی ورژن کاتالوگمون:[plugins]composeMultiplatform = { id = &quot;com.example.upfiles.composeMultiplatform&quot;, version = &quot;unspecified&quot; }kotlinMultiplatform = { id = &quot;com.example.upfiles.kotlinMultiplatform&quot;, version = &quot;unspecified&quot; }و تمام دیگه میتونیم فایل های Gradle ماژول هامون را خوانا تر بنویسیمنمونه کد فایل ها قبل از تغییرات:import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApiplugins {    kotlin(&quot;multiplatform&quot;)  kotlin(&quot;plugin.serialization&quot;)    id(&quot;com.android.library&quot;)    id(&quot;org.jetbrains.compose&quot;)}@OptIn(ExperimentalKotlinGradlePluginApi::class)kotlin {    targetHierarchy.default()    androidTarget()    ios()    iosArm64()    iosX64()    iosSimulatorArm64()    sourceSets {        val commonMain by getting {            dependencies {                implementation(compose.runtime)                implementation(compose.foundation)                implementation(compose.material3)                implementation(compose.materialIconsExtended)                implementation(libs.koin.core)                implementation(libs.coroutines)            }        }    }}android {    compileSdk = libs.versions.compileSdk.get().toInt()    namespace = &quot;com.example.upfiles.profile&quot;    sourceSets[&quot;main&quot;].manifest.srcFile(&quot;src/androidMain/AndroidManifest.xml&quot;)    sourceSets[&quot;main&quot;].res.srcDirs(&quot;src/main/resources&quot;)    sourceSets[&quot;main&quot;].resources.srcDirs(&quot;src/main/resources&quot;)    defaultConfig {        minSdk = libs.versions.minSdk.get().toInt()    }    compileOptions {        sourceCompatibility = JavaVersion.VERSION_17        targetCompatibility = JavaVersion.VERSION_17    }    kotlin {        jvmToolchain(17)    }}نمونه کد ریفکتور شده:import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApiplugins {    alias(libs.plugins.composeMultiplatform)    alias(libs.plugins.kotlinMultiplatform)    kotlin(&quot;plugin.serialization&quot;) version libs.versions.kotlin.get()}4-سخن پایانیهمان طور که در برنامه نویسی اندروید ما به وسلیه gradle convention plugin کدهای بیلد ماژول های خود را خواناتر و منسجم تر میکنیم میتوانیم در Kotlin Multiplatform  هم به آسانی همین کار را انجام دهیم.متاسفانه با اینکه تلاش زیادی کردم موفق نشدم پلاگین هایی به عنوان نمونه kotlin serialization را به کاستوم پلاگین اضافه کنم و نتیجه جستجو در این مورد این بود که این کار ممکن نیست خوشحال میشم اگه راهی بلد هستین با بنده به اشتراک بزارید همچنین هر گونه بهبودی بنظرتون میرسه خوشحال میشم بگینبا تشکر</description>
                <category>محمد جواد صفاتاج</category>
                <author>محمد جواد صفاتاج</author>
                <pubDate>Wed, 12 Jun 2024 15:25:34 +0330</pubDate>
            </item>
            </channel>
</rss>