This project is a playground demonstrating how to import Swift code into a Kotlin Multiplatform (KMP) project using the spmForKMP plugin.
It provides practical examples of Swift-Kotlin interoperability, specifically for iOS testing and development.
These examples are working with any other way to import Swift Code through cinterop.
The project includes several test files, each focusing on a specific aspect of Swift-Kotlin integration:
1. Basic Interoperability (Basic.swift & BasicTest.kt)
- Class Instantiation: Creating Swift class instances from Kotlin.
- Methods: Calling instance, static, and class methods.
- Properties: Accessing and modifying read-only and mutable properties.
- Objective-C Name Overrides: Using Swift methods with custom
@objcnames. - Data Types: Passing standard types like
NSNumberand handling optional values (nil).
2. Swift Concurrency (Concurrency.swift & ConcurrencyTest.kt)
- Async/Await: Calling Swift
asyncmethods from Kotlin. - Coroutines Integration: Wrapping callback-based Swift APIs into Kotlin
suspendfunctions usingsuspendCoroutine. - Error Handling: Managing errors returned via Swift callbacks.
3. Enums and Type Safety (Enums.swift & EnumTest.kt)
- Swift Enums: Importing and using Swift enums in Kotlin.
- Type-Safe Enums: Demonstrating the use of
strictEnumsconfiguration from thespmforkmpplugin to make imported enums type-safe in Kotlin.
4. Error Handling and Exceptions (Throws.swift, ThrowTest.kt)
- Handling Throws: Intercepting Swift errors (
throws) in Kotlin.
5. Wrapping Swift Native APIs (ObjectWrapper.swift & ObjectWrapperTest.kt)
- Pure Swift Types: Handling Swift structs and classes that aren't directly compatible with Objective-C/Kotlin.
- Bridging Pattern: Demonstrating how to expose Swift-only APIs (like third-party libraries) through Objective-C compatible interfaces.
The project includes a utility function, executeWithErrorHandling, designed to simplify error management when calling Swift methods that follow the Objective-C error pointer pattern.
- Idiomatic Kotlin: It transforms the lower-level Objective-C
NSError**pointer pattern into idiomatic Kotlin exceptions (SwiftException). - Reduces Boilerplate: You don't need to manually manage
memScoped, allocate an error pointer, and check if it'snullevery time you call a throwing Swift function. - Type-Safe Exceptions: It provides a consistent
SwiftExceptiontype that wraps the underlyingNSError, giving you easy access to itslocalizedDescriptionand other properties. - Better Debugging: Instead of having to inspect an error pointer after each call, you can use standard Kotlin
try-catchblocks, making the code cleaner and easier to maintain.
Example usage:
val result = executeWithErrorHandling { errorPtr ->
swiftInstance.throwingMethod(errorPtr)
}The project uses the spmforkmp plugin, configured in shared/build.gradle.kts. Key configuration highlights include:
- Swift Package Configuration: Defining the Swift version and name for the generated cinterop.
toolsVersion = "6.0": Specifies the Swift tools version to use. This enables advanced features like typed throws and strict concurrency.
- Compiler Arguments: A requirement for iOS simulator testing (see Concurrency Support in KMP iOS Test):
freeCompilerArgs += listOf("-Xoverride-konan-properties=osVersionMin.ios_simulator_arm64=16.0")
- Strict Enums: Specifying which Swift enums should be treated as type-safe enums in Kotlin (see Strict Enums Documentation):
strictEnums = listOf("EnumData", "EnumError", "ConcurrencyError", "ThrowError")
To run the tests, you will need a Mac with Xcode and Kotlin Multiplatform setup.
- Clone the repository.
- Open the project in IntelliJ IDEA or Android Studio.
- Run the iOS tests from the
sharedmodule.
If you have any feedback, encounter issues, or want to request new examples, please feel free to open an issue or a discussion on the GitHub repository.