我的 Android Kotlin Jetpack Compose 项目无法识别使用 Gradle 构建的 OpenApi 客户端 Kotlin Jar 依赖项

问题描述 投票:0回答:1

我实际上正在开发一个具有 Kotlin Springboot 后端的项目,其中使用 OpenApi 生成的 Api(在 yaml 中),我想将其插入客户端 Android Jetpack Compose。

我想要做的是从我的后端项目生成 openApi 客户端作为 Jar Kotlin 依赖项,并将其导入到我的客户端项目中。

这是实现“客户端生成/jar打包/maven本地发布”阶段的后端gradle构建:

后端客户端生成:

tasks.register("generateKotlinClient", org.openapitools.generator.gradle.plugin.tasks.GenerateTask::class) {
    generatorName.set("kotlin")
    inputSpec.set("$rootDir/src/main/resources/api/api.yaml")
    outputDir.set(layout.buildDirectory.dir("generated/grimoire-server-client").get().asFile.path)
    invokerPackage.set("com.com.corbz.grimoire.backend.client")
    packageName.set("com.com.corbz.grimoire.backend.client")
    apiPackage.set("com.com.corbz.grimoire.backend.client.api")
    modelPackage.set("com.com.corbz.grimoire.backend.client.model")

    generateApiDocumentation.set(false)
    generateModelDocumentation.set(false)
    generateApiTests.set(false)
    generateModelTests.set(false)

    configOptions.set(
        mapOf(
            "sourceFolder" to "."
        )
    )
}

tasks.register("packageClientJar", Jar::class) {
    group = "build"
    val generatedClientDir = layout.buildDirectory.dir("generated/grimoire-server-client/com").get().asFile
    from(generatedClientDir)
    archiveBaseName.set("grimoire-backend-client")
    archiveVersion.set("1.0.0")
    destinationDirectory.set(layout.buildDirectory.dir("libs").get().asFile)
}

publishing {
    publications {
        create<MavenPublication>("grimoireBackendClient") {
            groupId = "com.corbz"
            artifactId = "grimoire-backend-client"
            version = "1.0.0"

            artifact(tasks.named("packageClientJar").get()) {
                builtBy(tasks.named("packageClientJar"))
            }
        }
    }
    repositories {
        maven {
            name = "local"
            url = uri("${System.getProperty("user.home")}/.m2/repository")
        }
    }
}

它为我生成一个包含包文件夹和清单文件夹的 jar。我的 Android 项目由主 build.gradle.kts /setting.gradle.kts 组织,我的代码位于具有自己的 build.gradle.kts /setting.gradle.kts 的应用程序包中。在应用程序包的 build.gradle.kts 中,我的库是这样导入的(我没有将所有文件与所有依赖项放在一起,但这就是我导入客户端依赖项的方式):

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
}

android {
    namespace = "com.corbz.grmoire.android"
    compileSdk = 35

    defaultConfig {
        applicationId = "com.corbz.grmoire.android"
        minSdk = 24
        targetSdk = 35
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    kotlinOptions {
        jvmTarget = "17"
    }
    buildFeatures {
        compose = true
    }
}


dependencies {

    // Business dependencies --------------------------
    implementation(libs.grimoire.backend.client)
    implementation(libs.moshi)
    implementation(libs.moshi.kotlin)
    // ------------------------------------------------
}

由于我不明白该库是否被识别,我可以像这样导入包:

package com.corbz.grmoire.android.config


import android.app.Application
import dagger.hilt.android.HiltAndroidApp
import com.corbz.grimoire.backend.client.model.*

@HiltAndroidApp
class GrimoireApplication: Application() {
    
}

但是,如果我尝试从此包中导入例如 GrimoireDto,则无法识别它。这是从 openApi 客户端依赖项为我的 GrimoireDto 生成的类 (kt):

@file:Suppress(
    "ArrayInDataClass",
    "EnumEntryName",
    "RemoveRedundantQualifierName",
    "UnusedImport"
)

package com.com.corbz.grimoire.backend.client.model


import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

/**
 * 
 *
 * @param code Unique identifier for the grimoire.
 * @param creationDate The creation date of the grimoire.
 * @param lastUpdateDate The last update date of the grimoire.
 */


data class GrimoireDto (

    /* Unique identifier for the grimoire. */
    @Json(name = "code")
    val code: kotlin.String,

    /* The creation date of the grimoire. */
    @Json(name = "creationDate")
    val creationDate: java.time.OffsetDateTime,

    /* The last update date of the grimoire. */
    @Json(name = "lastUpdateDate")
    val lastUpdateDate: java.time.OffsetDateTime

) {


}

我不明白为什么这个 Kotlin 类不能导入,因为它是一个 .kt 文件,对我来说该类没有任何问题,我还尝试导入子依赖项(例如客户端的 mochi)以使所有依赖项都正常工作但没有任何效果。 我什至尝试使用 android 生成器生成(对我来说它应该与 kotlin 多平台一起使用,但它是“为了科学”)但问题仍然是一样的。

您能帮忙找出我的生成/导入出了什么问题吗?我想导入这个客户端以避免客户端调用后端的手动编码。

提前感谢大家!

android kotlin gradle openapi openapi-generator
1个回答
0
投票

经过一番搜索和尝试,我发现它可以解决我的问题。正如在某些情况下建议的那样,我所做的就是更改我的项目结构以进行根构建,并将应用程序模块(包含源、构建定义、测试)和客户端模块(客户端构建和 jar包装):

项目结构

这是客户端 build.gradle.kts :

plugins {
    // Inherited
    kotlin("jvm")
    id("org.openapi.generator")
    id("maven-publish")
}

group = "com.corbz.grimoire"
version = "0.0.2-SNAPSHOT"



repositories {
    mavenCentral()
}

sourceSets {
    main {
        java.srcDir("src/main/generated-client")
    }
}

/**
 * Build Processing Workflow
 */

task("processGeneratedFilesClient") {
    val generatedDir = file("$projectDir/src/main/generated-client")
    println("GeneratedDir to clean : $generatedDir")
    if (generatedDir.exists()) {
        println("Cleaning up existing generated files...")
        delete(generatedDir)
    }
}

// Ajout d'une tâche pour s'assurer que les sources sont générées avant la compilation
tasks.compileKotlin {
    dependsOn(tasks.openApiGenerate)
}

// Backend Client Generation
openApiGenerate {
    generatorName.set("kotlin")
    inputSpec.set("$rootDir/api/api.yaml") // Chemin vers ton fichier YAML
    outputDir.set("$projectDir/src/main/generated-client")

    invokerPackage.set("com.corbz.grimoire.backend.client")
    packageName.set("com.corbz.grimoire.backend.client")
    apiPackage.set("com.corbz.grimoire.backend.client.api")
    modelPackage.set("com.corbz.grimoire.backend.client.model")

    generateApiDocumentation.set(false)
    generateModelDocumentation.set(false)
    generateApiTests.set(false)
    generateModelTests.set(false)

    configOptions.set(mapOf("sourceFolder" to ""))
}

publishing {
    publications {
        create<MavenPublication>("grimoireBackendClientJar") {
            groupId = project.group.toString()
            artifactId = "grimoire-backend-client"
            version = project.version.toString()

            from(components["java"])
        }
    }
    repositories {
        mavenLocal()
    }
}

dependencies {
    implementation("com.squareup.moshi:moshi-kotlin:1.15.2")
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
}

这是应用程序构建:

 plugins {
    kotlin("plugin.spring") version "2.1.0"
    id("org.springframework.boot") version "3.3.5"
    id("io.spring.dependency-management") version "1.1.6"

    // Inherited
    kotlin("jvm")
    id("org.openapi.generator")
}

group = "com.corbz.grimoire.backend.app"
version = "0.0.1-SNAPSHOT"

kotlin {
    jvmToolchain(23)
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(kotlin("stdlib-jdk8"))

    // Open Api Generation
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.springdoc:springdoc-openapi-starter-common:2.2.0")
    implementation("com.squareup.okhttp3:okhttp:4.12.0")

    // Spring Ecosystem
    implementation("org.springframework.boot:spring-boot-starter-web")

    // database
    implementation("org.springframework.boot:spring-boot-starter-data-mongodb") // Documents / Consistences negligeables
    implementation("org.springframework.boot:spring-boot-starter-data-jpa") // Utilisateurs / Consistences fortes
    implementation("org.postgresql:postgresql:42.7.4")
    implementation("de.flapdoodle.embed:de.flapdoodle.embed.mongo.spring25x:4.18.0") //TODO : Pas sûr d'en avoir besoin
    implementation("org.jetbrains.kotlin:kotlin-reflect") //TODO: idem

    // Security
    implementation("org.springframework.boot:spring-boot-starter-security")
    implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")

    // Unit testing
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")

    // Integration testing
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.testcontainers:testcontainers:1.17.6")
    testImplementation("org.testcontainers:postgresql:1.20.4")
    testImplementation("org.testcontainers:mongodb:1.17.6")
    testImplementation("org.testcontainers:junit-jupiter:1.17.6")
}

sourceSets {
    main {
        java.srcDir("src/main/generated-api") // Ajouter le dossier 'generated' comme répertoire source
    }
}




/**
 * Build Processing Workflow
 */

task("processGeneratedFilesApi") {
    // Nettoyer le dossier 'generated' s'il existe
    val generatedDir = file("$projectDir/src/main/generated-api")
    println("GeneratedDir to clean : $generatedDir")
    if (generatedDir.exists()) {
        println("Cleaning up existing generated $projectDir files...")
        delete(generatedDir)  // Supprimer les fichiers existants dans le dossier 'generated'
    }
}

tasks.compileKotlin {
    dependsOn(tasks.openApiGenerate)
}

/**
 * API Generation
 */

//Server Api Generation
openApiGenerate {
    generatorName.set("kotlin-spring")
    inputSpec.set("$rootDir/api/api.yaml") // Chemin vers ton fichier YAML
    outputDir.set("$projectDir/src/main/generated-api") // Dossier où tu veux que le code généré soit placé

    apiPackage.set("com.corbz.grimoire.api")
    modelPackage.set("com.corbz.grimoire.api.model")

    configOptions.set(
        mapOf(
            "interfaceOnly" to "true",
            "skipDefaultInterface" to "true", // Force l'implémentation des APIs
            "useSpringBoot3" to "true", // Utilisation de jakarta vs javax,
            "sourceFolder" to "", // Place le package au bon niveau,
            "gradleBuildFile" to "false",
            "documentationProvider" to "none"
        )
    )
}

/**
 * Testing tasks
 */
tasks.withType<Test> {
    useJUnitPlatform()
}

这允许我将客户端构建为 jar 依赖项,以便作为依赖项集成到其他项目中

© www.soinside.com 2019 - 2024. All rights reserved.