web-dev-qa-db-ja.com

マルチプラットフォームプロジェクトのiOSモジュールでktorの依存関係が解決されない

IOSとAndroidをターゲットにしたkotlinマルチプラットフォームプロジェクトがあります。 Ktorhttpクライアントは共通モジュールで使用されます。

Android appですべてがうまく機能します。しかし、iOS libでプロジェクトをビルドすると、次の例外が発生します。

> Task :app:compileKotlinIos FAILED
src/commonMain/kotlin/com/ottamotta/mozoli/api/MozoliApiKtor.kt:4:8: error: unresolved reference: io
import io.ktor.client.HttpClient
       ^
src/commonMain/kotlin/com/ottamotta/mozoli/api/MozoliApiKtor.kt:5:8: error: unresolved reference: io
import io.ktor.client.features.feature

...そして他のものは、ktorの依存関係のどれも解決されていないと言っています。

これがbuild.gradleです:

plugins {
    id 'kotlin-multiplatform' version '1.3.10'
}
repositories {
    google()
    jcenter()
    mavenCentral()
    maven { url "https://kotlin.bintray.com/kotlinx" }
}

ext {
    support_lib_version = '28.0.0'
    ktor_version = '1.0.0'
}

def keystorePropertiesFile = rootProject.file("./app/secret.properties");
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

apply plugin: 'com.Android.application'
apply plugin: 'kotlin-Android-extensions'

Android {
    compileSdkVersion 28
    buildToolsVersion '28.0.3'
    defaultConfig {
        applicationId "com.ottamotta.mozoli"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "Android.support.test.runner.AndroidJUnitRunner"
        manifestPlaceholders = [auth0Domain: "@string/com_auth0_domain", auth0Scheme: "https"]
    }
    buildTypes {

        debug {
            resValue "string", "com_auth0_client_id", keystoreProperties['com_auth0_client_id']
        }
        release {
            resValue "string", "com_auth0_client_id", keystoreProperties['com_auth0_client_id']
            minifyEnabled false
        }
    }

    lintOptions {
        abortOnError false
    }


}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "com.Android.support:recyclerview-v7:${support_lib_version}"
    implementation "com.Android.support:appcompat-v7:${support_lib_version}"
    implementation 'com.squareup.picasso:picasso:2.71828'

    implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.7"

    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.1")
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-Android:1.0.1'

    implementation "com.auth0.Android:auth0:1.14.1"

    androidTestImplementation 'com.Android.support.test:runner:1.0.2'
}

kotlin {
    targets {
        fromPreset(presets.Android, 'Android')
        // This preset is for iPhone emulator
        // Switch here to presets.iosArm64 (or iosArm32) to build library for iPhone device
        fromPreset(presets.iosX64, 'ios') {
            compilations.main.outputKinds('FRAMEWORK')
        }
    }
    sourceSets {
        commonMain {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
                implementation "io.ktor:ktor-client:$ktor_version"
                implementation "io.ktor:ktor-client-json:$ktor_version"
                implementation "io.ktor:ktor-client-jackson:$ktor_version"
            }
        }
        commonTest {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-test-common'
                implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
            }
        }
        androidMain {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-stdlib'
                implementation "io.ktor:ktor-client-Android:$ktor_version"
            }
        }
        androidTest {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-test'
                implementation 'org.jetbrains.kotlin:kotlin-test-junit'
            }
        }
        iosMain {
            dependencies {
                implementation("io.ktor:ktor-client-ios:$ktor_version")
            }
        }
        iosTest {
        }
    }
}

task copyFramework {
    def buildType = project.findProperty("kotlin.build.type") ?: "DEBUG"
    def target = project.findProperty("kotlin.target") ?: "ios"
    dependsOn "link${buildType.toLowerCase().capitalize()}Framework${target.capitalize()}"

    doLast {
        def srcFile = kotlin.targets."$target".compilations.main.getBinary("FRAMEWORK", buildType)
        def targetDir = getProperty("configuration.build.dir")
        copy {
            from srcFile.parent
            into targetDir
            include 'app.framework/**'
            include 'app.framework.dSYM'
        }
    }
}

エラーを生成する共通モジュールからのファイルのコードは次のとおりです。

package com.ottamotta.mozoli.api

import com.ottamotta.mozoli.*
import io.ktor.client.HttpClient
import io.ktor.client.features.feature
import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.JsonSerializer
import io.ktor.client.features.json.defaultSerializer
import io.ktor.client.request.header
import io.ktor.client.request.request
import io.ktor.client.request.url
import io.ktor.http.HttpMethod


class MozoliApiKtor(
    private val serverUrl: String,
    private var jsonSerializer: JsonSerializer? = null,
    private val tokenProvider: suspend () -> String?
) : MozoliApi {

    private val client: HttpClient

    private val AUTH_HEADER = "Authorization";
    private val TOKEN_PREFIX = "Bearer "

    init {
        client = HttpClient {
            install(JsonFeature) {
                serializer = jsonSerializer ?: defaultSerializer()
            }
        }
        jsonSerializer = client.feature(JsonFeature)?.serializer
    }

    override suspend fun getUserProfile(): User {
        return client.request {
            url("${serverUrl}/user/")
            method = HttpMethod.Get
            header(AUTH_HEADER, TOKEN_PREFIX + tokenProvider())
        }
    }

    override suspend infix fun getEventsByCity(cityId: String): List<Event> {
        return client.request {
                url("${serverUrl}/event/city/${cityId}")
                method = HttpMethod.Get
                header(AUTH_HEADER, TOKEN_PREFIX + tokenProvider())
            }

    }

}
6

私はあなたとまったく同じ問題を抱えていました。 Androidアプリ用に構築され、問題なく動作しますが、iOSモジュールはKtor、コルーチン、またはkotlinxシリアル化クラスを見つけることができません。

https://github.com/adrianbukros/github-multiplatform-example に沿って進み、セットアップをコピーしようとすると、最終的にpackForXCodeタスクをいくつかコピーして機能させることができました。つまり、彼らのgradleは次のように設定されています。

それらの共通モジュールbuild.gradleは、次のようになります。

apply plugin: 'kotlin-multiplatform'
apply plugin: 'kotlinx-serialization'

kotlin {
    targets {
        fromPreset(presets.jvm, "Android")

        fromPreset(presets.iosX64, "ios_x86_64")
        fromPreset(presets.iosArm64, "ios_arm64")
        configure([ios_x86_64, ios_arm64]) {
            compilations.main.outputKinds("FRAMEWORK")
        }
    }

    sourceSets {
        commonMain.dependencies {
            implementation "org.jetbrains.kotlin:kotlin-stdlib"
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutines_version"
            implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version"

            implementation "io.ktor:ktor-client-core:$ktor_version"
            implementation "io.ktor:ktor-client-json:$ktor_version"
        }

        androidMain.dependencies {
            implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"

            implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"

            implementation "io.ktor:ktor-client-core-jvm:$ktor_version"
            implementation "io.ktor:ktor-client-json-jvm:$ktor_version"
        }

        iosMain.dependencies {
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$coroutines_version"
            implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serialization_version"

            implementation "io.ktor:ktor-client-ios:$ktor_version"
            implementation "io.ktor:ktor-client-core-ios:$ktor_version"
            implementation "io.ktor:ktor-client-json-ios:$ktor_version"
        }
        configure([ios_x86_64Main, ios_arm64Main]) {
            dependsOn iosMain
        }
    }
}

// workaround for https://youtrack.jetbrains.com/issue/KT-27170
configurations {
    compileClasspath
}

task packForXCode(type: Sync) {
    final File frameworkDir = new File(buildDir, "xcode-frameworks")

    final String configuration = project.findProperty("CONFIGURATION")?.toUpperCase() ?: "DEBUG"
    final String Arch = project.findProperty("ARCHS") ?: "x86_64"

    dependsOn kotlin.targets."ios_${Arch}".compilations.main.linkTaskName("FRAMEWORK", configuration)

    from { kotlin.targets."ios_${Arch}".compilations.main.getBinary("FRAMEWORK", configuration).parentFile }
    into frameworkDir
}

tasks.build.dependsOn packForXCode

そして、次のようになるはずのsettings.gradleファイル:

enableFeaturePreview("GRADLE_METADATA") // IMPORTANT!

include 'commoncode'
include 'app'

それでも機能しない場合は、それらの*.gradleファイルとgradle.*ファイルをすべて調べて、ファイルの違いを確認してください。

これでようやくタスクが通過し、XCodeでKotlinKtorコードを使用できるようになりました。ただし、現在Android Studioは共有iOSモジュールに対して「Kotlinが構成されていません」と言っています。理由がわかったら報告します。何か見つけたら共有してください!

[〜#〜] edit [〜#〜]共通モジュールbuild.gradleを次のように変更しました。すべてが正常に機能しているようです!

apply plugin: 'kotlin-multiplatform'
apply plugin: 'kotlinx-serialization'

kotlin {
    targets {
        fromPreset(presets.jvm, 'Android')

        // Change to `presets.iosArm64` to deploy the app to iPhone
        fromPreset(presets.iosX64, 'ios') {
            compilations.main.outputKinds('FRAMEWORK')
        }
    }

    sourceSets {
        commonMain.dependencies {
            implementation "org.jetbrains.kotlin:kotlin-stdlib"
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutines_version"
            implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version"

            implementation "io.ktor:ktor-client-core:$ktor_version"
            implementation "io.ktor:ktor-client-json:$ktor_version"
        }

        androidMain.dependencies {
            implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"

            implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"

            implementation "io.ktor:ktor-client-core-jvm:$ktor_version"
            implementation "io.ktor:ktor-client-json-jvm:$ktor_version"
        }

        iosMain.dependencies {
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$coroutines_version"
            implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serialization_version"

            implementation "io.ktor:ktor-client-ios:$ktor_version"
            implementation "io.ktor:ktor-client-core-ios:$ktor_version"
            implementation "io.ktor:ktor-client-json-ios:$ktor_version"
        }
    }
}

// workaround for https://youtrack.jetbrains.com/issue/KT-27170
configurations {
    compileClasspath
}

task packForXCode(type: Sync) {
    final File frameworkDir = new File(buildDir, "xcode-frameworks")
    final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'

    inputs.property "mode", mode
    dependsOn kotlin.targets.ios.compilations.main.linkTaskName("FRAMEWORK", mode)

    from { kotlin.targets.ios.compilations.main.getBinary("FRAMEWORK", mode).parentFile }
    into frameworkDir

    doLast {
        new File(frameworkDir, 'gradlew').with {
            text = "#!/bin/bash\nexport 'Java_HOME=${System.getProperty("Java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n"
            setExecutable(true)
        }
    }
}

tasks.build.dependsOn packForXCode
8
Jeff Johnson