Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Multiplatform Mobile: From Hello World to Production

pahill
October 24, 2022
76

Kotlin Multiplatform Mobile: From Hello World to Production

Droidcon London version

pahill

October 24, 2022
Tweet

Transcript

  1. Pamela Hill & Tadeas Kriz Kotlin Multiplatform Mobile From Hello

    World to Production @pamelaahill @TadeasKriz
  2. Topics • Introduction • Use Case Scenarios • Application Architecture

    • Testing • Debugging Crashes • Closing • Q&A Introduction Use Case Scenarios Architecture Testing Debugging Crashes Closing
  3. What is Kotlin Multiplatform Mobile? • SDK by JetBrains, beta

    earlier in October • Allows development teams to share common code • Doesn't impose restrictions on non-shared code
  4. .framework What is Kotlin Multiplatform Mobile? Android App iOS App

    Kotlin/JVM Kotlin/Native MySharedModule .jar/.aar
  5. How can you share code? iOS App Multiplatform Mobile Module

    (Shared) Android App Presentation (Presenters, View Models, Controllers) UI (Views) Presentation (Presenters, View Models, Controllers) UI (Views) Data / Core (Repositories, HTTP Clients, Cache) Business / Domain (Entities, Use Cases, Interactors)
  6. How can you share code? iOS App Multiplatform Mobile Module

    (Shared) Android App Presentation (Presenters, View Models, Controllers) UI (Views) UI (Views) Data / Core (Repositories, HTTP Clients, Cache) Business / Domain (Entities, Use Cases, Interactors)
  7. What are the bene f its of Kotlin Multiplatform Mobile?

    • Flexibility to choose what is shared and what not 
 • Shared code lowers the e ff ort, cost per feature 
 • Shared code ensures consistency amongst platforms
  8. Green f ield project #1 Kotlin Multiplatform Mobile Project shared

    <KMM module> androidApp <module> iosApp <module> commonMain <source set> iosMain <source set> androidMain <source set>
  9. Green f ield project #2 Kotlin Multiplatform Mobile Project androidApp

    <module> iosApp <module> analytics <KMM module> validation <KMM module> formatting <KMM module>
  10. Brown f ield project #1 Android Project Regular Android code

    shared <module> commonMain <source set> iosMain <source set> androidMain <source set> iOS Project Regular iOS code Dependencies management • CocoaPods • Swift Package Manager • Manual framework
  11. Brown f ield project #2 Android Project Regular Android code

    analytics <KMM module> iOS Project Regular iOS code validation <KMM module> formatting <KMM module> shared <KMM module> Dependencies management • CocoaPods • Swift Package Manager • Manual framework
  12. Brown f ield project #3 analytics <KMM library> validation <KMM

    library> formatting <KMM library> iOS Project Regular iOS code Android Project Regular Android code
  13. KMMBridge Android App Swift / Obj-C iOS App Framework Releases

    1.2.0 1.2.1 … SPM/Cocoapods KMMBridge Android / Kotlin
  14. Adding Multiplatform Mobile to Your Projects • Start small •

    Keep your shared API simple • Think like a library developer • Implementation should not impact API • Minimise accessibility of everything • Coexist peacefully with (both) platforms
  15. Presentation Layer • Sharing is possible to a degree •

    Prefer MVVM and MVI • Decompose, moko-mvvm • Needs experienced team to share
  16. Data Layer • Usually shareable • Repositories, DTOs and entities

    • SQLDelight, Realm, Ktor Client, Apollo, kotlinx-datetime
  17. Project Structure Kotlin Multiplatform Mobile Project shared <KMM module> androidApp

    <module> iosApp <module> androidMain <source set> androidTest <source set> commonMain <source set> commonTest <source set> iosMain <source set> iosTest <source set>
  18. Testing Shared Code shared/build.gradle.kts val commonTest by getting { dependencies

    { implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) } } val androidTest by getting { dependencies { implementation(kotlin("test-junit")) implementation("junit:junit:4.13.2") } }
  19. Testing Shared Code commonMain/../NewYear.kt import kotlinx.datetime.* fun daysUntilNewYear( today: LocalDate

    = Clock.System.todayIn(TimeZone.currentSystemDefault()) ): Int { val closestNewYear = LocalDate(today.year + 1, 1, 1) return today.daysUntil(closestNewYear) }
  20. Testing Shared Code commonTest/…/NewYearTest.kt import kotlinx.datetime.LocalDate import kotlin.test.Test import kotlin.test.assertEquals

    class NewYearTest { @Test fun `From Jan 1 2022 to Jan 1 2023`() { val startDate = LocalDate( year = 2022, monthNumber = 1, dayOfMonth = 1 ) assertEquals( expected = 365, actual = daysUntilNewYear(startDate), "There are x days until New Year 2023" ) } }
  21. Testing expect/actual //commonMain expect class Platform() { val osName: String

    } //androidMain actual class Platform actual constructor() { actual val osName = "Android" } //iosMain actual class Platform actual constructor() { actual val osName = UIDevice.currentDevice.systemName() }
  22. Testing expect/actual androidTest/../PlatformTest.kt actual class PlatformTest { private val platform

    = Platform() @Test actual fun testOSName() { assertEquals( expected = "Android", actual = platform.osName, message = "The OS name should be Android." ) } }
  23. Testing expect/actual iosTest/../PlatformTest.kt actual class PlatformTest { private val platform

    = Platform() @Test actual fun testOSName() { assertTrue( actual = platform.osName.equals("iOS", ignoreCase = true) message = "The OS name should be iOS." ) } }
  24. MocKMP Multiplatform framework for creating mocks and fakes class MyTests

    : TestsWithMocks() { override fun setUpMocks() = injectMocks(mocker) @Mock lateinit var view: View @Fake lateinit var model: Model val controller by withMocks { Controller( view = view, firstModel = model ) } ... }
  25. iOS UI Testing iosApp/…/iosAppUITests.swift import XCTest class iosAppUITests: XCTestCase {

    private let app = XCUIApplication() override func setUp() { super.setUp() continueAfterFailure = false app.launch() } func testButtonExistence() { XCTAssert(app.buttons["clickMeButton"].exists) } }
  26. Errors and Exceptions Swift and ObjC func iThrow() throws {

    throw NSError() } func iCrash() { fatalError() } -(BOOL)iThrow:(NSError**)error { *error = [[NSError alloc] init]; return NO; } -(void)iCrash { [NSException raise:@"Oops" format:@""]; } Recoverable Unrecoverable
  27. Errors and Exceptions Kotlin vs Swift func iThrow() throws {

    throw NSError() } func iCrash() { fatalError() } @Throws(IllegalStateException::class) fun iThrow() { throw IllegalStateException() } fun iCrash() { throw IllegalStateException() }
  28. Key Points • Kotlin Multiplatform Mobile is powerful, but challenging

    • No silver bullets • Use it now, it's ready!