FutureMind/koru

Wrappers not generated with KSP when using embedAndSignAppleFrameworkForXcode

micHar opened this issue · 10 comments

This is an issue that got mixed with #49.

User @yamakentoc reports that this gradle config doesn't result in wrapper classes being generated.

// HogeHogeHoge/shared/build.gradle.kts
// kotlin version: 1.7,0

val ktorVersion = "2.0.1"
val kotlinCoroutineVersion = "1.6.3"

plugins {
    kotlin("multiplatform")
    id("com.android.library")
    id("com.google.devtools.ksp") version "1.7.0-1.0.6"
    id("com.futuremind.koru").version("0.11.0")
    kotlin("plugin.serialization")
}

kotlin {
    android()

    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "HogeHogeHoge"
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                //Coroutines
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutineVersion-native-mt")
                //Network
                implementation("io.ktor:ktor-client-core:$ktorVersion")
                implementation("io.ktor:ktor-client-serialization:$ktorVersion")
                // JSON Serialization
                implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
                implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
                // client mock
                implementation("io.ktor:ktor-client-mock:$ktorVersion")
                // koru
                implementation("com.futuremind:koru:0.11.1")
                // firebase
                implementation("dev.gitlive:firebase-auth:1.6.1")
            }
        }

        val androidMain by getting {
            dependencies {
                //Network
                implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }

        val iosX64Main by getting
        val iosArm64Main by getting
        val iosSimulatorArm64Main by getting
        val iosMain by creating {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
            iosSimulatorArm64Main.dependsOn(this)
            dependencies {
                //Network
                implementation("io.ktor:ktor-client-darwin:$ktorVersion")
            }
        }
    }
}

android {
    compileSdk = 31
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 27
        targetSdk = 31
    }
}

koru {
    nativeSourceSetNames = listOf("iosMain")
}

@yamakentoc I'm gonna need more details.

  1. Can you show an example class that you annotate in your commonMain?
  2. What gradle command do you use to build? The shared module and the ios framework.
  3. After running the gradle command, do you have anything in build/generated/ksp directory?

@micHar
< 1. Can you show an example class that you annotate in your commonMain?

OK. This is the code that mimics the real code.
This code was not generated wrapper too.

// HogeHogeHoge/shared/src/commonMain/hogehogehoge/Sample.kt

import com.futuremind.koru.ToNativeClass
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*


@ToNativeClass(name = "LoadTaskUseCaseIos")
class LoadTaskUseCase {
    private val taskRepository = TaskRepository()
    operator fun invoke() : Flow<TaskList> = taskRepository.getAllTask()
}

class TaskRepository {
    fun getAllTask(): Flow<TaskList> {
        return flow { emit(date) }.flowOn(Dispatchers.Default)
    }
    companion object {
        val date = TaskList(
            mapOf(
                1L to Task(1, "sample1", "detail", false),
                2L to Task(2, "sample2", "detail", true),
                3L to Task(3, "sample3", "detail", false),
            )
        )
    }
}

data class TaskList(val value: Map<Long, Task>) {
    companion object {
        fun empty() = TaskList(emptyMap())
    }
}

data class Task(val id: Long, val title: String, val detail: String, val isCompleted: Boolean)

@micHar

What gradle command do you use to build? The shared module and the ios framework.

I don't know much about build. So, I will check with other member.
But I'm sure use Android Studio to build.

After running the gradle command, do you have anything in build/generated/ksp directory?

ksp folder was not generated.

スクリーンショット 2022-08-11 1 14 21

I assume that kapt working and ksp not for your setup has something to do with the gradle task that you use. In the example repo I build xcframework with gradle assembleXCFramework and it seems to pick up the ksp step. gradle shared:build or gradle shared:assemble should be fine, too.

The code looks fine to me. Not sure how operator fun will behave, but if kapt works, ksp will probably, too. Will add tests for that, too.

@micHar
Hmm... I tried various things, but it didn't work.😢
So for now I will use v0.10.0 with kapt.

But would you please tell me how do you build the ios framework for your ios app from kotlin code?

@micHar
I'm sorry. I misunderstood.
wrapper class was generated when build with Xcode !!! 🙌

when I used kapt(v0.10.0), the wrapper class was generated as soon as build with Android Studio.
So thought ksp would also generate wrapper class soon.

Sorry for my misunderstanding🙇‍♂️

gradlew runs when build with Xcode, so it may be affected
スクリーンショット 2022-08-12 1 05 44

@yamakentoc thank you for working with me on this. So I checked embedAndSignAppleFrameworkForXcode and for me it seems to work fine.

Can you please check if when you build in xcode and this "Run Script" phase invoked the embedAndSignAppleFrameworkForXcode what are the gradle commands run?

You should see shared:kspCommonMainKotlinMetadata and after that thebuild/generated/ksp folder should be created with all the classes.

Zrzut ekranu 2022-08-12 o 13 33 28

Okay, now I misunderstood your comment. So it seems like everything is fine, I'm glad.

For anyone that wanders here - the kspCommonMainKotlinMetadata should be run during compilation of the commonMain module. If anyone sees a different behavior, please open another issue.