背景
KMM官方提供的例子都是Android,iOS,KMM三个模块耦合在一个工程中,提供的构建指南也基本基于此。但是现实场景中,基本三个模块都是在三个单独的工程中。这种情况下,该如何构建双端产物并集成到双端工程中对于不少初学者来说都是个难题。KMM官方的插件任务多且类似,不一个个尝试都不能确定每个任务到底是在干啥。对于iOS的集成则更加麻烦,官方只提供了插件来支持cocoapods集成,并且指南也不明确,对于SPM的支持则完全没有。
在这个背景下,我决定编写一个插件KMMDeploy。它提供清晰的双端产物构建任务,并且支持多种集成方案,包括本地集成,远端maven集成,cocoapods集成,以及spm集成。开发者只需要使用这个插件便可以轻松完成双端的产物构建,发布及部署。
主要功能
该插件主要提供三个功能:
-
将KMM工程构建成双端产物,Android为AAR,iOS为XCFrameworks
-
自动配置Maven发布任务,生成发布Android产物AAR以及iOS产物的zip包到远端仓库的任务
-
iOS若配置Cocoapods插件则生成podspec文件,和XCFrameworks一起复制到对应的git submodule(这个后面会详讲)。若配置SPM则生成Package.swift文件,并将产物打为zip包,发布到远端仓库
构建产物
对于第一次尝试KMM的开发人员来说,构建Android和iOS工件可能会让他们感到困惑。 Kotlin Multiplatform插件产生了很多任务,并没有提供有关如何构建项目的指南。因此,该插件提供了几个任务,清楚地显示如何为Android和iOS生成对应产物。
- 构建Debug/Release版本的双端产物
./gradlew buildKMMDebug ./gradlew buildKMMRelease
- 构建所有版本的双端产物
./gradlew buildKMM
-
单独构建Android的AAR产物或者iOS的XCFrameworks产物
./gradlew buildKMMAARs ./gradlew buildKMMXCFrameworks
跑完这些任务后,即可在如下位置找到对应的产物:
-
Android:/build/outputs/aar/***.aar
-
iOS CocoaPods: /build/cocoapods/publish/
-
iOS XCFrameworks: /build/XCFrameworks/
配置发布任务
两端主工程想要依赖到KMM工程生成的产物就需要这些产物发送到远端仓库,而KMM插件并没有提供这样的能力,需要开发者手动配置发布任务和仓库,手动触发发布任务才能发布。而该插件则自动配置了对应的发布任务,并将最终的部署任务依赖到发布任务上,实现一键完成产物发布和部署
AAR
通过上面的任务获取到AAR后,就需要配置发布任务来将AAR发布到远端,这样我们的Android仓库才能访问到KMM模块。常规都是发布到Maven仓库,所以这个插件提供了自动配置Maven发布AAR的任务,节约了开发者手动配置的时间
./gradlew publishKMMAndroidPublicationToMavenLocal
./gradlew publishKMMAndroidPublicationToMavenRepository
kmmdeploy分组下还有一个publishAAR任务,等同于publishKMMAndroidPublicationToMavenRepository
./gradlew publishAAR
SPM
在2.0.0的版本中,该插件添加了对SPM的支持。插件会生成任务来将iOS的XCFramework产物打包成zip文件,并发布到远端仓库,通常都是Maven仓库。这里只介绍发布任务,打包任务后面会介绍
./gradlew publishKMMSpmPublicationToMavenLocal
./gradlew publishKMMSpmPublicationToMavenRepository
kmmdeploy分组下还有一个publishXCFrameworks任务,等同于publishKMMSpmPublicationToMavenRepository
./gradlew publishXCFrameworks
部署产物
iOS
对于iOS的产物部署,该插件提供了三种方式:
本地部署
如果只是处于调试阶段,想本地集成产物,那么该插件提供了一个任务可以将XCFramework产物复制到根目录下的一个产物目录。这样,你可以自由选择如何将该产物集成到Xcode中本地使用
./gradlew copyXCFrameworkToProject
Cocoapods
如果你选择了使用Cocoapods集成,那么该插件提供了一种推荐的工作流来完成产物部署:
-
首先你需要创建一个git仓库用来存放生成的Podspec文件以及XCFramework产物
-
然后将该仓库添加为KMM项目的submodule
git submodule add https://github.com/url
最后直接跑该插件生成的部署任务即可
./gradlew deployKMMiOSCocoapods
SPM
上面提到,从2.0.0起,该插件支持了SPM部署。它会将XCFramework打成zip包并且生成Package.swift文件。此外还配置了zip包的发布任务。这一切可以通过一个简单的部署任务触发。当然,想要开启spm支持需要在build.gradle添加配置:
kmmDeploy {
spm("https://maven.pkg.github.com/KevinnZou/KMMDeployPlugin")
}
括号内的链接及为zip包所发布的远程仓库地址,如不填则采用Maven插件中配置的第一个仓库地址。然后,跑一个部署命令即可完成打包,发布,部署。
./gradlew deployKMMiOSSpm
Android
Android的部署任务比较简单,其实就是触发之前配置的发布aar任务。此外,它还会将aar复制一份到根目录下,用于本地调试
./gradlew deployKMMAndroid
所有产物
最后提供了一个部署双端产物的任务,这一个任务会完成双端的打包,发布以及部署任务,可以说是一键即可完成部署
./gradlew deployKMM
快速开始
前置配置
由于该项目使用 CocoaPods 和 Maven 进行 Kotlin Multiplatform 项目的 Artifacts 部署,因此想要使用该插件的项目必须应用 kotlin("native.cocoapods")、maven-publish 和 kotlin("multiplatform") 插件。
plugins {
kotlin("multiplatform")
kotlin("native.cocoapods")
`maven-publish`
}
注意:从1.3.0版本开始,CocoaPods不再是必须项,如果不配置该插件且还希望打XCFramework,可以参考如下配置:
kotlin {
val iosTargets = listOf(iosX64(), iosArm64(), iosSimulatorArm64())
// uncomment it if you don't want to use CococaPods plugin, then you can use this to produce XCFrameworks'
val xcf = XCFramework()
iosTargets.forEach {
it.binaries.framework {
baseName = "shared"
xcf.add(this)
}
}
}
请注意,您必须为产物指定 baseName。否则,你会得到报错。
启用插件
该插件已经发布到了Gradle官方仓库,因此,你可以直接在build.gradle中启用。当前的最新版本是2.2.0
plugins {
kotlin("multiplatform")
kotlin("native.cocoapods")
`maven-publish`
id("io.github.kevinnzou.kmmdeploy") version "2.2.0"
}
配置Maven仓库
如果要将 AAR 输出发布到远程 Maven 仓库,则需要配置远程仓库地址及权限信息。
publishing {
repositories {
maven {
url = uri("[input your repository url]")
credentials { }
}
}
}
Cocoapods配置
注意:上面提到的,从1.3.0版本开始,Cocoapods插件不再是必须项。不过如果你还是希望继续使用,那么需要配置一下必要的信息来保证生成的podspec文件是正确的:
kotlin {
// ...
cocoapods {
summary = "Some description for the Shared Module"
homepage = "https://github.com/KevinnZou/kmmdeploy-podspec"
source = "{:git=> 'https://github.com/KevinnZou/kmmdeploy-podspec.git' }"
version = project.version.toString()
ios.deploymentTarget = "14.1"
podfile = project.file("../iosApp/Podfile")
framework {
baseName = "shared"
}
}
}
配置自定义项
该插件提供了丰富的自定义项供开发者自由配置:
interface KmmDeployExtension {
/**
* Version for artifacts published to Maven
* Use gradle version by default
*/
val version: Property<String>
/**
* ArtifactId for artifacts published to Maven
* Use "kmm-android" by default
*/
val androidArtifactId: Property<String>
/**
* The name of the submodule that manages the Podspec file and XCFramework
* If you do not want to use submodule, please don't specify this property
*/
val podspecRepoName: Property<String>
/**
* The name of the output directory for artifacts of Android and iOS
* Use "KMMOutputs" by default
*/
val outputDirectory: Property<String>
/**
* ArtifactId for artifacts published to Maven
* Use "kmm-spm" by default
*/
val spmArtifactId: Property<String>
/**
* The Name of the Zip file of XCFrameworks
* Use "$name-xcframework-$version" by default
*/
val xcFrameworkZipName: Property<String>
/**
* Whether need SPM Support
* Use false by default
*/
val useSpm: Property<Boolean>
/**
* The url of the repository that store the zip file of XCFrameworks
* which will be used to fill the url filed of Package.swift files
* Use the url of the first repository in maven-publish extension by default
*/
val spmUrl: Property<String>
/**
* Need SPM Support
*/
fun Project.spm(url: String? = null) {
useSpm.set(true)
url?.apply { spmUrl.set(url) }
}
}
示例配置如下:
kmmDeploy {
androidArtifactId.set("kmm-android")
podspecRepoName.set("kmmdeploy-podspec")
spm("https://maven.pkg.github.com/KevinnZou/KMMDeployPlugin")
}
本地开发
前文有提到过,该插件可以为开发者本地开发调试KMM项目提供便利
Android
开发完成后,调用 copyAndroidAAR 任务即可构建AAR产物并将其复制到项目的根目录。
./gradlew copyAndroidAAR
假设您的 Android 项目与 KMM 项目位于同一目录,那么您可以像这样依赖生成的AAR:
dependencies {
implementation(files("../KMMProject/kmm-outputs/shared-debug.aar"))
}
iOS
对于 iOS,该插件提供了 cocoapods 和 SPM 两种方式。 您只需调用 copyXCFramework 任务即可构建 iOS 工件、压缩它并将其复制到根项目。 如果你应用 cocoapods 插件,它也会生成 podfile。 通过这些输出,您可以直接将生成的 XCFramework 移动到 Xcode 并在本地使用它。
./gradlew copyXCFramework
总结
总的来说,该插件提供了双端产物的打包,远程仓库的发布支持,以及iOS端的Cocoapods和SPM支持。可以做到只需触发一个deploy任务即可将最新产物发布到远端完成部署,大大节约了开发者的时间。