繁体   English   中英

如何从 Android Studio 加速 Kotlin Multiplatform 的 iOS 应用构建

[英]How to speed up iOS app builds of Kotlin Multiplatform from Android Studio

我有一个 KMP 项目,其中包含 iOS 应用程序、Android 应用程序和共享的 KMP 模块。 当我尝试从 Android Studio 构建 iOS 应用程序(以便能够对其进行调试)时,构建成功。 ☺️

问题是构建总是(当你更改代码时)需要大约 12 分钟⏰。 当您调试并经常测试给定代码是否有效时,这是很长的时间。 花费在构建上的 90% 的时间用于运行这些任务:

> Task :kmpcorelib:linkDebugFrameworkIosArm64
> Task :kmpcorelib:linkDebugFrameworkIosX64
> Task :kmpcorelib:linkKMPCoreDebugFrameworkIosArm64
> Task :kmpcorelib:linkKMPCoreDebugFrameworkIosX64
> Task :kmpcorelib:linkKMPCoreReleaseFrameworkIosArm64
> Task :kmpcorelib:linkKMPCoreReleaseFrameworkIosX64
> Task :kmpcorelib:linkReleaseFrameworkIosArm64
> Task :kmpcorelib:linkReleaseFrameworkIosX64

我的问题是:有没有办法在不运行所有这些任务的情况下如何在 iOS 模拟器上运行应用程序?

不知道工作室为什么要链接RELEASE版本的框架。

我也不明白为什么它在 X64 模拟器上运行时必须运行iOSArm64变体。

运行linkDebugFrameworkIosArm64linkKMPCoreDebugFrameworkIosArm64有什么区别,不是重复吗?

PS:我通过点击 Android Studio 中的默认配置来运行 iOS buld,而不是一些自定义的 gradle 脚本。

这是 KMP build.gradle 的样子:

plugins {
    id("com.android.library")
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    kotlin("plugin.serialization") version "1.5.0"
    id("com.prof18.kmp.fatframework.cocoa") version "0.0.1"
    id("io.gitlab.arturbosch.detekt")
    id("maven-publish")
}
version = "1.3.11"
group = "com.betsys.kmpcorelib"
val podName = "KMPCore"
detekt {
    autoCorrect = true
    config = files("$rootDir/config/detekt.yml")
    baseline = file("$rootDir/config/baseline.xml")
    input = files("src/commonMain/kotlin")
    reports {
        html.enabled = true
        xml.enabled = true
        txt.enabled = true
    }
}

// If you want to build iOS app from Android Studio - you have to put this config to comment - it somehow breaks the iOS build
fatFrameworkCocoaConfig {
    fatFrameworkName = podName
    outputPath = "$rootDir/../cocoapods"
    versionName = "1.16.1"
}
val ktorVersion = "1.5.4"
val napierVersion = "1.4.1"
val koinVersion = "3.0.1"
val kotlinxVersion = "1.4.1"
val kotlinxDatetime = "0.1.1"
kotlin {
    // We cant use simple ios() target now, since it doesnt support Arm32 architecture
    // For that reason we have specify each target explicitly
    // Same for folders with iOS code. We havet to use duplicit iosX64Main etc. instead of one iosMain folder
    ios("ios") {
        binaries.framework(podName)
    }
    android {
        publishLibraryVariants("debug")
        publishLibraryVariantsGroupedByFlavor = true
    }
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-core:$ktorVersion")
                implementation("io.ktor:ktor-client-logging:$ktorVersion")
                implementation("io.ktor:ktor-client-mock:$ktorVersion")
                implementation("io.ktor:ktor-client-serialization:$ktorVersion")
                implementation("io.ktor:ktor-client-websockets:$ktorVersion")
                api("io.insert-koin:koin-core:$koinVersion")
                api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxVersion-native-mt")
                api("org.jetbrains.kotlinx:kotlinx-datetime:$kotlinxDatetime")
                api("com.ionspin.kotlin:bignum:0.3.1-SNAPSHOT")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.0")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
                implementation( "io.mockk:mockk-common:1.11.0")
                implementation("com.ionspin.kotlin:bignum:0.3.1-SNAPSHOT")
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-android:$ktorVersion")
                implementation("com.google.android.material:material:1.3.0")
                implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinxVersion")
                implementation("com.jakewharton.timber:timber:4.7.1")
            }
        }
        val androidTest by getting {
            dependencies {
                implementation(kotlin("test-junit"))
                implementation("junit:junit:4.13.2")
                implementation("io.mockk:mockk:1.11.0")
            }
        }
        val iosMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-ios:$ktorVersion")
            }
        }
        val iosTest by getting
    }
}
android {
    compileSdkVersion(30)
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdkVersion(19)
        targetSdkVersion(30)
        versionCode = 1
        versionName = "1.0"
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
        }
    }
    packagingOptions {
        excludes.add("META-INF/*.kotlin_module")
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().all {
        kotlinOptions {
            jvmTarget = "1.8"
        }
    }
}
val packForXcode by tasks.creating(Sync::class) {
    val targetDir = File(buildDir, "xcode-frameworks")
    /// selecting the right configuration for the iOS
    /// framework depending on the environment
    /// variables set by Xcode build
    val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
    val sdkName: String? = System.getenv("SDK_NAME")
    val isiOSDevice = sdkName.orEmpty().startsWith("iphoneos")
    val framework = kotlin.targets
        .getByName<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>(
            if (isiOSDevice) {
                "iosArm64"
            } else {
                "iosX64"
            }
        )
        .binaries.getFramework(mode)
    inputs.property("mode", mode)
    dependsOn(framework.linkTask)
    from({ framework.outputDirectory })
    into(targetDir)
    println("Build Folder => $targetDir")
    /// generate a helpful ./gradlew wrapper with embedded Java path
    doLast {
        val gradlew = File(targetDir, "gradlew")
        gradlew.writeText(
            "#!/bin/bash\n"
                    + "export 'JAVA_HOME=${System.getProperty("java.home")}'\n"
                    + "cd '${rootProject.rootDir}'\n"
                    + "./gradlew \$@\n"
        )
        gradlew.setExecutable(true)
    }
}
tasks.build.dependsOn("packForXCode")

Android Studio 中的“默认配置”(例如, assemblebuild gradle 任务)将构建所有“构建”任务,其中包括 Z1BDF605991920DB11CBDF8508204C4EB4 发布框架和 Arm4 架构的链接。

请注意您在build.gradle.kts文件中获得的packForXcode任务? 当您想要为 iOS 应用程序(至少在本地)构建 KMM 模块时,这就是您想要调用的内容。 使用该任务将只构建您需要的架构和配置(例如,您的模拟器上的X64DEBUG ),您很快就会发现它要快得多。 作为 Xcode 项目的构建步骤的一部分,它应该在运行脚本阶段被调用。

如果您在 Android Studio 中创建新项目时使用 Kotlin 多平台应用程序模板,我相信这应该已自动添加到您的 Xcode 项目中。

您可以在此处阅读更多相关信息:了解 KMM 项目结构 |Kotlin 多平台移动文档

我使用此任务为 iOS 构建更改:

./gradlew :shared:compileKotlinIosSimulatorArm64

工作很快

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM