Does the module where I declare an interface with ...
# multiplatform
c
Does the module where I declare an interface with a companion object have any impact on what is exported to Swift/ObjC? I have the following module structure: •
:kmp:shared
- This contains
ClassId
as shown in the thread •
:kmp:feature1
- This contains
AuthToken
as shown in the thread I can access
ClassIdCompanion
from my Swift code, but I don't see
AuthTokenCompanion
ClassId defined in
:kmp:shared
module - this is the one that is exported to Swift:
Copy code
interface ClassId {
    val value: Int
    fun isValid(): Boolean = value >= 0
    companion object {
        val Invalid = withValue(-1)
        fun withValue(value: Int): ClassId = ClassIdImpl(value)
    }
}

@JvmInline
private value class ClassIdImpl(override val value: Int) : ClassId
AuthToken defined in
:kmp:feature1
module - this is not exported to Swift; just the
implementation(projects.kmp.feature1)
dependency is declared
Copy code
interface AuthToken {
    val token: String
    companion object {
        fun of(token: String): AuthToken = AuthTokenImpl(token)
    }
}

@JvmInline
private value class AuthTokenImpl(override val token: String) : AuthToken
I can see AuthToken with a package prefix in my swift code but I cannot see the companion object. I can see
MypackageAuthToken
but I cannot see
MypackageAuthTokenCompanion
that allows me to create an instance.
j
It's likely to be some MypackageAuthToken.Companion.shared.<your method> or something like that, don't recall off the top of my head exactly; but the Xcode will offer it when you start typing
c
I thought I had tried that and I did not see the Companion being generated. I even went through the generated Swift header file and I did not find it there either. Right now I've changed my approach in order to avoid having to call this companion from Swift but I'm still interested in knowing how to achieve it.
For example I wonder if the
ObjCName
annotations would help?
I also see that only the
:kmp:shared
module has this snippet that configures the binaries. I don't have this snippet in any other multiplatform module that
:kmp:shared
depends on. Wonder if that has any impact:
Copy code
target.binaries.framework {
    baseName = "KMPShared"
}
j
Ah OK; then I guess it is probably stripped out as it is not called anywhere. To test if that's the case, call the function in the companion from some piece of code that you know is executed, and see if then it is included in the Swift header file. If yes - then try to find out how to make it not stripped out; no idea if there's annotation for that or something; for my project it was enough to declare an interface { val x: ClassIWantedExported }, but it is a bit hacky, and not sure if it helps in your case.
👍🏽 1
[Oh and to be clear - executed from the kmpshared]
d
If you want to export more than one module to iOS, you can use `export(project(":moduleName"))`: https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#export-dependencies-to-binaries
c
@Daniel Seither But is that necessary if I'm already depending on the other module in the
commonMain { dependencies {}}
block? Another way of asking the same question is, if I don't use
export(project(":moduleName"))
, will symbols present in
":moduleName"
not be visible to Swift?
d
Yes. Dependencies of the main module are not automatically exported to Objective-C/Swift, only the types from the dependencies that are used in any interfaces exported by the main module.
export(…)
changes this.
c
only the types from the dependencies that are used in any interfaces exported by the main module
This was the missing part of the puzzle. Thanks.