KMM-developed Xcode framework with C-Interoped static library fails with 'unrecognized selector'

Hello everyone,

My team is currently developing a multiplatform library targeting Android and iOS platforms. For this we’re using Android Studio and KMM plugin.

The library performs, among other things, some cryptographic operations. We have put these in per-platform classes using expect/actual mechanism. For Android, these classes take the necessary crypto implementations from SpongyCastle. For iOS, things get a little tricky, since the platform.CoreCrypto package does not contain necessary functions; therefore, we settled on including statically linked OpenSSL library into the project, using Cinterop mechanism.

Unit tests on iOS simulator run without problems in Android Studio. Unfortunately, the framework built with packForXcode task doesn’t work well. The iOS app built with the framework crashes in runtime with enigmatic description:

‘NSInvalidArgumentException’ reason: '-[MyLibrary_kobjcc1 update]: unrecognized selector sent to instance

Call stack isn’t helpful since the only thing it contains are some memory addresses.

We have been searching for a solution for quite a bit of time and it seems that our c-interoped openssl library might be the culprit.

This is the content of our .def file:

headers = openssl/bio.h openssl/ssl.h openssl/err.h openssl/evp.h openssl/ec.h openssl/bn.h
headerFilter = openssl/*
staticLibraries = libcrypto.a
libraryPaths.ios_arm64 = /Users/bl90/AndroidStudioProjects/myLibrary/src/nativeInterop/cinterop/openssl/iPhoneOS13.2-arm64.sdk/lib
compilerOpts.ios_arm64 = -/Users/bl90/AndroidStudioProjects/myLibrary/src/nativeInterop/cinterop/openssl/iPhoneOS13.2-arm64.sdk/include
libraryPaths.ios_x64 = /Users/bl90/AndroidStudioProjects/myLibrary/src/nativeInterop/cinterop/openssl/iPhoneSimulator13.2-x86_64.sdk/lib
compilerOpts.ios_x64 = -I/Users/bl90/AndroidStudioProjects/myLibrary/src/nativeInterop/cinterop/openssl/iPhoneSimulator13.2-x86_64.sdk/include

I didn’t set any additional linker flags since the libcrypto.a is to be statically linked. We did however try linking without ‘staticLibraries/libraryPaths’ part and using -L/path_to_lib_directory and -lcrypto linker flags, to no avail.

Relevant parts from build.gradle.kts:

kotlin {
    android {
        // android specific stuff
    }
    ios {
        binaries {
            framework {
                baseName = "myLibrary"
            }
        }
        compilations.getByName("main") {
            val openSSL by cinterops.creating {
                // def file
                // default path src/nativeInterop/cinterop/<interop-name>
                defFile(project.file("src/nativeInterop/cinterop/openssl/openssl.def"))

                // packageName for kotlin API
                packageName("org.openssl")
            }
        }
    }
}

val packForXcode by tasks.creating(Sync::class) {
    group = "build"
    val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
    val sdkName = System.getenv("SDK_NAME") ?: "iphoneos14.4"//"iphonesimulator"
    val targetName = "ios" + if (sdkName.startsWith("iphoneos")) "Arm64" else "X64"
    val framework = kotlin.targets.getByName<KotlinNativeTarget>(targetName).binaries.getFramework(mode)
    inputs.property("mode", mode)
    dependsOn(framework.linkTask)
    val targetDir = File(buildDir, "xcode-frameworks")
    from({ framework.outputDirectory })
    into(targetDir)
}

I’d appreciate any hints of what might be wrong, and maybe how to get Xcode to give more useful feedback (debug symbols?)

All the best,
Bart

After more dubugging, problem turned out to be unrelated to the linked c-library. Another platform-specific component, called between the c-library operations, had some sort of an issue.