droidcon Italy 2022 - KMM Survival Guide: how to tackle everyday struggles between Kotlin and Swift
Slides used during my talk at droidcon Italy 2022 about how to use Kotlin Multiplatform Mobile, what issues are currently unsolved, and how to work around them!
to do. Android module: you see no difference and just use the shared module code iOS project: using Kotlin Native, the code is compiled into an AppleFramework like it was written in Objective-C. Then you can just use it in the same way as when you import an iOS dependency. How does it work?
return if(isSuccess) { SuccessKMMIntResult(Random.nextInt(until = 10)) } else { ErrorKMMIntResult(RuntimeException("There was an error, Int not generated")) } } Shared code
switch randomInt { case let error as KMMIntResult.ErrorKMMIntResult: randomIntText = "Error: \(error.throwable.message ?? error.throwable.description())" case let success as KMMIntResult.SuccessKMMIntResult: randomIntText = "Success: \(success.value)" default: randomIntText = "This never happens" } iOS
randomIntText: String switch randomInt { case let error as KMMResultErrorKMMResult: randomIntText = "Error: \(error.throwable.message ?? error.throwable.description())" case let success as KMMResultSuccessKMMResult<KotlinInt>: randomIntText = "Success: \(success.value)" default: randomIntText = "This never happens" }
throwable: Throwable ): KMMResult<Nothing>() data class ErrorKMMResult<Value>( val throwable: Throwable ): KMMResult<Value>() case let error as KMMResultErrorKMMResult<KotlinInt>: case let error as KMMResultErrorKMMResult:
API for Kotlin/Native framework. Note: at the moment, all subclasses in a sealed class must be nested, otherwise the generation fails. Generics and sealed classes Definitive solution
public var sealed: KMMResult<Value> { switch self { case .successKMMResult(let obj): return obj as shared.KMMResult<Value> case .errorKMMResult(let obj): return obj as shared.KMMResult<Value> } } public init(_ obj: KMMResult<Value>) { if let obj = obj as? shared.KMMResultSuccessKMMResult<Value> { self = .successKMMResult(obj) } else if let obj = obj as? shared.KMMResultErrorKMMResult<Value> { self = .errorKMMResult(obj) } else { fatalError("KMMResultKs not synchronized with KMMResult class") } } } Generics and sealed classes
${lastName.lastName}" value class FirstName(val firstName: String) value class LastName(val lastName: String) formatFirstAndLastName( FirstName("John"), LastName("Doe") ) Shared code
{ return formatFirstAndLastName(FirstName(firstName.firstName), LastName(lastName.lastName)) } data class FirstNameIos( val firstName: String ) data class LastNameIos( val lastName: String ) Shared iOS code
and may be changed at any time In the new memory manager (MM), we're lifting restrictions on object sharing: there's no need to freeze objects to share them between threads anymore. kotlin.native.binary.memoryModel=experimental https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md
checked errors Exception specified with @Throws -> Propagated as NSError Exception without @Throws -> iOS crash Always catch Exceptions in the shared code and return a Result like class