How to make dependency project visible for Ios app? - kotlin-multiplatform

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.

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)
}
}
...

Kotlin multiplatform project depending on another one with cocoapods

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
}
}

Kotlin Multiplatform Library: Unable to generate .framework for iOS

I am new to Android/KotlinMultiplatform , I am trying to create a library for iOS/Android using Kotlin Multiplatform.
When I run the command on terminal
./gradlew :shared:packForXcode
It succeeds but could not find a /build/xcode-frameworks folder inside the root folder.
Could anyone help me to find where it is going wrong...?
IntelliJ CE Version : 2020.2.3
My Gradle file Content:
plugins {
id("org.jetbrains.kotlin.multiplatform") version "1.4.10"
id("com.android.library")
id("kotlin-android-extensions")
"maven-publish"
}
repositories {
mavenCentral()
}
group "me.myname"
version "0.0.1"
kotlin {
targets {
android()
ios {
binaries {
framework {
baseName = "MyLib"
}
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9")
}
}
val androidMain by getting {
dependencies { }
}
val iosMain by getting {
dependencies { }
}
}
}
android {
compileSdkVersion(29)
defaultConfig {
minSdkVersion(24)
targetSdkVersion(29)
versionCode = 1
versionName = "1.0"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
}
val packForXcode by tasks.creating(Sync::class) {
val targetDir = File(buildDir, "xcode-frameworks")
/// selecting the right configuration for the iOS
/// framework depending on the environment
/// variables set by Xcode build
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val sdkName: String? = System.getenv("SDK_NAME")
val isiOSDevice = sdkName.orEmpty().startsWith("iphoneos")
val framework = kotlin.targets
.getByName<KotlinNativeTarget>(
if(isiOSDevice) {
"iosArm64"
} else {
"iosX64"
}
)
.binaries.getFramework(mode)
inputs.property("mode", mode)
dependsOn(framework.linkTask)
from({ framework.outputDirectory })
into(targetDir)
println("Build Folder => $targetDir")
/// generate a helpful ./gradlew wrapper with embedded Java path
doLast {
val gradlew = File(targetDir, "gradlew")
gradlew.writeText("#!/bin/bash\n"
+ "export 'JAVA_HOME=${System.getProperty("java.home")}'\n"
+ "cd '${rootProject.rootDir}'\n"
+ "./gradlew \$#\n")
gradlew.setExecutable(true)
}
}
tasks.build.dependsOn("packForXCode")
UPDATE
Project Created using IntelliJ IDEA, as below screenshot:
My project structure looks like below:
I've only been able to see the template of your screenshot by using
IntelliJ 2020.2.3 Ultimate
This template doesn't have the packForXcode task set by default, so you would have put it by hands I suppose.
Anyway, with a cleaned project, if you run it, you could have the debug framework in the build folder where you want to have it.
You should have, of course, at least one source (Greeting.kt) file like the one I've shown you in my pic.
I suggest you to look deep at the documentation starting from here and here.
If I remember correctly, this task is not designed to be executed manually. It should be triggered as a part of the Xcode project build, see in the documentation. Please try to follow the steps from the documentation, and see if the framework connects and works fine from Xcode.

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