Updated to 1.3.60 and used the target shortcuts for ios and now the platform libraries are missing. I'm using NSUserDefaults, dispatch_async, and dispatch_get_main_queue. I can't import them but it's building normally.
Please try to add this line: kotlin.mpp.enableGranularSourceSetsMetadata=true to the gradle.properties of your project.
Hmmm. Just did that and now, there's no syntax highlighting on my multiplatform modules.
Okay, maybe the problem is somewhere else. Can you please illustrate by some snippet what is your project structure and how are you setting the targets?
Sure.
My project is a multiplatform project for Android and iOS.
├── android
| ├── app-modules-1
| ├── app-modules-2
| └── library-module-1
| └── library-module-2
| └── library-module-3
├── shared
| ├── shared-module-1
| └── shared-module-2
└── ios
└── ios-stuff
The shared folder contains the multiplatform modules and I configure them through a function I created in buildSrc. A typical configuration for a shared module would be:
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.multiplatform")
id("org.jetbrains.kotlin.native.cocoapods")
id("com.myproject.multiplatform.android")
}
setupKotlinMultiplatform("SharedModule1")
version = "1.0.0"
kotlin {
cocoapods {
summary = "Shared module for Android and iOS"
homepage = "Link to a Kotlin/Native module homepage"
}
}
and setupKotlinMultiplatform just abstracts the details and so I don't have to do them per module
fun Project.setupKotlinMultiplatform(frameworkName: String) {
val kotlinMultiplatformExtension = project.extensions.getByType<KotlinMultiplatformExtension>()
kotlinMultiplatformExtension.apply {
ios {
binaries {
framework(frameworkName) {
baseName = frameworkName
}
}
}
android()
sourceSets["commonMain"].dependencies {
MultiplatformDependencies.coreCommonDependencies.forEach { implementation(it) }
}
sourceSets["iosMain"].dependencies {
MultiplatformDependencies.coreNativeDependencies.forEach { implementation(it) }
}
}
tasks.filterIsInstance<KotlinNativeLink>()
.filter { it.binary is Framework }
.forEach {
val framework = it.binary
if (framework is Framework) {
val linkTask = framework.linkTask
val syncTaskName = linkTask.name.replaceFirst("link", "sync")
val syncFramework = tasks.create(syncTaskName, Sync::class) {
group = "cocoapods"
from(framework.outputDirectory)
into(file("build/cocoapods/framework"))
}
syncFramework.dependsOn(linkTask)
}
}
}
then I created a plugin to configures the android target in the multiplatform module for the source set, dependencies, and flavors
open class MyProjectMultiplatformAndroidPlugin : Plugin<Project> {
override fun apply(project: Project) {
val libraryExtension = project.extensions.getByType<LibraryExtension>()
libraryExtension.configureAndroidDirectory()
libraryExtension.configureAndroidLibrary()
project.configureAndroidDependencies()
}
internal fun BaseExtension.configureCommonAndroid() {
compileSdkVersion(Properties.COMPILE_SDK_VERSION)
defaultConfig {
minSdkVersion(Properties.MIN_SDK_VERSION)
targetSdkVersion(Properties.TARGET_SDK_VERSION)
}
flavorDimensions("environment")
}
internal fun LibraryExtension.configureAndroidLibrary() {
configureCommonAndroid()
buildTypes {
getByName("release") {
isMinifyEnabled = true
consumerProguardFiles("consumer-rules.pro")
}
}
productFlavors {
create("dev")
create("production")
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
private fun LibraryExtension.configureAndroidDirectory() {
sourceSets {
getByName("main") {
manifest.srcFile("src/androidMain/AndroidManifest.xml")
java.srcDirs("src/androidMain/kotlin")
res.srcDirs("src/androidMain/res")
}
}
}
private fun Project.configureAndroidDependencies() = dependencies {
MultiplatformDependencies.coreAndroidDependencies.forEach {
add("implementation", it)
}
}
}
and then my multiplatform module would just be like this:
├── androidMain
| └── kotlin
| └── com.myproject.whatever
├── commonMain
| └── kotlin
| └── com.myproject.whatever
└── iosMain
└── kotlin
└── com.myproject.whatever
Prior to this, I was using the switching mechanism:
val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget =
if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true)
::iosArm64
else
::iosX64
iOSTarget("ios") {
binaries {
framework(frameworkName) {
baseName = frameworkName
if (iOSTarget == presets.getByName("iosX64")) {
embedBitcode("disable")
}
}
}
}
I am sorry but I was unable to reproduce exactly that behavior. If it's not too hard, I'd ask you to construct some relatively small reproducer - it would be wonderful. The problem here is that this flag is in a very-experimental stage of developing, so some cases probably can fail.
About the ios() shortcut. The main issue here is that the iosMain source set, as mentioned in the documentation, is just an intermediate common set, not a platform-specific one. So, for now, the IDE doesn't even try to resolve platform-specific dependencies for it. This inconvenience is the reason why this feature was not in the changelog. But on the compilation, everything goes fine, as you also noticed.
Hello @artdfel! Thanks for trying to help me. Here's the small project you're requesting.
I've also tried that it works on 1.3.50 regardless on whether I'm using the switching mechanisim or the ios shortcut on 1.3.60.
For now, I'll be using it since it compiles anyway.
Hello @kuuuurt! I've checked the project you provided in IDEA 2019.2 with Kotlin IDE-plugin 1.3.61 and haven't observed the problem. The platform libraries are really missing in the iosMain source set initially but adding the kotlin.mpp.enableGranularSourceSetsMetadata=true to gradle.properties fixes this issue. I don't observe highlighting breaking either.
BTW, which IDE (IDEA or Android Studio) do you use and what is its version? What is the version of your Kotlin IDE-plugin?
Thanks for the response @ilmat192. I'm using Android Studio 3.5.2 and my Kotlin plugin was on 1.3.50. Just updated to 1.3.61 and it worked!
Now, I'm having problems with the libraries. iosMain can't see the dependencies I've included, specifically coroutines but that's another issue so I'm closing this. Thanks for the help!
TL;DR make sure Kotlin Plugin is updated and use kotlin.mpp.enableGranularSourceSetsMetadata=true on gradle.properties
I'm having problems with the libraries. iosMain can't see the dependencies I've included, specifically coroutines but that's another issue
Yes, it's a known issue. At the moment an IDE support for such intermediate source sets like iosMain is very experimental, requires kotlin.mpp.enableGranularSourceSetsMetadata=true to be specified and is enabled for platform libraries only.
Is there any workaround for this so we can see the native libraries? I haven't confirmed if it also compiles even though the imports aren't working. I'll have to get back on that. Seems like right now, it's choosing between the platform libraries and the kotlin/native libraries.
Is there any workaround for this so we can see the native libraries?
Only using the old switching mechanism you referred above.
I have this workaround in my build.gradle:
// You may uncomment this line for autocompletion to work on Android Studio
//iosX64('ios') // DO NOT COMMIT THIS UNCOMMENTED LINE
Uncommenting that line makes autocompletion work, and the extreme warning comments are enough to keep that hack at bay. If I understand correctly what's going on, iosX64('ios') replaces the intermediate ios stuff with a normal iosX64 target that the IDE understands.
It's horrible and manual, but its enough for my 2 person team while we wait for this to be properly fixed.
kotlin.mpp.enableGranularSourceSetsMetadata=true breaks the android target expect/actual declaration stuff, so only @NinoScript solution works for me regarding the platform declarations. Alas, cocoapods library imports don't seem to get resolved. Any idea what fixes that?
@NinoScript your solution also worked for me. Do you (or anyone else on the thread) know if there's an issue on YouTrack regarding this problem?
@jeremangnr There's no issues for me starting from Kotlin 1.4 onward. However, I needed to create a new project from scratch in order to resolve all the issues.
Most helpful comment
I have this workaround in my
build.gradle:Uncommenting that line makes autocompletion work, and the extreme warning comments are enough to keep that hack at bay. If I understand correctly what's going on,
iosX64('ios')replaces the intermediateiosstuff with a normaliosX64target that the IDE understands.It's horrible and manual, but its enough for my 2 person team while we wait for this to be properly fixed.