অ্যান্ড্রয়েড কেএমপির জন্য কাস্টম গ্রেডল প্লাগইন তৈরি করুন

এই ডকুমেন্টটি প্লাগইন লেখকদের জন্য একটি নির্দেশিকা প্রদান করে, যেখানে কোটলিন মাল্টিপ্ল্যাটফর্ম (KMP) সেটআপকে সঠিকভাবে শনাক্ত করা, এর সাথে ইন্টারঅ্যাক্ট করা এবং কনফিগার করার পদ্ধতি বর্ণনা করা হয়েছে। এতে একটি KMP প্রোজেক্টের মধ্যে অ্যান্ড্রয়েড টার্গেটগুলোর সাথে ইন্টিগ্রেশনের উপর বিশেষভাবে আলোকপাত করা হয়েছে। এই সুপারিশগুলো উভয় ক্ষেত্রেই প্রযোজ্য, আপনি আপনার প্রোজেক্টের মডিউলগুলোর মধ্যে কনফিগারেশনকে মানসম্মত করার জন্য কনভেনশন প্লাগইন তৈরি করুন বা বৃহত্তর কমিউনিটির ব্যবহারের জন্য প্লাগইন তৈরি করুন। KMP-এর ক্রমাগত বিবর্তনের সাথে সাথে, একটি মাল্টিপ্ল্যাটফর্ম প্রোজেক্টে সংজ্ঞায়িত সমস্ত প্ল্যাটফর্মে নির্বিঘ্নে কাজ করে এমন শক্তিশালী এবং ভবিষ্যৎ-উপযোগী টুলিং তৈরির জন্য সঠিক হুক এবং এপিআই—যেমন KotlinMultiplatformExtension , KotlinTarget টাইপ এবং অ্যান্ড্রয়েড-নির্দিষ্ট ইন্টিগ্রেশন ইন্টারফেস—বোঝা অপরিহার্য।

কোনো প্রজেক্টে কোটলিন মাল্টিপ্ল্যাটফর্ম প্লাগইন ব্যবহার করা হয়েছে কিনা তা পরীক্ষা করুন।

ত্রুটি এড়াতে এবং আপনার প্লাগইনটি যেন শুধুমাত্র KMP উপস্থিত থাকলেই চলে, তা নিশ্চিত করতে আপনাকে অবশ্যই পরীক্ষা করতে হবে যে প্রজেক্টটি KMP প্লাগইন ব্যবহার করছে কিনা। তাৎক্ষণিকভাবে পরীক্ষা না করে, KMP প্লাগইনটি প্রয়োগ হওয়ার প্রতিক্রিয়ায় plugins.withId() ব্যবহার করাই সর্বোত্তম পন্থা। এই প্রতিক্রিয়াশীল পদ্ধতিটি ব্যবহারকারীর বিল্ড স্ক্রিপ্টে প্লাগইনগুলো যে ক্রমে প্রয়োগ করা হয়, তার ওপর আপনার প্লাগইনের নির্ভরশীলতা রোধ করে।

import org.gradle.api.Plugin
import org.gradle.api.Project

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
            // The KMP plugin is applied, you can now configure your KMP integration.
        }
    }
}

মডেলটি অ্যাক্সেস করুন

সকল কোটলিন মাল্টিপ্ল্যাটফর্ম কনফিগারেশনের প্রবেশপথ হলো KotlinMultiplatformExtension এক্সটেনশনটি।

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
            val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
        }
    }
}

কোটলিন মাল্টিপ্ল্যাটফর্ম টার্গেটগুলিতে প্রতিক্রিয়া জানান

ব্যবহারকারী প্রতিটি টার্গেট যোগ করার সাথে সাথে আপনার প্লাগইনটি প্রতিক্রিয়াশীলভাবে কনফিগার করতে targets কন্টেইনারটি ব্যবহার করুন।

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
            val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
            kmpExtension.targets.configureEach { target ->
                // 'target' is an instance of KotlinTarget
                val targetName = target.name // for example, "android", "iosX64", "jvm"
                val platformType = target.platformType // for example, androidJvm, jvm, native, js
            }
        }
    }
}

লক্ষ্য-নির্দিষ্ট যুক্তি প্রয়োগ করুন

আপনার প্লাগইনকে যদি শুধুমাত্র নির্দিষ্ট ধরণের প্ল্যাটফর্মে লজিক প্রয়োগ করতে হয়, তবে একটি প্রচলিত পদ্ধতি হলো platformType প্রপার্টিটি পরীক্ষা করা। এটি একটি enum যা লক্ষ্যবস্তুকে বিস্তৃতভাবে শ্রেণীবদ্ধ করে।

উদাহরণস্বরূপ, এটি ব্যবহার করুন যদি আপনার প্লাগইনকে কেবল ব্যাপকভাবে পার্থক্য করার প্রয়োজন হয় (যেমন, শুধুমাত্র JVM-সদৃশ টার্গেটে চালানো):

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
            val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
            kmpExtension.targets.configureEach { target ->
                when (target.platformType) {
                    KotlinPlatformType.jvm -> { /* Standard JVM or Android */ }
                    KotlinPlatformType.androidJvm -> { /* Android */ }
                    KotlinPlatformType.js -> { /* JavaScript */ }
                    KotlinPlatformType.native -> { /* Any Native (iOS, Linux, Windows, etc.) */ }
                    KotlinPlatformType.wasm -> { /* WebAssembly */ }
                    KotlinPlatformType.common -> { /* Metadata target (rarely needs direct plugin interaction) */ }
                }
            }
        }
    }
}

অ্যান্ড্রয়েড-নির্দিষ্ট বিবরণ

যদিও সমস্ত অ্যান্ড্রয়েড টার্গেটে platformType.androidJvm ইন্ডিকেটরটি থাকে, ব্যবহৃত অ্যান্ড্রয়েড গ্রেডল প্লাগইনের উপর নির্ভর করে KMP-এর দুটি স্বতন্ত্র ইন্টিগ্রেশন পয়েন্ট রয়েছে: com.android.library বা com.android.application ব্যবহারকারী প্রোজেক্টের জন্য KotlinAndroidTarget , এবং com.android.kotlin.multiplatform.library ব্যবহারকারী প্রোজেক্টের জন্য KotlinMultiplatformAndroidLibraryTarget

KotlinMultiplatformAndroidLibraryTarget API-টি AGP 8.8.0-তে যোগ করা হয়েছিল, তাই আপনার প্লাগইনের ব্যবহারকারীরা যদি AGP-এর নিম্নতর সংস্করণে কাজ করে, তাহলে target is KotlinMultiplatformAndroidLibraryTarget পরীক্ষা করলে ClassNotFoundException দেখা দিতে পারে। এটিকে নিরাপদ করতে, টার্গেটের ধরন পরীক্ষা করার আগে AndroidPluginVersion.getCurrent() ব্যবহার করে দেখুন। মনে রাখবেন যে AndroidPluginVersion.getCurrent() ব্যবহারের জন্য AGP 7.1 বা তার উচ্চতর সংস্করণ প্রয়োজন।

import com.android.build.api.AndroidPluginVersion
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("com.android.kotlin.multiplatform.library") {
            val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
            kmpExtension.targets.configureEach { target ->
                if (target is KotlinAndroidTarget) {
                    // Old kmp android integration using com.android.library or com.android.application
                }
                if (AndroidPluginVersion.getCurrent() >= AndroidPluginVersion(8, 8) &&
                    target is KotlinMultiplatformAndroidLibraryTarget
                ) {
                    // New kmp android integration using com.android.kotlin.multiplatform.library
                }
            }
        }
    }
}

অ্যান্ড্রয়েড কেএমপি এক্সটেনশন এবং এর প্রোপার্টিগুলো অ্যাক্সেস করুন।

আপনার প্লাগইনটি প্রাথমিকভাবে কোটলিন মাল্টিপ্ল্যাটফর্ম প্লাগইন দ্বারা প্রদত্ত কোটলিন এক্সটেনশন এবং KMP অ্যান্ড্রয়েড টার্গেটের জন্য AGP দ্বারা প্রদত্ত অ্যান্ড্রয়েড এক্সটেনশনের সাথে ইন্টারঅ্যাক্ট করবে। একটি KMP প্রোজেক্টের কোটলিন এক্সটেনশনের ভেতরের android {} ব্লকটি KotlinMultiplatformAndroidLibraryTarget ইন্টারফেস দ্বারা উপস্থাপিত হয়, যা KotlinMultiplatformAndroidLibraryExtension কেও এক্সটেন্ড করে। এর মানে হলো, আপনি এই একটিমাত্র অবজেক্টের মাধ্যমে টার্গেট-নির্দিষ্ট এবং অ্যান্ড্রয়েড-নির্দিষ্ট উভয় ধরনের DSL প্রোপার্টি অ্যাক্সেস করতে পারবেন।

import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("com.android.kotlin.multiplatform.library") {
            val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)

            // Access the Android target, which also serves as the Android-specific DSL extension
            kmpExtension.targets.withType(KotlinMultiplatformAndroidLibraryTarget::class.java).configureEach { androidTarget ->

                // You can now access properties and methods from both
                // KotlinMultiplatformAndroidLibraryTarget and KotlinMultiplatformAndroidLibraryExtension
                androidTarget.compileSdk = 34
                androidTarget.namespace = "com.example.myplugin.library"
                androidTarget.withJava() // enable Java sources
            }
        }
    }
}

অন্যান্য অ্যান্ড্রয়েড প্লাগইনগুলির (যেমন com.android.library বা com.android.application ) মতো নয়, KMP অ্যান্ড্রয়েড প্লাগইন তার প্রধান DSL এক্সটেনশনটি প্রজেক্ট লেভেলে রেজিস্টার করে না। এটি KMP টার্গেট হায়ারার্কির মধ্যে থাকে, যাতে এটি শুধুমাত্র আপনার মাল্টিপ্ল্যাটফর্ম সেটআপে সংজ্ঞায়িত নির্দিষ্ট অ্যান্ড্রয়েড টার্গেটেই প্রযোজ্য হয়।

সংকলন এবং উৎস সেট পরিচালনা করুন

প্রায়শই, প্লাগইনগুলিকে শুধু টার্গেটের চেয়েও আরও সূক্ষ্ম স্তরে কাজ করতে হয়—বিশেষ করে, সেগুলিকে কম্পাইলেশন স্তরে কাজ করতে হয়। KotlinMultiplatformAndroidLibraryTarget এর মধ্যে KotlinMultiplatformAndroidCompilation ইনস্ট্যান্সগুলি থাকে (উদাহরণস্বরূপ, main , hostTest , deviceTest )। প্রতিটি কম্পাইলেশন কোটলিন সোর্স সেটের সাথে যুক্ত থাকে। প্লাগইনগুলি সোর্স, ডিপেন্ডেন্সি যোগ করতে বা কম্পাইলেশন টাস্ক কনফিগার করতে এগুলির সাথে ইন্টারঅ্যাক্ট করতে পারে।

import com.android.build.api.dsl.KotlinMultiplatformAndroidCompilation
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("com.android.kotlin.multiplatform.library") {
            val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
            kmpExtension.targets.configureEach { target ->
                target.compilations.configureEach { compilation ->
                    // standard compilations are usually 'main' and 'test'
                    // android target has 'main', 'hostTest', 'deviceTest'
                    val compilationName = compilation.name

                    // Access the default source set for this compilation
                    val defaultSourceSet = compilation.defaultSourceSet

                    // Access the Android-specific compilation DSL
                    if (compilation is KotlinMultiplatformAndroidCompilation) {

                    }

                    // Access and configure the Kotlin compilation task
                    compilation.compileTaskProvider.configure { compileTask ->

                    }
                }
            }
        }
    }
}

কনভেনশন প্লাগইনগুলিতে টেস্ট কম্পাইলেশন কনফিগার করুন

একটি কনভেনশন প্লাগইনে টেস্ট কম্পাইলেশনের জন্য ডিফল্ট মান (যেমন ইন্সট্রুমেন্টেড টেস্টের জন্য targetSdk ) কনফিগার করার সময়, আপনার withDeviceTest { } বা withHostTest { } এর মতো এনাবলার মেথড ব্যবহার করা এড়িয়ে চলা উচিত। এই মেথডগুলোকে ইগারলি কল করলে কনভেনশন প্লাগইন প্রয়োগকারী প্রতিটি মডিউলের জন্য সংশ্লিষ্ট অ্যান্ড্রয়েড টেস্ট ভ্যারিয়েন্ট এবং কম্পাইলেশন তৈরি হয়ে যায়, যা উপযুক্ত নাও হতে পারে। এছাড়াও, একটি নির্দিষ্ট মডিউলে সেটিংস পরিমার্জন করার জন্য এই মেথডগুলোকে দ্বিতীয়বার কল করা যায় না, কারণ তা করলে একটি এরর আসবে যেখানে বলা থাকবে যে কম্পাইলেশনটি ইতিমধ্যেই তৈরি করা হয়েছে।

এর পরিবর্তে, আমরা কম্পাইলেশন কন্টেইনারে একটি রিঅ্যাক্টিভ configureEach ব্লক ব্যবহার করার পরামর্শ দিই। এটি আপনাকে ডিফল্ট কনফিগারেশন সরবরাহ করার সুযোগ দেয়, যা কেবল তখনই প্রযোজ্য হয় যখন কোনো মডিউল স্পষ্টভাবে টেস্ট কম্পাইলেশন সক্ষম করে:

import com.android.build.api.dsl.KotlinMultiplatformAndroidDeviceTestCompilation
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("com.android.kotlin.multiplatform.library") {
            val kmpExtension =
                project.extensions.getByType(KotlinMultiplatformExtension::class.java)
            kmpExtension.targets.withType(KotlinMultiplatformAndroidLibraryTarget::class.java)
                .configureEach { androidTarget ->
                    androidTarget.compilations.withType(
                        KotlinMultiplatformAndroidDeviceTestCompilation::class.java
                    ).configureEach {
                        targetSdk { version = release(34) }
                    }
                }
        }
    }
}

এই প্যাটার্নটি নিশ্চিত করে যে আপনার কনভেনশন প্লাগইনটি লেজি থাকে এবং স্বতন্ত্র মডিউলগুলিকে ডিফল্টগুলির সাথে সাংঘর্ষিক না হয়ে তাদের পরীক্ষাগুলি সক্রিয় করতে ও আরও কাস্টমাইজ করতে withDeviceTest { } কল করার অনুমতি দেয়।

ভ্যারিয়েন্ট এপিআই-এর সাথে ইন্টারঅ্যাক্ট করুন

যেসব কাজের জন্য শেষ পর্যায়ের কনফিগারেশন, আর্টিফ্যাক্ট অ্যাক্সেস (যেমন ম্যানিফেস্ট বা বাইট-কোড), অথবা নির্দিষ্ট কম্পোনেন্ট চালু বা বন্ধ করার ক্ষমতার প্রয়োজন হয়, সেগুলোর জন্য আপনাকে অবশ্যই অ্যান্ড্রয়েড ভ্যারিয়েন্ট এপিআই (Android Variant API) ব্যবহার করতে হবে। কেএমপি (KMP) প্রোজেক্টে, এক্সটেনশনটির টাইপ হলো KotlinMultiplatformAndroidComponentsExtension

কেএমপি অ্যান্ড্রয়েড প্লাগইনটি প্রয়োগ করার সময় এক্সটেনশনটি প্রজেক্ট লেভেলে নিবন্ধিত হয়।

ভেরিয়েন্ট অথবা তাদের নেস্টেড টেস্ট কম্পোনেন্ট ( hostTests এবং deviceTests ) তৈরি নিয়ন্ত্রণ করতে beforeVariants ব্যবহার করুন। প্রোগ্রাম্যাটিকভাবে টেস্ট নিষ্ক্রিয় করতে বা DSL প্রোপার্টির মান পরিবর্তন করতে এটিই সঠিক জায়গা।

import com.android.build.api.variant.KotlinMultiplatformAndroidComponentsExtension
import org.gradle.api.Plugin
import org.gradle.api.Project

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("com.android.kotlin.multiplatform.library") {
            val androidComponents = project.extensions.findByType(KotlinMultiplatformAndroidComponentsExtension::class.java)
            androidComponents?.beforeVariants { variantBuilder ->
                // Disable all tests for this module
                variantBuilder.hostTests.values.forEach { it.enable = false }
                variantBuilder.deviceTests.values.forEach { it.enable = false }
            }
        }
    }
}

চূড়ান্ত ভ্যারিয়েন্ট অবজেক্ট ( KotlinMultiplatformAndroidVariant ) অ্যাক্সেস করতে onVariants ব্যবহার করুন। এখানেই আপনি রিজলভ করা প্রোপার্টিগুলো পরীক্ষা করতে পারেন অথবা মার্জ করা ম্যানিফেস্ট বা লাইব্রেরি ক্লাসের মতো আর্টিফ্যাক্টগুলোতে ট্রান্সফরমেশন রেজিস্টার করতে পারেন।

import com.android.build.api.variant.KotlinMultiplatformAndroidComponentsExtension
import org.gradle.api.Plugin
import org.gradle.api.Project

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.plugins.withId("com.android.kotlin.multiplatform.library") {
            val androidComponents = project.extensions.findByType(KotlinMultiplatformAndroidComponentsExtension::class.java)
            androidComponents?.onVariants { variant ->
                // 'variant' is a KotlinMultiplatformAndroidVariant
                val variantName = variant.name

                // Access the artifacts API
                val manifest = variant.artifacts.get(com.android.build.api.variant.SingleArtifact.MERGED_MANIFEST)
            }
        }
    }
}
{% হুবহু %} {% endverbatim %} {% হুবহু %} {% endverbatim %}