How to properly import a Kotlin Multiplatform project (and only run tasks necessary when building)

963 Views Asked by At

Is it possible to not have all the iOS (kotlin/Native) tasks (cinterop + cocoapods) run when I am developing the android app with a Kotlin Multiplatform Project imported?

Our current KMP project (SharedLibrary) structure is:

SharedLibrary
 - build.gradle.kts
 - settings.gradle.kts
 - ...
 - shared
   - build.gradle.kts
     - commonMain
     - androidMain (android library target)
     - ...  

We have a separate Android Project (SomeApp) with the following settings to import our shared library.

// settings.gradle.kts
include ":shared"
project(":shared").projectDir = file("../SharedLibrary/shared")

The thing is... this is quite an annoying development pattern especially since the iOS artifacts (cinterop + cocoapods etc) get rebuilt every time there is a change even if I only care about the android library artifact.

Things I tried:

  • I tried switching to a composite build but i get errors relating to gradle not being able to find the multiplatform plugin.
  • I am thinking of switching to pushing to local maven but it definitely will slow down the development process so I am resisting.

Is this an issue with our setup? Or are the tasks just dependent on each other and there is no way around it?

2

There are 2 best solutions below

2
On BEST ANSWER

You can exclude iOS target from build like this:

kotlin {
    android()
    // kotlin.native.cocoapods.target property passed by cocoapods build from Xcode 
    val shouldBuildIos = project.findProperty("kotlin.native.cocoapods.target") != null
    if (shouldBuildIos) {
        ios()
        cocoapods {
            // ...
        }
    }
    sourceSets {
        // ...
        if (shouldBuildIos) {
            val iosMain by getting {
                libDependencies(
                    "ktor.client.engine.ios",
                )
            }
        }
    }
}

But in this case you won't have any code suggestions in the IDE. Also be careful because your podspec will be removed in this case.

If you're only working on android part and an other dev is working on iOS one, you can create you own property in the local.properties, and make sure you won't push removing podspec file(or just ignore it)

But if you're a single dev it's not a good option. I have faced long cocoapods build time too, and decided to move it from the multiplatform module.

Each time I need it, I create an interface in the common code, and pass an instance implementing it or a "generator" function(if you don't wanna create an object unless it's needed) from iOS part.

in y iOS part it looks something like this:

featureProvider = FeatureProvider(
    context: .init(
        rootController: rootViewController,
        application: application,
        launchOptions: launchOptions
    ),
    providerGenerator: { socialNetwork, context -> CredentialProvider in
        switch socialNetwork {
        case .facebook:
            return FacebookProvider(context: context)
            
        case .google:
            return GoogleProvider(context: context)
            
        default: fatalError()
        }
    }
)
1
On

Just want to say a word about the problem from the supporter's point of view.

I found this YouTrack issue which seems related: https://youtrack.jetbrains.com/issue/KT-43796. Please check if this describes your problem correctly, and comment there if it does not. Also, that is the best place to get updates on the problem's status.