How to add thirdparty iOS pod library into kotlin native project ? getting error "SharedCode:cinteropAFNetworkingIos failed"
Asked Answered
C

2

5

I created Kotlin native project to shared code between iOS and android.I did integration for cocoapods in-order to use in iOS project using POD file, Project successfully run on iOS and Android but when I tried to used iOS pod library in Kotlin native project, I start getting errors below.

I know that I have to run pod install first from Xcode in-order to compile library in Kotlin native project.

SO iOS pod library should be converted via cinterop, to use in Kotlin Native Project.

I run below command just to check either framework compile successfully or not.

./gradlew :SharedCode:packForXCode

got this error


FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':SharedCode:cinteropAFNetworkingIos'.
> Cannot perform cinterop processing for AFNetworking: cannot determine headers location.

  Probably the build is executed from command line.
  Note that a Kotlin/Native module using CocoaPods dependencies can be built only from Xcode.

please find below Gradle file.

build.Gradle.kts


plugins {
    kotlin("multiplatform")
    kotlin("native.cocoapods")
}

kotlin {

    //select iOS target platform depending on the Xcode environment variables
    val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget =
        if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true)
            ::iosArm64
        else
            ::iosX64

    iOSTarget("ios") {
        binaries {
            framework("Shared") {
                baseName = "SharedCode"
            }
        }
    }
    jvm("android")

    sourceSets["commonMain"].dependencies {
        implementation("org.jetbrains.kotlin:kotlin-stdlib-common")
    }

    sourceSets["androidMain"].dependencies {
        implementation("org.jetbrains.kotlin:kotlin-stdlib")
    }

    version = "1.0.0"
    cocoapods {
        summary = "This is sample Summary"
        homepage = "Home URL"

        pod("AFNetworking", "~> 3.2.0")
    }
}


val packForXcode by tasks.creating(Sync::class) {
    group = "build"

    //selecting the right configuration for the iOS framework depending on the Xcode environment variables
    val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
    val framework = kotlin.targets.getByName<KotlinNativeTarget>("ios").binaries.getFramework(mode)

    inputs.property("mode", mode)
    dependsOn(framework.linkTask)

    val targetDir = File(buildDir, "xcode-frameworks")
    from({ framework.outputDirectory })
    into(targetDir)

    doLast {
        val gradlew = File(targetDir, "gradlew")
        gradlew.writeText("#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n")
        gradlew.setExecutable(true)
    }
}

tasks.getByName("build").dependsOn(packForXcode)```




Copperplate answered 8/2, 2020 at 11:51 Comment(4)
Have you run the build from Xcode? It has to be called from there.Jarrod
@ArtyomDegtyarev yes ran from Xcode but even on Xcode error is same.Copperplate
So, looking at this steps, you made everything just like that?Jarrod
@ArtyomDegtyarev I downloaded project from github.com/kotlin-hands-on/mpp-ios-android then I did cocoapods integration on this project to use iOS Pod (AFNetworking).Copperplate
J
6

I just tried these steps and managed to extend this sample with working interop of AFNetworking framework using CocoaPods plugin. These are my steps:

  1. After cloning the project and checking out the step-008 branch, edit build.gradle.kts that way: add CocoaPods plugin to the plugins section as id("org.jetbrains.kotlin.native.cocoapods") and delete whole binaries block from the iOSTarget specification block. This should be done because the cocoaPods plugin creates framework on it's own, and we should avoid duplication (see discussion). Instead of that block, add cocoapods specification. This part of the script should look like that:
iOSTarget("ios") {}
    version = "1.0.0"
    cocoapods {
        summary = "This is sample Summary"
        homepage = "Home URL"

        pod("AFNetworking", "~> 3.2.0")
    }
  1. Then, execute Gradle task podspec to generate podspec for your framework. This should be done inside of the /SharedCode/ directory, as the previous one. If the task is not presented, it means that the CocoaPods plugin was not applied correctly.
  2. When the podspec is ready, we can use it from the Xcode project. To do it, open the /native/KotlinIOS/ directory, and create Podfile there. I used these contents for is:
use_frameworks!

platform :ios, '9.0'

target 'KotlinIOS' do
    pod 'SharedCode', :path => '../../SharedCode'
end

The important part here is that the name corresponds to our framework name, and the relative path points on the place containing build.gradle.kts from the first step. After Podfile creation, install pods here using pod install from the terminal(CocoaPods should be installed).

  1. Now open generated KotlinIOS.xcworkspace with Xcode. There, one more thing should be fixed. At this moment the KotlinIOS project is set to search for frameworks only in /SharedCode/build/Xcode-frameworks/ directory, but CocoaPods won't put anything there. So, select KotlinIOS on the left panel, open Build Settings tab and find there Search Paths -> Framework Search Paths. Press + and add $(inherited) to the list, to make available frameworks that CocoaPods installed.
  2. Now, execute Build from the Xcode. After that, in your Kotlin IDE the AFNetworking package should become available. To import it, use import cocoapods.AFNetworking.*. For the first time it might need to invalidate Caches and Restart, to make it see this package correctly.

I hope this will help. Please comment if something is unclear in this instruction.

Jarrod answered 10/2, 2020 at 14:47 Comment(11)
I was missing only this point "/SharedCode/build/Xcode-frameworks/" "Great 👍 I compiled successfully and able to use shared library. Also I tried Get API through Afnetworking and its working perfectly. Thanks.Copperplate
I've followed your instruction and still import cocoapods is unresolved, code completition is not working. Is it working for you?Inoperative
For me, after doing everything, i've got error in xcode that it can't find gradlew inside SharedCode/build/xcode-frameworksInoperative
@Inoperative yes it is working fine for me.. may be you missing some step.Copperplate
@Copperplate i've finally got it working with help from kotlin slack. For me, the main requirement to make it work, was to convert build.gradle to build.gradle.kts in multiplatform module o_O. Then it works without any problemsInoperative
@Inoperative great 👍Copperplate
How to make code completion work? Everything builds correctly from Xcode and I can use the code written in iosMain source set, but all the ios platform.* and cocoapods.* imports are unresolved.Ringster
I want to use an xcFramework (DDMathParser) in my Kotlin project. I've searched a lot of pages and still can't find how to do it, the closest information is this one, but I still can't read a lot of information. Could you please teach me how to do it? Thank you in advance!Stokeontrent
Hi, @michaelma! I haven't worked a lot with KMM recently, but my guess is that you would like to try this instructions. It looks like the DDMathParser is available through CocoaPods. The only blocker I see here is that DDMathParser is written in Swift. If so, it won't work right now, as "Integration with the CocoaPods dependency manager is also supported with the same limitation – you cannot use pure Swift pods.". For details see youtrack.jetbrains.com/issue/KT-49521Jarrod
@ArtyomDegtyarev, thank you for your reply! I looked at the webpage you provided and unfortunately I still can't figure out how to do it. Are there any step-by-step tutorials in the internet? (DDMathParser has an Objective-C version)Stokeontrent
@michaelma, I'm looking at the github.com/davedelong/DDMathParser saying 99.7% Swift. This means that you won't be able to use it. If you still want to try, follow the instruction I mentioned before. It contains three main steps - CocoaPods installation, adding a pod() dependency and using import notation when the project is synced.Jarrod
B
1

Adding this answer because some users are wondering why IDE suggestions are not coming in case of IOS common code. The reason is that still the commonization of the IOS code is not done which means iosMain won't work it will compile but no show suggestions or import. To make it work as usual you have to specify a specific source set.

for example.

kotlin {
android()
iosX64()

cocoapods {
    // Configure fields required by CocoaPods.
    summary = "Kotlin Multiplatform Firebase login sample"
    homepage = "https://github.com/worstkiller/firebaseloginkmm"
    pod("FirebaseAuth")
    frameworkName = "sharedFramework"
}

sourceSets {
    val commonMain by getting {
        dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.coroutines}")
        }
    }
    val commonTest by getting {
        dependencies {
            implementation(kotlin("test-common"))
            implementation(kotlin("test-annotations-common"))
        }
    }
    val androidMain by getting {
        dependencies {
            implementation("com.google.firebase:firebase-auth:${Versions.firebase_auth_android}")
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutines}")
            implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.viewmodel}")
        }
    }
    val androidTest by getting {
        dependencies {
            implementation(kotlin("test-junit"))
            implementation("junit:junit:${Versions.junit}")
        }
    }

    val iosX64Main by getting
    val iosX64Test by getting

    configure(listOf(iosX64Main)) {
        dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:${Versions.coroutines_native}")
        }
    }
}

}

in the above code block, I have added the support for only iosX64 source sets which means it will work on machine only. You can similarly add support for iosArm64.

Here is an issue I have already raised if possible vote it to make it count.

https://youtrack.jetbrains.com/issue/KT-42319

Bradley answered 29/12, 2020 at 18:20 Comment(1)
Clarification: per a comment in that you track link, it looks like code completion becomes available only when your file is within a specific source set folder (e.g. iosArm64Main) vs the commonized one iosMain. Theoretically the code will still compile in iosMain, but it's hard to write because the IDE won't show code completion there and will have lots of red squigglies.Responsiveness

© 2022 - 2024 — McMap. All rights reserved.