Hi everyone, I'm working on a multiplatform (iOS/...
# multiplatform
m
Hi everyone, I'm working on a multiplatform (iOS/Android) library for Firebase Analytics. In principle everything works fine, but the resulting iOS framework is quite large (30MB). It looks like kotlin generates an umbrella framework which includes all the other framework dependencies I have defined via
linkerOpts
and
compilerOpts
in my
cinterop.def
file (FirebaseCore, nanobp etc.) This also leads to "duplicate symbol" issues when the framework is embedded in our app, since we are using cocoapods which pulls in transitive dependencies that are already embedded in our analytics library. Is there any cinterop flag or gradle option to tell kotlin not to embed subframeworks?
i
Hi! Do you use the
org.jetbrains.kotlin.native.cocoapods
plugin or configure cinterop manually? Could you also provide your buildscript? It would help to find a correct root cause for your problem.
m
Hey! We are using Carthage to fetch our dependencies, which means that we specify cinterop manually. I cant show you the full buildscript, but the relevant parts should be: build.gradle.kts:
Copy code
kotlin {
    data class IosTarget(
        val name: String, val preset: String, val id: String,
        val embedBitcode: Framework.BitcodeEmbeddingMode
    )

    val iosTargets = listOf(
        IosTarget("ios", "iosArm64", "ios-arm64", Framework.BitcodeEmbeddingMode.BITCODE),
        IosTarget("iosSim", "iosX64", "ios-x64", Framework.BitcodeEmbeddingMode.DISABLE)
    )

    for ((targetName, presetName, id, bitcodeEmbeddingMode) in iosTargets) {
        targetFromPreset(presets.getByName(presetName), targetName) {
            (this as KotlinNativeTarget).run {
                compilations {
                    val main by getting {
                        val carthageBuildDir = "$projectDir/Carthage/Build/iOS"
                        cinterops(Action {
                            val firebaseAnalytics by creating {
                                defFile("src/iosMain/cinterop/firebaseAnalytics.def")
                                includeDirs.allHeaders("$carthageBuildDir/FirebaseAnalytics.framework/Headers")
                            }
                        })

                        binaries {
                            framework {
                                baseName = "OurFramework"
                                embedBitcode(bitcodeEmbeddingMode)
                            }
                        }
                    }
                }
            }
        }
    }
}
Build Framework Task:
Copy code
tasks.register("buildUniversalFrameworkRelease", FatFrameworkTask::class.java) {
    baseName = "OurFramework"
    from(
        (kotlin.targets.getByName("ios") as KotlinNativeTarget).binaries.getFramework(NativeBuildType.RELEASE),
        (kotlin.targets.getByName("iosSim") as KotlinNativeTarget).binaries.getFramework(NativeBuildType.RELEASE)
    )
    destinationDir = buildDir.resolve("xcode-frameworks")
}
cinterop:
Copy code
package = framework.FirebaseAnalytics
language = Objective-C
headers = FirebaseAnalytics.h

compilerOpts = -F ./Carthage/Build/iOS -framework FIRAnalyticsConnector -framework FirebaseCore -framework GoogleDataTransportCCTSupport -framework nanopb -framework Firebase -framework FirebaseCoreDiagnostics -framework GoogleAppMeasurement -framework GoogleUtilities -framework FirebaseAnalytics -framework FirebaseInstallations -framework GoogleDataTransport -framework PromisesObjC -lsqlite3 -framework StoreKit

linkerOpts = -ObjC -F ./Carthage/Build/iOS -framework FIRAnalyticsConnector -framework FirebaseCore -framework GoogleDataTransportCCTSupport -framework nanopb -framework FirebaseCoreDiagnostics -framework GoogleAppMeasurement -framework GoogleUtilities -framework FirebaseAnalytics -framework FirebaseInstallations -framework GoogleDataTransport -framework PromisesObjC -lsqlite3 -framework StoreKit
And right after sending the above message I had the idea to check if the frameworks downloaded by carthage are static or dynamic. And they are indeed
ar archives
which means that they are static libraries 🙄
Mystery solved. Sorry for bothering you...
i
No problem 🙂 BTW if you need, you can build a static K/N framework too. To do this, specify
isStatic = true
in the
binaries.framework
block.
🙏 1