Yumemi.apk #3 ( https://yumemi.connpass.com/event/202135/ ) の資料
Get started with KotlinMultiplatform Mobile2021.03.05 YUMEMI.apk #3Hiroyuki Kusu ( @hkusu_ )
View Slide
About me
https://blog.jetbrains.com/ja/kotlin/2020/09/kotlin-multiplatform-mobile-goes-alpha-ja/
https://kotlinlang.org/docs/mobile/home.htmlKMM ͷυΩϡϝϯτ
Android Studio ༻ͷϓϥάΠϯ
৽ن KMM ϓϩδΣΫτ࡞༻ͷςϯϓϨʔτ
KMMϓϩδΣΫτͷܗ͕࡞͞ΕΔ
https://github.com/hkusu/KmmSampleApp؆୯ͳαϯϓϧΛ࡞ͬͯΈͨ
6TF$BTF3FQPTJUPSZ"QJ%BUB$MBTT"DUJWJUZ7JFX.PEFMBOESPJE"QQJPT"QQ※ ࠓճݕূͰ͖͍ͯ·ͤΜ(JU)VC"1*TIBSFE
• ಈ࡞֬ೝͨ͠ϩʔΧϧڥ• 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 ͷίʔυͷํΛΈ͍ͯͩ͘͞
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.ktssharedCoroutines + serialization + Ktor ͷಋೖ※ ਖ਼֬ͳઃఆ GitHub ͷίʔυͷํΛݟ͍ͯͩ͘͞
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.ktsshared※ ਖ਼֬ͳઃఆ GitHub ͷίʔυͷํΛݟ͍ͯͩ͘͞Dagger Hilt ͷಋೖ(Androidͷํʹ͚ͩ)
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
shared/commonMainKtor ෦Ҏ֎ී௨ͷ Kotlin + Coroutines ͷίʔυͳͷͰ Ktor ෦͚ͩҎ߱Ͱઆ໌ڞ௨ιʔε෦
internal object Libs {internal val httpClient: HttpClient by lazy {HttpClient {install(JsonFeature) {serializer = KotlinxSerializer(json = Json {ignoreUnknownKeys = true})}}}}shared/commonMainKtor ͷ HTTP ΫϥΠΞϯτͷੜͱ Kotlin serialization ͷઃఆAndroid/iOS Ͱڞ௨ͷઃఆͰOK
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/commonMainsuspending function ʹରԠAPIͷఆٛ
@Module@InstallIn(SingletonComponent::class)internal object Module {@Providesfun provideGitHubApi(): GitHubApi {return GitHubApi(Libs.httpClient)}@Provides@Singletonfun provideUserRepository(gitHubApi: GitHubApi): UserRepository {return UserRepositoryImpl(gitHubApi)}@Providesfun provideGetUserUseCase(userRepository: UserRepository): GetUserUseCase {return GetUserUseCase(userRepository)}}shared/androidMainDagger Hilt ͷϞδϡʔϧ※ commonMain ʹ Dagger ແ͘ίϯετϥΫλΠϯδΣΫγϣϯͰ͖ͳ͍ͷͰ͜͜ͰΠϯελϯεੜํ๏Λఆٛ(SharedͷதͷOSผ࣮)
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.ktsandroidApp͓ͳ͡ΈͷϥΠϒϥϦୡ
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.ktsandroidAppDagger Hilt
@HiltViewModelclass MainViewModel @Inject constructor(getUser: GetUserUseCase) : ViewModel() {private val _userList: MutableLiveData> = MutableLiveData()val userList = _userList as LiveData>init {viewModelScope.launch {_userList.value = getUser()}}}ViewModelandroidAppDagger Hilt
@HiltViewModelclass MainViewModel @Inject constructor(getUser: GetUserUseCase) : ViewModel() {private val _userList: MutableLiveData> = MutableLiveData()val userList = _userList as LiveData>init {viewModelScope.launch {_userList.value = getUser()}}}ViewModelandroidAppshared ʹஔ͍ͨ UseCase Λ inject
• Android ෦ʹؔͯ͠ී௨ʹ࡞Εͦ͏• Android ͔ΒݟΕී௨ͷϚϧνϞδϡʔϧߏ• ڞ௨ιʔε෦ʹ͍ͭͯ..• ϚϧνϓϥοτϑΥʔϜରԠͷϥΠϒϥϦΛར༻͢Δඞཁ͕͋Δ• ͜͜Λ iOS ͚ʹͲ͏ఏڙ͍͔͕ͯ͘͠ϙΠϯτʹͳΓͦ͏• iOS ͚ʹ DI ͢ΔͳΒ KOIN Kodein Λར༻ͨ͠ํ͕Αͦ͞͏
Thank you !@hkusu_