Kotlin Multiplatform (KMP) is a promising approach that enables developers to share business logic across multiple platforms, including iOS and Android, while allowing platform-specific implementations for platform-dependent functionalities. This article demonstrates how to integrate KMP with iOS, showcasing how to expose Kotlin interfaces to Swift, implement these interfaces in Swift, and leverage them in a Swift UI application.
The focus here is to explore an alternative approach that avoids the complexity of expect/actual patterns. Instead, this method streamlines the integration by minimizing the interaction with platform APIs not exposed in KMP.
We’ll build a sample Swift UI application that encrypts, stores, and decrypts data. The business logic resides in Kotlin, while platform-specific functionality is implemented in Swift.
Setting Up the Kotlin Mutliplatform Library in Android Studio
To begin, you’ll need to create a KMP library using Android Studio. For reference, you can use the which accepts 2 interfaces as dependencies:
package io.github.arskov
class MultiplatformService(
private val cryptoProvider: CryptoProvider,
private val storeProvider: StoreProvider
) {
@Throws(StoreException::class, EncryptionException::class)
fun storeData(data: PlainData, encryptionKey: ByteArray?) {
if (!data.encrypted && encryptionKey != null) {
val encryptedData =
cryptoProvider.encrypt(op = EncryptOp.ENCRYPT, key = encryptionKey, data = data.content)
val encryptedPlainData =
PlainData(id = data.id, encrypted = true, updated = 0L, content = encryptedData)
storeProvider.store(encryptedPlainData)
} else {
storeProvider.store(data)
}
}
@Throws(StoreException::class, EncryptionException::class)
fun loadData(id: Long, encryptionKey: ByteArray?): PlainData {
val data = storeProvider.load(id)
if (data.encrypted && encryptionKey != null) {
val decryptedData = cryptoProvider.encrypt(op = EncryptOp.DECRYPT, key = encryptionKey, data = data.content)
return PlainData(id = data.id, encrypted = false, updated = 0L, content = decryptedData)
}
return data
}
}
The main idea of the library is accepting the data, perform a provided crypto operation, and store the value in the provided store.
For simplicity, we also have a default in-memory implementation of the StoreProvider, but this could also be implemented on the Swift side. See below.
Now what we want to do is to integrate this MultiplatformService into Swift UI sample application. In Swift when we construct the MultiplatformService we provide a Swift implementation of the CryptoProvider and the StoreProvider.
Building the XCFramework
An XCFramework is a container that supports multiple architectures, allowing your library to work seamlessly on different iOS devices and simulators.
Steps to Build the XCFramework:
Set the Framework Name: Ensure the framework has a clear and unique name, likeKmpLib.
Specify Target Platforms: Define architectures such asiosArm64for physical devices andiosSimulatorArm64for simulators.
Run the Build Task:
Use./gradlew taskto see what are the possible assemble tasks you have.
Use the Gradle task./gradlew assembleKmpLibXCFrameworkto build the XCFramework. The output will be located in thekmp-lib/library/build/XCFrameworks/{debug|release}/directory. Gradle generates assembleXCFramework task if you give your framework a name.
Sample Swift UI Application
The Swift UI application demonstrates how to utilize the KMP library for secure data management. Here's a high-level overview of its functionality:
Encryption: Data is encrypted using theCryptoProviderinterface implemented in Swift.
Storage: Encrypted data is stored using theInMemoryStoreProvideror a custom implementation.
Decryption: The app retrieves and decrypts the data for display.
Example Workflow:
- Input sample data into the app.
- Encrypt and store the data using Kotlin’s business logic.
- Retrieve and decrypt the data, showcasing the seamless interplay between Swift and KMP.
This integration allows Swift to access Kotlin’s business logic.
Implementing KMP Interfaces in Swift
In our example, we’ve imported the KmpLib framework and now we are going to implement its exposed interfaces in Swift. The key interfaces are:
. In this case, we use the defaultInMemoryStoreProviderfrom KMP.- Example of the file contains main UI logic:
- Set the password for the content encryption
- Set the text
- Button to encrypt and store the content
- Controls to display the encrypted text in HEX
- Button to load and decrypt the content
CODEButton(action: {
let service = ServiceLocator.sharedInstance
.getMultiplatformService()
let store = ServiceLocator.sharedInstance.getStoreProvider()
let plainData = PlainData(
id: 1,
encrypted: false,
updated: 0,
content: self.plainDataText.toKotlinByteArray()
)
do {
try service.storeData(
data: plainData,
encryptionKey: encryptionKey.toKotlinByteArray())
let storedData = try store.load(id: 1)
self.encryptedDataText = storedData.content.toHexString()
} catch {
print("error: \(error)")
}
})
Important detail, that we also crated some
Conclusion
This article provided a step-by-step guide on leveraging Kotlin Multiplatform libraries for iOS development. By following this alternative approach, you can efficiently share business logic across platforms without delving into the complexities of
expect/actualAPIs. The sample Swift UI application highlights the practical integration of KMP interfaces in Swift, showcasing the potential for streamlined cross-platform development.
For further exploration, check out the complete example on GitHub.
↗ Original-Artikel auf dev.to lesenVollständiger Original-BerichtAusführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
SOCIAL SHARE CARD GENERATOR