$30 off During Our Annual Pro Sale. View Details »

Get started with Kotlin Multiplatform Mobile

Get started with Kotlin Multiplatform Mobile

Yumemi.apk #3 ( https://yumemi.connpass.com/event/202135/ ) の資料

Hiroyuki Kusu

March 05, 2021
Tweet

More Decks by Hiroyuki Kusu

Other Decks in Programming

Transcript

  1. Get started with Kotlin


    Multiplatform Mobile
    2021.03.05 YUMEMI.apk #3


    Hiroyuki Kusu ( @hkusu_ )

    View Slide

  2. About me

    View Slide

  3. https://blog.jetbrains.com/ja/kotlin/2020/09/kotlin-multiplatform-mobile-goes-alpha-ja/

    View Slide

  4. https://kotlinlang.org/docs/mobile/home.html
    KMM ͷυΩϡϝϯτ

    View Slide

  5. Android Studio ༻ͷϓϥάΠϯ

    View Slide

  6. ৽ن KMM ϓϩδΣΫτ࡞੒༻ͷςϯϓϨʔτ

    View Slide

  7. KMMϓϩδΣΫτͷ਽ܗ͕࡞੒͞ΕΔ

    View Slide

  8. https://github.com/hkusu/KmmSampleApp
    ؆୯ͳαϯϓϧΛ࡞ͬͯΈͨ

    View Slide

  9. 6TF$BTF
    3FQPTJUPSZ
    "QJ
    %BUB$MBTT
    "DUJWJUZ
    7JFX.PEFM
    BOESPJE"QQ
    JPT"QQ
    ※ ࠓճ͸ݕূͰ͖͍ͯ·ͤΜ
    (JU)VC"1*
    TIBSFE

    View Slide

  10. • ಈ࡞֬ೝͨ͠ϩʔΧϧ؀ڥ


    • Android Studio 4.1.2


    • Android Studio Plugin


    • Kotlin: 1.4.31-release-Studio4.1-1


    • Kotlin Multiplatform Mobile: 0.2.0-release-65-Studio4.1


    • Ϗϧυπʔϧ΍ϥΠϒϥϦͷόʔδϣϯ౳͸ GitHub ͷίʔυͷํΛΈ͍ͯͩ͘͞

    View Slide

  11. plugins {


    // ...


    id("kotlinx-serialization")


    }


    kotlin {


    // ...


    sourceSets {


    val commonMain by getting {


    dependencies {


    // ...


    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2")


    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0")


    implementation("io.ktor:ktor-client-core:1.5.2")


    implementation("io.ktor:ktor-client-serialization:1.5.2")


    }


    }


    // ...


    val androidMain by getting {


    dependencies {


    // ...


    implementation("io.ktor:ktor-client-android:1.5.2")


    }


    }


    // ...


    val iosMain by getting {


    dependencies {


    implementation("io.ktor:ktor-client-ios:1.5.2")


    }


    }


    // ...


    }


    }


    build.gradle.kts
    shared
    Coroutines + serialization + Ktor ͷಋೖ
    ※ ਖ਼֬ͳઃఆ͸ GitHub ͷίʔυͷํΛݟ͍ͯͩ͘͞

    View Slide

  12. plugins {


    // ...


    id("kotlin-kapt")


    }


    kotlin {


    // ...


    sourceSets {


    // ...


    val androidMain by getting {


    dependencies {


    // ...


    implementation("com.google.dagger:hilt-android:2.31.2-alpha")


    // javax.annotation.Generated ͕ݟ͔ͭΒͳ͍Τϥʔ͕ग़ΔͷͰ..


    compileOnly("javax.annotation:javax.annotation-api:1.3.2")


    }


    }


    // ...


    }


    }


    // ref: https://www.reddit.com/r/Kotlin/comments/ack2r6/problem_using_kapt_in_a_multiplatform_project/


    dependencies {


    "kapt"("com.google.dagger:hilt-android-compiler:2.31.2-alpha")


    }
    build.gradle.kts
    shared
    ※ ਖ਼֬ͳઃఆ͸ GitHub ͷίʔυͷํΛݟ͍ͯͩ͘͞
    Dagger Hilt ͷಋೖ(Androidͷํʹ͚ͩ)

    View Slide

  13. buildscript {


    repositories {


    gradlePluginPortal()


    jcenter()


    google()


    mavenCentral()


    }


    dependencies {


    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.30")


    classpath("com.android.tools.build:gradle:4.1.2")


    classpath("org.jetbrains.kotlin:kotlin-serialization:1.4.30")


    classpath("com.google.dagger:hilt-android-gradle-plugin:2.31.2-alpha")


    }


    }


    allprojects {


    repositories {


    google()


    jcenter()


    mavenCentral()


    }


    }
    ϓϩδΣΫτϧʔτͷ build.gradle.kts

    View Slide

  14. shared/commonMain
    Ktor ෦෼Ҏ֎͸ී௨ͷ Kotlin + Coroutines ͷίʔυͳͷͰ Ktor ෦෼͚ͩҎ߱Ͱઆ໌
    ڞ௨ιʔε෦෼

    View Slide

  15. internal object Libs {


    internal val httpClient: HttpClient by lazy {


    HttpClient {


    install(JsonFeature) {


    serializer = KotlinxSerializer(json = Json {


    ignoreUnknownKeys = true


    })


    }


    }


    }


    }
    shared/commonMain
    Ktor ͷ HTTP ΫϥΠΞϯτͷੜ੒ͱ Kotlin serialization ͷઃఆ
    Android/iOS Ͱڞ௨ͷઃఆͰOK

    View Slide

  16. internal class GitHubApi(private val httpClient: HttpClient) {


    suspend fun getUserList(): List {


    return httpClient.get("${BASE_URL}/users")


    }


    companion object {


    private const val BASE_URL = "https://api.github.com"


    }


    }
    shared/commonMain
    suspending function ʹ΋ରԠ
    APIͷఆٛ

    View Slide

  17. @Module


    @InstallIn(SingletonComponent::class)


    internal object Module {


    @Provides


    fun provideGitHubApi(): GitHubApi {


    return GitHubApi(Libs.httpClient)


    }


    @Provides


    @Singleton


    fun provideUserRepository(gitHubApi: GitHubApi): UserRepository {


    return UserRepositoryImpl(gitHubApi)


    }


    @Provides


    fun provideGetUserUseCase(userRepository: UserRepository): GetUserUseCase {


    return GetUserUseCase(userRepository)


    }


    }
    shared/androidMain
    Dagger Hilt ͷϞδϡʔϧ
    ※ commonMain ʹ͸ Dagger ͸ແ͘ίϯετϥΫλΠϯδΣΫγϣϯͰ͖ͳ͍ͷͰ


    ͜͜ͰΠϯελϯεੜ੒ํ๏Λఆٛ
    (SharedͷதͷOSผ࣮૷)

    View Slide

  18. plugins {


    id("com.android.application")


    kotlin("android")


    id("kotlin-kapt")


    id("dagger.hilt.android.plugin")


    }


    dependencies {


    implementation(project(":shared"))


    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2")


    implementation("androidx.appcompat:appcompat:1.2.0")


    implementation("androidx.core:core-ktx:1.3.2")


    implementation("androidx.activity:activity-ktx:1.2.0")


    implementation("androidx.fragment:fragment-ktx:1.3.0")


    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0")


    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.0")


    implementation("androidx.constraintlayout:constraintlayout:2.0.4")


    implementation("com.google.android.material:material:1.3.0")


    implementation("com.google.dagger:hilt-android:2.31.2-alpha")


    kapt("com.google.dagger:hilt-android-compiler:2.31.2-alpha")


    }


    android {


    compileSdkVersion(29)


    // ...
    build.gradle.kts
    androidApp
    ͓ͳ͡ΈͷϥΠϒϥϦୡ

    View Slide

  19. plugins {


    id("com.android.application")


    kotlin("android")


    id("kotlin-kapt")


    id("dagger.hilt.android.plugin")


    }


    dependencies {


    implementation(project(":shared"))


    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2")


    implementation("androidx.appcompat:appcompat:1.2.0")


    implementation("androidx.core:core-ktx:1.3.2")


    implementation("androidx.activity:activity-ktx:1.2.0")


    implementation("androidx.fragment:fragment-ktx:1.3.0")


    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0")


    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.0")


    implementation("androidx.constraintlayout:constraintlayout:2.0.4")


    implementation("com.google.android.material:material:1.3.0")


    implementation("com.google.dagger:hilt-android:2.31.2-alpha")


    kapt("com.google.dagger:hilt-android-compiler:2.31.2-alpha")


    }


    android {


    compileSdkVersion(29)


    // ...
    build.gradle.kts
    androidApp
    Dagger Hilt

    View Slide

  20. @HiltViewModel


    class MainViewModel @Inject constructor(getUser: GetUserUseCase) : ViewModel() {


    private val _userList: MutableLiveData> = MutableLiveData()


    val userList = _userList as LiveData>


    init {


    viewModelScope.launch {


    _userList.value = getUser()


    }


    }


    }
    ViewModel
    androidApp
    Dagger Hilt

    View Slide

  21. @HiltViewModel


    class MainViewModel @Inject constructor(getUser: GetUserUseCase) : ViewModel() {


    private val _userList: MutableLiveData> = MutableLiveData()


    val userList = _userList as LiveData>


    init {


    viewModelScope.launch {


    _userList.value = getUser()


    }


    }


    }
    ViewModel
    androidApp
    shared ʹஔ͍ͨ UseCase Λ inject

    View Slide

  22. • Android ෦෼ʹؔͯ͠͸ී௨ʹ࡞Εͦ͏


    • Android ͔ΒݟΕ͹ී௨ͷϚϧνϞδϡʔϧߏ੒


    • ڞ௨ιʔε෦෼ʹ͍ͭͯ͸..


    • ϚϧνϓϥοτϑΥʔϜରԠͷϥΠϒϥϦΛར༻͢Δඞཁ͕͋Δ


    • ͜͜Λ iOS ޲͚ʹͲ͏ఏڙ͍͔͕ͯ͘͠ϙΠϯτʹͳΓͦ͏


    • iOS ޲͚ʹ DI ͢ΔͳΒ KOIN ΍ Kodein Λར༻ͨ͠ํ͕Αͦ͞͏

    View Slide

  23. Thank you !


    @hkusu_

    View Slide