expect/actual एक Kotlin Multiplatform तंत्र है जो सामान्य कोड में प्लेटफ़ॉर्म-निर्भर API घाषित करने की अनुमति देता है। expect कीवर्ड commonMain में एक फ़ंक्शन, क्लास या प्रॉपर्टी का एक अनुबंध बनाता है, जबकि actual कीवर्ड प्रत्येक प्लेटफ़ॉर्म के लिए एक विशिष्ट कार्यान्वयन प्रदान करता है। कंपाइलर सत्यापित करता है कि सभी लक्ष्य प्लेटफ़ॉर्मों पर प्रत्येक expect घोषणा के अनुरूप actual कार्यान्वयन हो। JetBrains, 2025 के अनुसार, यह तंत्र 80% KMM परियोजनाओं में प्लेटफ़ॉर्म व्यवसायिक तर्क के कार्यान्वयन के लिए उपयोग किया जाता है।
मुख्य बातें
expect/actual प्लेटफ़ॉर्म-उन्मुख प्रोग्रामिंग के कार्यान्वयन के लिए Kotlin Multiplatform का एक घोषणात्मक तंत्र है। यह एक बार सामान्य मॉड्यूल (expect) में API का वर्णन करने और इसे प्रत्येक प्लेटफ़ॉर्म (actual) के लिए अलग-अलग लागू करने की अनुमति देता है। इंटरफ़ेस के विपरीत, expect/actual वर्चुअल कॉल नहीं बनाता — कंपाइलर कंपाइल टाइम पर expect और actual घोषणाओं को जोड़ता है, जिससे डायनेमिक डिस्पैच का ओवरहैड समाप्त हो जाता है।
expect/actual का इतिहास 2017 में Kotlin Multiplatform की शुरुआत के साथ शुरू हुआ। शुरुआत में, इस तंत्र को expect/actual declarations कहा जाता था और यह प्रयोगात्मक था। Kotlin 1.2 में expect एनोटेशन जोड़े गए, और Kotlin 1.3 में expect/actual क्लास और फ़ंक्शन के लिए स्थिर हो गया। समय के साथ तंत्र का विस्तार हुआ: Kotlin 1.6 ने कंपैनियन ऑब्जेक्ट के लिए expect/actual का समर्थन जोड़ा, Kotlin 1.7 ने enum क्लास के लिए, और Kotlin 2.0 ने typealias के लिए।
expect/actual की मुख्य विशेषता कंपाइल-टाइम सुरक्षा है। यदि कोई डेवलपर commonMain में एक expect घोषणा जोड़ता है लेकिन iOS के लिए actual कार्यान्वयन प्रदान करना भूल जाता है, तो कंपाइलर एक त्रुटि उत्पन्न करेगा। यह रनटाइम विफलताओं को रोकता है जो रिफ़लेक्शन या प्लेटफ़ॉर्म कोड के डायनेमिक लोडिंग का उपयोग करने वाले दृष्टिकोणों में आम हैं।
expect/actual का तंत्र source set स्तर पर काम करता है — Kotlin Multiplatform की मॉड्यूल प्रणाली। सभी प्लेटफ़ॉर्मों के लिए उपलब्ध सामान्य कोड commonMain source set में रहता है। प्लेटफ़ॉर्म-निर्भर कोड iosMain, androidMain, macosMain आदि में रहता है। commonMain में expect कीवर्ड एक API घाषित करता है, जबकि प्लेटफ़ॉर्म source set में actual कीवर्ड कार्यान्वयन प्रदान करता है। कंपाइलर कोड जनरेशन स्तर पर उन्हें जोड़ता है, लक्ष्य प्लेटफ़ॉर्म के लिए expect फ़ंक्शन कॉल को संगत actual कार्यान्वयन से बदलता है।
एक विशिष्ट KMM परियोजना में source set पदानुक्रम इस प्रकार दिखता है: commonMain में expect घोषणाएँ हैं, iosMain और androidMain में actual कार्यान्वयन हैं। iOS के लिए संकलन करते समय iosMain से actual का उपयोग होता है, Android के लिए संकलन करते समय androidMain से actual का। Source set मध्यवर्ती हो सकते हैं (उदाहरण के लिए, एक विशिष्ट आर्किटेक्चर के लिए iosArm64Main), जो विभिन्न उपकरणों के लिए कार्यान्वयनों को परिशोधित करने की अनुमति देते हैं।
// commonMain — expect declaration
expect fun getPlatformName(): String
// androidMain — actual for Android
actual fun getPlatformName(): String = "Android"
// iosMain — actual for iOS
actual fun getPlatformName(): String = "iOS"
Kotlin कंपाइलर expect/actual के साथ काम करते समय कई शर्तों की जाँच करता है। प्रत्येक सक्रिय प्लेटफ़ॉर्म के लिए प्रत्येक expect घोषणा का actual कार्यान्वयन होना चाहिए। actual घोषणा के हस्ताक्षर expect हस्ताक्षर से मेल खाना चाहिए (@OptionalExpectation एनोटेशन इस आवश्यकता को शिथिल कर सकता है)। एक्सेस मॉडिफायर, रिटर्न टाइप और पैरामीटर समान होने चाहिए। कंपाइलर expect और actual घोषणाओं के बीच चाक्रीय निर्भरताओं की अनुपस्थिति की भी जाँच करता है।
expect/actual कई प्रकार की घोषणाओं का समर्थन करता है। सबसे अधिक उपयोग प्लेटफ़ॉर्म संचालनों के लिए expect/actual फ़ंक्शन, नेटिव कार्यान्वयन की आवश्यकता वाली वस्तुओं के लिए expect/actual क्लास, और स्थिरांकों और सेटिंग्स के लिए expect/actual प्रॉपर्टी हैं। प्रत्येक प्रकार के अपने उपयोग नियम और सीमाएँ हैं।
Expect/actual फ़ंक्शन सबसे सरल और सामान्य प्रकार हैं। इनका उपयोग प्लेटफ़ॉर्म API जैसे समय प्राप्त करना, फ़ाइलें पढ़ना या HTTP अनुरोध भेजने के लिए किया जाता है। Expect/actual क्लास का उपयोग वस्तुओं को बनाने के लिए किया जाता है जो सीधे नेटिव कोड के साथ इंटरैक्ट करती हैं (उदाहरण के लिए, कैमरा, जीओलॉकेशन या की स्टोरेज तक पहुंचने के लिए)। Expect/actual प्रॉपर्टी (val) प्लेटफ़ॉर्म स्थिरांकों के लिए उपयुक्त हैं — OS नाम, SDK संस्करण या सिस्टम निर्देशिका पथ।
| घोषणा प्रकार | कीवर्ड | उपयोग उदाहरण |
|---|---|---|
| फ़ंक्शन | expect fun / actual fun | एक अनूठा डिवाइस पहचानकर्ता प्राप्त करना |
| क्लास | expect class / actual class | SecureStorage तक पहुंचना (Keychain / EncryptedSharedPreferences) |
| प्रॉपर्टी | expect val / actual val | वर्तमान प्लेटफ़ॉर्म (iOS / Android) |
| Enum क्लास | expect enum / actual enum | उपलब्ध एप अनुमतियों की सूची |
| Typealias | expect typealias / actual typealias | प्लेटफ़ॉर्म-विशिष्ट नेटवर्क प्रतिक्रिया प्रकार |
Kotlin के सभी निर्माणों का expect/actual के साथ उपयोग नहीं किया जा सकता। एक expect घोषणा में बॉडी नहीं हो सकता — केवल हस्ताक्षर। एक expect क्लास में पैरामीटर के साथ कंस्ट्रक्टर नहीं हो सकता (इसका एक खाली प्राइमरी कंस्ट्रक्टर होना चाहिए)। enum expect/actual के लिए, सभी स्थिरांक expect और actual दोनों में समान होने चाहिए। Expect प्रॉपर्टी val (वर नहीं) होनी चाहिए, क्योंकि प्लेटफ़ॉर्म प्रॉपर्टीज़ के लिए सामान्य मॉड्यूल में अवस्था संग्रहीत करना अर्थहीन है।
आइए सरल फ़ंक्शन से लेकर पूर्ण क्लास तक expect/actual के व्यावहारिक उदाहरणों का पता लगाएँ। मूल मामला UI में उपयोग के लिए प्लेटफ़ॉर्म का नाम प्राप्त करना है। अधिक जटिल उदाहरणों में नेटिव स्टोरेज तक पहुंचना और प्लेटफ़ॉर्म थ्रेड्स के साथ काम करना शामिल है।
// commonMain — expect class for secure storage
expect class PlatformStorage {
fun save(key: String, value: String)
fun get(key: String): String?
fun remove(key: String)
}
// androidMain — actual on Android
actual class PlatformStorage {
private val prefs = AppContext.getSharedPreferences("secure", 0)
actual fun save(key: String, value: String) { prefs.edit().putString(key, value).apply() }
actual fun get(key: String): String? = prefs.getString(key, null)
actual fun remove(key: String) { prefs.edit().remove(key).apply() }
}
इस उदाहरण में, expect क्लास PlatformStorage एक सरल की-वैल्यू स्टोरेज का अनुबंध परिभाषित करता है। Android पर, कार्यान्वयन SharedPreferences का उपयोग करता है, जबकि iOS पर Keychain या NSUserDefaults का। expect/actual के कारण, commonMain में व्यवसायिक तर्क प्लेटफ़ॉर्म कार्यान्वयन के बारे में जाने बिना ही save/get/remove को कॉल करता है।
// iosMain — actual on iOS with Keychain
actual class PlatformStorage {
actual fun save(key: String, value: String) {
val query = mapOf<String, Any>(
kSecClass to kSecClassGenericPassword,
kSecAttrAccount to key,
kSecValueData to value.encodeToByteArray()
)
SecItemAdd(query, null)
}
actual fun get(key: String): String? {
val query = mapOf<String, Any>(
kSecClass to kSecClassGenericPassword,
kSecAttrAccount to key,
kSecReturnData to true
)
val result = mutableMapOf<String, Any>()
return if (SecItemCopyMatching(query, result) == errSecSuccess)
result[kSecValueData]?.toString()
else null
}
actual fun remove(key: String) {
val query = mapOf<String, Any>(
kSecClass to kSecClassGenericPassword,
kSecAttrAccount to key
)
SecItemDelete(query)
}
}
expect/actual API डिजाइन करते समय, कई सिद्धांतों का पालन किया जाना चाहिए। expect घोषणाओं की संख्या को कम से कम रखें — जितना अधिक सामान्य कोड होगा, रखरखाव उतना ही सरल होगा। expect/actual का उपयोग केवल उन API के लिए करें जो वास्तव में प्लेटफ़ॉर्मों के बीच भिन्न होती हैं। बाकी कोड के लिए, फ़ैक्टरी या डिपेंडेंसी इंजेक्शन के साथ इंटरफ़ेस का उपयोग करें, जो परीक्षण को सरल बनाता है।
expect घोषणाओं को विषयगत मॉड्यूल में समूहीत करने की अनुशंसा है, एक ही फ़ाइल में मिलाने के बजाय। उदाहरण के लिए, Storage.kt भंडारण संबंधी expect घोषणाओं के लिए, Platform.kt OS के साथ काम करने वाले expect फ़ंक्शन के लिए, और Analytics.kt विश्लेषण expect क्लास के लिए। यह KMM परियोजना के प्लेटफ़ॉर्म सतह को नेविगेट करने और समझने में सरलता पैदा करता है। प्रत्येक actual फ़ाइल संगत source set में होनी चाहिए: androidMain, iosMain, desktopMain आदि।
expect fun के साथ actual fun के माध्यम से डिफ़ॉल्ट कार्यान्वयन जहां actual सामान्य कोड का उपयोग करता है, एक सामान्य प्रतिरूप है। यदि प्लेटफ़ॉर्म कार्यान्वयन डिफ़ॉल्ट से अलग नहीं है, तो expect/actual की आवश्यकता नहीं है। ऐसे मामलों में, commonMain में एक सरल फ़ंक्शन का उपयोग करें। साथ ही, तुच्छ getters के लिए expect/actual से बचें — स्थिरांकों के साथ expect val का उपयोग करें।
expect/actual कोड का उचित संरचना परियोजना पढ़ने क्षमता के लिए महत्वपूर्ण है। प्रत्येक expect/actual मॉड्यूल का एक ही प्रवेश बिंदु होना चाहिए। उदाहरण संगठन: commonMain/kotlin/com/project/platform में expect घोषणाएँ हैं, androidMain/kotlin/com/project/platform में Android के लिए actual है, iosMain/kotlin/com/project/platform में iOS के लिए actual है। फ़ाइल और पैकेज के नाम expect और actual के लिए समान होने चाहिए, ताकि डेवलपर संगत कार्यान्वयन जल्दी ढूंढ सके।
प्लेटफ़ॉर्म फ़ैक्टरी के सااत्ह इंटरफ़ेस expect/actual का मुख्य विकल्प है। एक expect क्लास के बजाय, आप commonMain में एक इंटरफ़ेस घाषित कर सकते हैं और प्लेटफ़ॉर्म मॉड्यूल में ठोस क्लास बना सकते हैं। एक फ़ैक्टरी या DI कंटेनर रनटाइम पर सही कार्यान्वयन प्रदान करता है। यह दृष्टिकोण परीक्षण के लिए बेहतर है, क्योंकि इंटरफ़ेस को मॉक किया जा सकता है।
डिपेंडेंसी इंजेक्शन (Koin, Kodein) एक अधिक लचीला लेकिन कम प्रभावी दृष्टिकोण है। एक DI कंटेनर प्रत्येक प्लेटफ़ॉर्म के लिए अलग-अलग कॉन्फ़िगर किया जाता है और सामान्य कोड को प्लेटफ़ॉर्म निर्भरताएँ प्रदान करता है। expect/actual के विपरीत, इंजेक्शन रनटाइम पर होता है, जो परीक्षण के लिए कार्यान्वयन को बदलने की अनुमति देता है। दूसरी ओर, DI कॉन्फ़िगरेशन त्रुटियाँ केवल रनटाइम पर ही पता लगती हैं, कंपाइल टाइम पर नहीं।
| दृष्टिकोण | कंपाइल टाइम जाँच | परीक्षण लचीलापन | रनटाइम ओवरहैड |
|---|---|---|---|
| expect/actual | पूर्ण | कम (actual को मॉक नहीं किया जा सकता) | शून्य (कंपाइल-टाइम बांधन) |
| इंटरफ़ेस + फ़ैक्टरी | आंशिक | उच्च (मॉक किया जा सकता है) | न्यूनतम (वर्चुअल कॉल) |
| डिपेंडेंसी इंजेक्शन | नहीं (रनटाइम) | उच्च | मध्यम (DI प्रॉक्सी) |
expect/actual और विकल्पों के बीच चयन संदर्भ पर निर्भर करता है। प्रदर्शन-क्रितिकाल कोड (गेम इंजन, रियल-टाइम प्रोसेसिंग) के लिए, expect/actual बेहतर है क्योंकि इसका ओवरहैड शून्य है। व्यवसायिक तर्क (रिपॉज़िटरी, यूज केस) के लिए, परीक्षण को सरल बनाने के लिए DI के साथ इंटरफ़ेस का उपयोग करना बेहतर है। एक संयुक्त दृष्टिकोण — निम्न-स्तरीय प्लेटफ़ॉर्म संचालनों के लिए expect/actual और व्यवसायिक तर्क परत के लिए इंटरफ़ेस — अधिकांश उत्पादन KMM परियोजनाओं में उपयोग किया जाता है।
अक्सर पूछे जाने वाले प्रश्न
expect/actual बिना वर्चुअल कॉल के कंपाइल टाइम पर कार्यान्वयन को बांधता है, जबकि इंटरफ़ेस रनटाइम पर बांधते हैं। expect/actual सभी प्लेटफ़ॉर्मों के लिए कार्यान्वयन की गारंटी देता है, इंटरफ़ेस को रनटाइम जाँच की आवश्यकता होती है।
हाँ, expect enum Kotlin 1.7 से समर्थित है। expect और actual enum दोनों में सभी स्थिरांक समान होने चाहिए। अलग-अलग प्लेटफ़ॉर्मों पर अलग स्थिरांक मान होना एक संकलन त्रुटि है।
कंपाइलर प्रत्येक उस प्लेटफ़ॉर्म के लिए एक त्रुटि उत्पन्न करेगा जहां actual कार्यान्वयन गायब है। परियोजना तब तक नहीं बनेगी जब तक सभी expect घोषणाओं के लिए संगत actual कार्यान्वयन नहीं जोड़े जाते।
नहीं, expect और actual अलग-अलग source sets में होने चाहिए। expect commonMain या एक मध्यवर्ती source set में, actual एक प्लेटफ़ॉर्म source set में। expect और actual को एक ही source set में रखना एक संकलन त्रुटि है।
expect/actual का परीक्षण करने के लिए, प्लेटफ़ॉर्म परीक्षण source sets के साथ commonTest का उपयोग करें। commonTest में expect परीक्षण और प्रत्येक प्लेटफ़ॉर्म के लिए actual परीक्षण लिखें। एकीकरण परीक्षण प्रत्येक लक्ष्य प्लेटफ़ॉर्म पर अलग-अलग चलाए जाते हैं।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें