Kotlin multiplatform project depending on another one with cocoapods - kotlin-multiplatform

I have a kotlin multipltform library which has several cocoapods
cocoapods {
....
pod("gRPC/GRPCCore", grpcVersion)
pod("gRPC-ProtoRPC", grpcVersion)
pod("Protobuf", "3.15.8")
// etc
}
I published this library to artifactory (maven) and the ios target contains all the klib's for the cinterop'ed pods.
I have a second Kotlin Multiplatform Library where I wish to consume the previous "core" library.
iOSTarget("ios") {
binaries {
framework {
baseName = "SecondSharedLib"
export("first.shared.lib:1.0.0")
xcf.add(this)
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
api("first.shared.lib:1.0.0")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
val androidMain by getting {
dependencies {
}
}
val androidTest by getting {
dependencies {
implementation("junit:junit:4.13.2")
}
}
val iosMain by getting {
dependencies {
}
}
val iosTest by getting
}
When linking ios however the pod modules are not found.
ex: ld: framework not found gRPC_ProtoRPC
I also tried redeclaring the pods to no avail.
Is what I am trying to do even possible? does anyone have any suggestions?
Note: I am not an iOS developer so please be harsh if my understanding is off

For anyone dealing with a nested multiplatform library where the base library relies on the cocoapods plugin, I had to link all the frameworks via the linker opts as well as redefine all the cocoapods so that the frameworks would be available for linking.

have you tried below code instead when referencing another KMM project? Below code snippet is from Kotlin's documentation
kotlin {
sourceSets["commonMain"].dependencies {
implementation(project(":some-other-multiplatform-module"))
}
sourceSets["androidMain"].dependencies {
//platform part of :some-other-multiplatform-module will be added automatically
}
}

Related

Can't generate arm64 simulator with KMM

TL;DR Can't run Xcode project with KMM package on simulator on M1 (Max) MacBook.
I have tried to create a simple KMM project from the official guide where I want to import the module into my project in Xcode as a swiftpackage. This is where I found Multiplatform-swiftpackage.
I have managed to get the package over to my project, and I am able to run it on my phone, but I can't run it on the simulator as it seems to not build arm64 simulator which are very much present in the build.gradle.kts. Which leads to this error in Xcode:
ld: warning: ignoring file /Users/x/Library/Developer/Xcode/DerivedData/Urge-enlioljftsmplubupdnskjmixphi/Build/Products/Debug-iphonesimulator/UrgeNetwork.framework/UrgeNetwork, building for iOS Simulator-arm64 but attempting to link with file built for iOS Simulator-x86_64. I can't just exclude arm64 from my project as I have other packages not building for x86_64
I had friend try the same with his project and it build a combined x86_64 and arm simulator package. Then he tried 2 days later and it stopped generating it.
The simulator works when I run it from Android Studio, so it's probably the package. I can't see any other solutions to get the package to run via SPM in Xcode, so open for alternative solutions.
Any hints is greatly appreciated.
build.gradle.kts
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
plugins {
kotlin("multiplatform")
id("com.android.library")
kotlin("plugin.serialization") version "1.6.21"
id("com.chromaticnoise.multiplatform-swiftpackage") version "2.0.3"
}
val ktorVersion = "2.0.2"
kotlin {
android()
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "UrgeNetwork"
}
}
multiplatformSwiftPackage {
swiftToolsVersion("5.5")
targetPlatforms {
iOS { v("15") }
}
outputDirectory(File(rootDir, "/"))
}
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2")
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
val androidMain by getting {
dependencies {
implementation("io.ktor:ktor-client-android:$ktorVersion")
}
}
val androidTest by getting
val iosX64Main by getting
val iosArm64Main by getting
val iosSimulatorArm64Main by getting
val iosMain by creating {
dependencies {
implementation("io.ktor:ktor-client-darwin:$ktorVersion")
}
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
}
val iosX64Test by getting
val iosArm64Test by getting
val iosSimulatorArm64Test by getting
val iosTest by creating {
dependsOn(commonTest)
iosX64Test.dependsOn(this)
iosArm64Test.dependsOn(this)
iosSimulatorArm64Test.dependsOn(this)
}
}
}
android {
compileSdk = 32
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdk = 29
targetSdk = 32
}
}
kotlin.targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget::class.java) {
binaries.all {
binaryOptions["memoryModel"] = "experimental"
}
}

Failing to generate libraryname.xcframework in kotlin multiplatform mobile (KMM)

I was trying to generate the XCFramework with Kotlin 1.5.31 containing the targets for iOSArm64 and iOSX64 .
With the below build.gradle.kt , it generates a FatFrameworks . I’m failing to generate XCFrameworks .
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
kotlin {
val xcFramework = XCFramework(libName)
android()
ios {
binaries.framework(libName) {
xcFramework.add(this)
}
}
sourceSets {
val commonMain by getting
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val androidMain by getting {
dependencies {
implementation("com.google.android.material:material:1.2.1")
}
}
val androidTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("junit:junit:4.13")
}
}
val iosMain by getting
val iosTest by getting
}
}
And also I have included the tasks in build.gradle.kts :
tasks {
register(“buildDebugXCFramework”)
register(“buildReleaseXCFramework”)
register(“publishDevFramework”)
register(“publishFramework”)
}
This is the output I got : fatframeowrks generated but not the libraryname.xcframeworks
If Any suggestions to generate XCFrameworks with targets iOSArm64 and iOSX64 ? , it would be helpful , Thank you .
I think that following the documentation might help here.
Please set library name by the baseName option and build the final XCFramework by running assembleXCFramework Gradle task.
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
kotlin {
val xcFramework = XCFramework()
android()
ios {
binaries.framework() {
baseName = "libName"
xcFramework.add(this)
}
}
...

How to make dependency project visible for Ios app?

I have a kotlin multiplatform project MusicFeature with targets for ios, android, common with the following build.gradle
sourceSets {
commonMain {
dependencies {
implementation(project(":ProjectUtils"))
}
}
androidMain {
}
iosMain {
}
}
ProjectUtils is also a multiplatform project.
There's no troubles in using ProjectUtils code from MusicFeature. But when I export MusicFeature as a framework for iOS, I don't have access to classes from ProjectUtils.
I guess you are looking for transitiveExport = true for your framework.
binaries {
framework {
export project(':dependency')
// Export transitively.
transitiveExport = true
}
}
You can find more reference here in export dependencies to binaries.

Kotlin/native cinterop build problem with gradle

I'm experimenting with Kotlin native and iOS. I tried to use the example at raywenderlich as a starting point. This example is a bit old , so I have updated the code to fit the Kotlin multiplatform 1.3.61. I'm using AppCode to build the code.
I'm struggling with the Kotlin DSL gradle file ( build.gradle.kts) , the example is using build.gradle :
plugins {
id "org.jetbrains.kotlin.platform.native" version "1.3.0"
}
components.main {
def productsDir = new File("").absolutePath
targets = ['ios_arm64', 'ios_x64']
outputKinds = [EXECUTABLE]
allTargets {
linkerOpts '-rpath', '#executable_path/Frameworks'
linkerOpts "-F${productsDir}"
}
dependencies {
cinterop('AFNetworking'){
packageName 'com.afnetworking'
compilerOpts "-F${productsDir}"
linkerOpts "-F${productsDir}"
includeDirs{
allHeaders "${productsDir}/AFNetworking.framework/Headers"
}
}
}
}
task copyExecutable() {
doLast {
def srcFile = tasks['compileDebugIos_x64KotlinNative'].outputFile
def targetDir = getProperty("konan.configuration.build.dir")
copy {
from srcFile.parent
into targetDir
}
}
}
I have tried to translate this into the build.gradle.kts file of my own :
plugins {
kotlin("multiplatform") version "1.3.61"
kotlin("xcode-compat") version "0.2.5"
}
repositories {
mavenCentral()
}
kotlin {
val productsDir = "/Users/trond/Desktop/native_meteor/native_meteor/"
iosX64("ios")
{
compilations.getByName("main")
{
val myInterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/afnetworking.def"))
packageName ("com.afnetworking")
compilerOpts ("-F${productsDir}")
// linkerOpts ("-F${productsDir}")
// 3
includeDirs{
allHeaders ("${productsDir}/AFNetworking.framework/Headers")
}
}
}
}
xcode {
setupApplication("native_meteor")
}
}
From what I can see the cinterops tool is doing it's job and is creating a klib file and a afnetworing.kt ( build/classes/kotlin/ios/main/..... )
But the I'm not able to use the library AFNetworking! I try to add the import directive in the ViewController.kt file :
import com.afnetworking.*
But this is not recognized. This results in that the project is not building :
> Task :native_meteor:compileKotlinNative_meteor FAILED
e: /Users/trond/Desktop/native_meteor/native_meteor/src/native_meteorMain/kotlin/ViewController.kt: (15, 8): Unresolved reference: com
e: /Users/trond/Desktop/native_meteor/native_meteor/src/native_meteorMain/kotlin/ViewController.kt: (37, 23): Unresolved reference: AFHTTPSessionManager
e: /Users/trond/Desktop/native_meteor/native_meteor/src/native_meteorMain/kotlin/ViewController.kt: (40, 38): Unresolved reference: AFJSONResponseSerializer
Anyone that can shed some light on this ?
Maybe it will make sense to check the contents of your result .klib to make sure you use the correct package name. It can be done using ~/.konan/kotlin-native-macos-1.3.61/bin/klib CLI tool. Also, I would recommend you to take a look at this sample from the Kotlin/Native Github, it also utilizes AFNetworking and uses the latest compiler version.
Thank you for pointing me in that direction. I investigated the .klib file, and I discovered that it contained the package that I expected. I then took a look at the Gradle sourcsets that I had in the Gradle pane in Appcode. Here I discovered that the .klib library was defined under "iosMain" and not "native_metorMain". I then found out that the line iosX64("ios") should be iosX64("meteor_main").
After that I got an error : "ld: framework not found AFNetworking" when I tried to compile in XCode. I then added -F{full path to framework} for the linkerOpts ( linkerOpts= -F{full path to framwork} -framework AFNetworking ) in the afnetworking.def file.
Now the project builds successfully.

Ktor and kotlinx dependencies not found when building iOS framework

I am trying to include support for ktor and kotlinx (serialization and coroutines to be exact) to my Kotlin/Native project. All libraries work on the Android version of the project, but when I try to compile the Xcode project, I receive errors stating that the kotlinx.serialization and kotlinx.coroutines libraries could not be found:
src/commonMain/kotlin/.../.kt:4:16: error: unresolved reference: coroutines
import kotlinx.coroutines.CoroutineDispatcher
^
src/commonMain/kotlin/.../.kt:5:16: error: unresolved reference: serialization
import kotlinx.serialization.json.JSON
Here is my gradle file for my project:
plugins {
id 'kotlin-multiplatform' version '1.3.11'
id 'kotlinx-serialization' version '1.3.0'
}
ext {
ktor_version = '1.0.1'
kotlinx_version = '1.1.0'
}
repositories {
maven { url "https://kotlin.bintray.com/ktor" }
maven { url "https://kotlin.bintray.com/kotlinx" }
google()
jcenter()
mavenCentral()
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android-extensions'
configurations {
compilerPlugin
}
android {
compileSdkVersion 27
defaultConfig {
applicationId "org.jetbrains.kotlin.mpp_app_android"
minSdkVersion 15
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
}
kotlin {
targets {
fromPreset(presets.android, 'android')
// This preset is for iPhone emulator
// Switch here to presets.iosArm64 (or iosArm32) to build library for iPhone device
fromPreset(presets.iosX64, 'ios') {
compilations.main.outputKinds('FRAMEWORK')
}
}
sourceSets {
commonMain {
dependencies {
implementation 'commons-codec:commons-codec:1.10'
implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
implementation("io.ktor:ktor-client:$ktor_version")
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$kotlinx_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:0.9.1"
}
}
commonTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test-common'
implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
}
}
androidMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib'
implementation("io.ktor:ktor-client-android:$ktor_version")
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinx_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1"
}
}
androidTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
}
}
iosMain {
dependencies {
implementation("io.ktor:ktor-client-ios:$ktor_version")
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$kotlinx_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.9.1"
}
}
iosTest {
}
}
}
// This task attaches native framework built from ios module to Xcode project
// (see iosApp directory). Don't run this task directly,
// Xcode runs this task itself during its build process.
// Before opening the project from iosApp directory in Xcode,
// make sure all Gradle infrastructure exists (gradle.wrapper, gradlew).
task copyFramework {
def buildType = project.findProperty("kotlin.build.type") ?: "DEBUG"
def target = project.findProperty("kotlin.target") ?: "ios"
dependsOn "link${buildType.toLowerCase().capitalize()}Framework${target.capitalize()}"
doLast {
def srcFile = kotlin.targets."$target".compilations.main.getBinary("FRAMEWORK", buildType)
def targetDir = getProperty("configuration.build.dir")
copy {
from srcFile.parent
into targetDir
include 'app.framework/**'
include 'app.framework.dSYM'
}
}
}
Any help would be greatly appreciated, thanks!
Make sure enableFeaturePreview("GRADLE_METADATA") is in the settings.gradle file. Once I added this line, I was able to compile from Xcode.
I'm having this problem as well. And it suddenly appeared on a project that I've been working on for months. I do have enableFeaturePreview('GRADLE_METADATA') set in settings.gradle. What could be going on? This is really frustrating; my project is suddenly at a standstill for no apparent reason.

Resources